xref: /llvm-project/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp (revision 1c067a513c757b731434fd793351c52b49628489)
1cde4d5a6SJacques Pienaar //===- ModuleTranslation.cpp - MLIR to LLVM conversion --------------------===//
25d7231d8SStephan Herhut //
330857107SMehdi Amini // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
456222a06SMehdi Amini // See https://llvm.org/LICENSE.txt for license information.
556222a06SMehdi Amini // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65d7231d8SStephan Herhut //
756222a06SMehdi Amini //===----------------------------------------------------------------------===//
85d7231d8SStephan Herhut //
95d7231d8SStephan Herhut // This file implements the translation between an MLIR LLVM dialect module and
105d7231d8SStephan Herhut // the corresponding LLVMIR module. It only handles core LLVM IR operations.
115d7231d8SStephan Herhut //
125d7231d8SStephan Herhut //===----------------------------------------------------------------------===//
135d7231d8SStephan Herhut 
145d7231d8SStephan Herhut #include "mlir/Target/LLVMIR/ModuleTranslation.h"
155d7231d8SStephan Herhut 
1652120584SChristian Ulmann #include "AttrKindDetail.h"
17c33d6970SRiver Riddle #include "DebugTranslation.h"
18889a1178SChristian Ulmann #include "LoopAnnotationTranslation.h"
19b00e0c16SChristian Ulmann #include "mlir/Analysis/TopologicalSortUtils.h"
20ea998709SAlex Zinenko #include "mlir/Dialect/DLTI/DLTI.h"
21ba0fa925SRiver Riddle #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
22edfefd7fSTobias Gysi #include "mlir/Dialect/LLVMIR/LLVMInterfaces.h"
23422b84a7SBilly Zhu #include "mlir/Dialect/LLVMIR/Transforms/DIExpressionLegalization.h"
24ce8f10d6SAlex Zinenko #include "mlir/Dialect/LLVMIR/Transforms/LegalizeForExport.h"
2592a295ebSKiran Chandramohan #include "mlir/Dialect/OpenMP/OpenMPDialect.h"
26d3f9388fSJan Sjodin #include "mlir/Dialect/OpenMP/OpenMPInterfaces.h"
2778d00a16SMarkus Böck #include "mlir/IR/AttrTypeSubElements.h"
285d7231d8SStephan Herhut #include "mlir/IR/Attributes.h"
2965fcddffSRiver Riddle #include "mlir/IR/BuiltinOps.h"
3009f7a55fSRiver Riddle #include "mlir/IR/BuiltinTypes.h"
319261ab70SKunwar Grover #include "mlir/IR/DialectResourceBlobManager.h"
32d4568ed7SGeorge Mitenkov #include "mlir/IR/RegionGraphTraits.h"
335d7231d8SStephan Herhut #include "mlir/Support/LLVM.h"
34b77bac05SAlex Zinenko #include "mlir/Target/LLVMIR/LLVMTranslationInterface.h"
35929189a4SWilliam S. Moses #include "mlir/Target/LLVMIR/TypeToLLVM.h"
365d7231d8SStephan Herhut 
37d4568ed7SGeorge Mitenkov #include "llvm/ADT/PostOrderIterator.h"
385d7231d8SStephan Herhut #include "llvm/ADT/SetVector.h"
39748c2959SAlex Bradbury #include "llvm/ADT/StringExtras.h"
4052120584SChristian Ulmann #include "llvm/ADT/TypeSwitch.h"
4192a295ebSKiran Chandramohan #include "llvm/Frontend/OpenMP/OMPIRBuilder.h"
425d7231d8SStephan Herhut #include "llvm/IR/BasicBlock.h"
43d9067dcaSKiran Chandramohan #include "llvm/IR/CFG.h"
445d7231d8SStephan Herhut #include "llvm/IR/Constants.h"
455d7231d8SStephan Herhut #include "llvm/IR/DerivedTypes.h"
465d7231d8SStephan Herhut #include "llvm/IR/IRBuilder.h"
47047400edSNicolas Vasilache #include "llvm/IR/InlineAsm.h"
48875eb523SNavdeep Kumar #include "llvm/IR/IntrinsicsNVPTX.h"
495d7231d8SStephan Herhut #include "llvm/IR/LLVMContext.h"
5099d03f03SGeorge Mitenkov #include "llvm/IR/MDBuilder.h"
515d7231d8SStephan Herhut #include "llvm/IR/Module.h"
52ce8f10d6SAlex Zinenko #include "llvm/IR/Verifier.h"
53c11627c2SXiang Li #include "llvm/Support/Debug.h"
54c11627c2SXiang Li #include "llvm/Support/raw_ostream.h"
55d9067dcaSKiran Chandramohan #include "llvm/Transforms/Utils/BasicBlockUtils.h"
565d7231d8SStephan Herhut #include "llvm/Transforms/Utils/Cloning.h"
5757b9b296SUday Bondhugula #include "llvm/Transforms/Utils/ModuleUtils.h"
581dfb104eSSirui Mu #include <numeric>
59a1fe1f5fSKazu Hirata #include <optional>
605d7231d8SStephan Herhut 
61c11627c2SXiang Li #define DEBUG_TYPE "llvm-dialect-to-llvm-ir"
62c11627c2SXiang Li 
632666b973SRiver Riddle using namespace mlir;
642666b973SRiver Riddle using namespace mlir::LLVM;
65c33d6970SRiver Riddle using namespace mlir::LLVM::detail;
665d7231d8SStephan Herhut 
6748f8d95fSStephen Tozer extern llvm::cl::opt<bool> UseNewDbgInfoFormat;
6848f8d95fSStephen Tozer 
69eb67bd78SAlex Zinenko #include "mlir/Dialect/LLVMIR/LLVMConversionEnumsToLLVM.inc"
70eb67bd78SAlex Zinenko 
719519e3ecSOleksandr "Alex" Zinenko namespace {
729519e3ecSOleksandr "Alex" Zinenko /// A customized inserter for LLVM's IRBuilder that captures all LLVM IR
739519e3ecSOleksandr "Alex" Zinenko /// instructions that are created for future reference.
749519e3ecSOleksandr "Alex" Zinenko ///
759519e3ecSOleksandr "Alex" Zinenko /// This is intended to be used with the `CollectionScope` RAII object:
769519e3ecSOleksandr "Alex" Zinenko ///
779519e3ecSOleksandr "Alex" Zinenko ///     llvm::IRBuilder<..., InstructionCapturingInserter> builder;
789519e3ecSOleksandr "Alex" Zinenko ///     {
799519e3ecSOleksandr "Alex" Zinenko ///       InstructionCapturingInserter::CollectionScope scope(builder);
809519e3ecSOleksandr "Alex" Zinenko ///       // Call IRBuilder methods as usual.
819519e3ecSOleksandr "Alex" Zinenko ///
829519e3ecSOleksandr "Alex" Zinenko ///       // This will return a list of all instructions created by the builder,
839519e3ecSOleksandr "Alex" Zinenko ///       // in order of creation.
849519e3ecSOleksandr "Alex" Zinenko ///       builder.getInserter().getCapturedInstructions();
859519e3ecSOleksandr "Alex" Zinenko ///     }
869519e3ecSOleksandr "Alex" Zinenko ///     // This will return an empty list.
879519e3ecSOleksandr "Alex" Zinenko ///     builder.getInserter().getCapturedInstructions();
889519e3ecSOleksandr "Alex" Zinenko ///
899519e3ecSOleksandr "Alex" Zinenko /// The capturing functionality is _disabled_ by default for performance
909519e3ecSOleksandr "Alex" Zinenko /// consideration. It needs to be explicitly enabled, which is achieved by
919519e3ecSOleksandr "Alex" Zinenko /// creating a `CollectionScope`.
929519e3ecSOleksandr "Alex" Zinenko class InstructionCapturingInserter : public llvm::IRBuilderCallbackInserter {
939519e3ecSOleksandr "Alex" Zinenko public:
949519e3ecSOleksandr "Alex" Zinenko   /// Constructs the inserter.
959519e3ecSOleksandr "Alex" Zinenko   InstructionCapturingInserter()
969519e3ecSOleksandr "Alex" Zinenko       : llvm::IRBuilderCallbackInserter([this](llvm::Instruction *instruction) {
979519e3ecSOleksandr "Alex" Zinenko           if (LLVM_LIKELY(enabled))
989519e3ecSOleksandr "Alex" Zinenko             capturedInstructions.push_back(instruction);
999519e3ecSOleksandr "Alex" Zinenko         }) {}
1009519e3ecSOleksandr "Alex" Zinenko 
1019519e3ecSOleksandr "Alex" Zinenko   /// Returns the list of LLVM IR instructions captured since the last cleanup.
1029519e3ecSOleksandr "Alex" Zinenko   ArrayRef<llvm::Instruction *> getCapturedInstructions() const {
1039519e3ecSOleksandr "Alex" Zinenko     return capturedInstructions;
1049519e3ecSOleksandr "Alex" Zinenko   }
1059519e3ecSOleksandr "Alex" Zinenko 
1069519e3ecSOleksandr "Alex" Zinenko   /// Clears the list of captured LLVM IR instructions.
1079519e3ecSOleksandr "Alex" Zinenko   void clearCapturedInstructions() { capturedInstructions.clear(); }
1089519e3ecSOleksandr "Alex" Zinenko 
1099519e3ecSOleksandr "Alex" Zinenko   /// RAII object enabling the capture of created LLVM IR instructions.
1109519e3ecSOleksandr "Alex" Zinenko   class CollectionScope {
1119519e3ecSOleksandr "Alex" Zinenko   public:
1129519e3ecSOleksandr "Alex" Zinenko     /// Creates the scope for the given inserter.
1139519e3ecSOleksandr "Alex" Zinenko     CollectionScope(llvm::IRBuilderBase &irBuilder, bool isBuilderCapturing);
1149519e3ecSOleksandr "Alex" Zinenko 
1159519e3ecSOleksandr "Alex" Zinenko     /// Ends the scope.
1169519e3ecSOleksandr "Alex" Zinenko     ~CollectionScope();
1179519e3ecSOleksandr "Alex" Zinenko 
1189519e3ecSOleksandr "Alex" Zinenko     ArrayRef<llvm::Instruction *> getCapturedInstructions() {
1199519e3ecSOleksandr "Alex" Zinenko       if (!inserter)
1209519e3ecSOleksandr "Alex" Zinenko         return {};
1219519e3ecSOleksandr "Alex" Zinenko       return inserter->getCapturedInstructions();
1229519e3ecSOleksandr "Alex" Zinenko     }
1239519e3ecSOleksandr "Alex" Zinenko 
1249519e3ecSOleksandr "Alex" Zinenko   private:
1259519e3ecSOleksandr "Alex" Zinenko     /// Back reference to the inserter.
1269519e3ecSOleksandr "Alex" Zinenko     InstructionCapturingInserter *inserter = nullptr;
1279519e3ecSOleksandr "Alex" Zinenko 
1289519e3ecSOleksandr "Alex" Zinenko     /// List of instructions in the inserter prior to this scope.
1299519e3ecSOleksandr "Alex" Zinenko     SmallVector<llvm::Instruction *> previouslyCollectedInstructions;
1309519e3ecSOleksandr "Alex" Zinenko 
1319519e3ecSOleksandr "Alex" Zinenko     /// Whether the inserter was enabled prior to this scope.
1329519e3ecSOleksandr "Alex" Zinenko     bool wasEnabled;
1339519e3ecSOleksandr "Alex" Zinenko   };
1349519e3ecSOleksandr "Alex" Zinenko 
1359519e3ecSOleksandr "Alex" Zinenko   /// Enable or disable the capturing mechanism.
1369519e3ecSOleksandr "Alex" Zinenko   void setEnabled(bool enabled = true) { this->enabled = enabled; }
1379519e3ecSOleksandr "Alex" Zinenko 
1389519e3ecSOleksandr "Alex" Zinenko private:
1399519e3ecSOleksandr "Alex" Zinenko   /// List of captured instructions.
1409519e3ecSOleksandr "Alex" Zinenko   SmallVector<llvm::Instruction *> capturedInstructions;
1419519e3ecSOleksandr "Alex" Zinenko 
1429519e3ecSOleksandr "Alex" Zinenko   /// Whether the collection is enabled.
1439519e3ecSOleksandr "Alex" Zinenko   bool enabled = false;
1449519e3ecSOleksandr "Alex" Zinenko };
1459519e3ecSOleksandr "Alex" Zinenko 
1469519e3ecSOleksandr "Alex" Zinenko using CapturingIRBuilder =
1479519e3ecSOleksandr "Alex" Zinenko     llvm::IRBuilder<llvm::ConstantFolder, InstructionCapturingInserter>;
1489519e3ecSOleksandr "Alex" Zinenko } // namespace
1499519e3ecSOleksandr "Alex" Zinenko 
1509519e3ecSOleksandr "Alex" Zinenko InstructionCapturingInserter::CollectionScope::CollectionScope(
1519519e3ecSOleksandr "Alex" Zinenko     llvm::IRBuilderBase &irBuilder, bool isBuilderCapturing) {
1529519e3ecSOleksandr "Alex" Zinenko 
1539519e3ecSOleksandr "Alex" Zinenko   if (!isBuilderCapturing)
1549519e3ecSOleksandr "Alex" Zinenko     return;
1559519e3ecSOleksandr "Alex" Zinenko 
1569519e3ecSOleksandr "Alex" Zinenko   auto &capturingIRBuilder = static_cast<CapturingIRBuilder &>(irBuilder);
1579519e3ecSOleksandr "Alex" Zinenko   inserter = &capturingIRBuilder.getInserter();
1589519e3ecSOleksandr "Alex" Zinenko   wasEnabled = inserter->enabled;
1599519e3ecSOleksandr "Alex" Zinenko   if (wasEnabled)
1609519e3ecSOleksandr "Alex" Zinenko     previouslyCollectedInstructions.swap(inserter->capturedInstructions);
1619519e3ecSOleksandr "Alex" Zinenko   inserter->setEnabled(true);
1629519e3ecSOleksandr "Alex" Zinenko }
1639519e3ecSOleksandr "Alex" Zinenko 
1649519e3ecSOleksandr "Alex" Zinenko InstructionCapturingInserter::CollectionScope::~CollectionScope() {
1659519e3ecSOleksandr "Alex" Zinenko   if (!inserter)
1669519e3ecSOleksandr "Alex" Zinenko     return;
1679519e3ecSOleksandr "Alex" Zinenko 
1689519e3ecSOleksandr "Alex" Zinenko   previouslyCollectedInstructions.swap(inserter->capturedInstructions);
1699519e3ecSOleksandr "Alex" Zinenko   // If collection was enabled (likely in another, surrounding scope), keep
1709519e3ecSOleksandr "Alex" Zinenko   // the instructions collected in this scope.
1719519e3ecSOleksandr "Alex" Zinenko   if (wasEnabled) {
1729519e3ecSOleksandr "Alex" Zinenko     llvm::append_range(inserter->capturedInstructions,
1739519e3ecSOleksandr "Alex" Zinenko                        previouslyCollectedInstructions);
1749519e3ecSOleksandr "Alex" Zinenko   }
1759519e3ecSOleksandr "Alex" Zinenko   inserter->setEnabled(wasEnabled);
1769519e3ecSOleksandr "Alex" Zinenko }
1779519e3ecSOleksandr "Alex" Zinenko 
178ea998709SAlex Zinenko /// Translates the given data layout spec attribute to the LLVM IR data layout.
179aa00e3e6Srkayaith /// Only integer, float, pointer and endianness entries are currently supported.
180aa00e3e6Srkayaith static FailureOr<llvm::DataLayout>
181ea998709SAlex Zinenko translateDataLayout(DataLayoutSpecInterface attribute,
182ea998709SAlex Zinenko                     const DataLayout &dataLayout,
1830a81ace0SKazu Hirata                     std::optional<Location> loc = std::nullopt) {
184ea998709SAlex Zinenko   if (!loc)
185ea998709SAlex Zinenko     loc = UnknownLoc::get(attribute.getContext());
186ea998709SAlex Zinenko 
187ea998709SAlex Zinenko   // Translate the endianness attribute.
188ea998709SAlex Zinenko   std::string llvmDataLayout;
189ea998709SAlex Zinenko   llvm::raw_string_ostream layoutStream(llvmDataLayout);
190ea998709SAlex Zinenko   for (DataLayoutEntryInterface entry : attribute.getEntries()) {
19168f58812STres Popp     auto key = llvm::dyn_cast_if_present<StringAttr>(entry.getKey());
192ea998709SAlex Zinenko     if (!key)
193ea998709SAlex Zinenko       continue;
194ea998709SAlex Zinenko     if (key.getValue() == DLTIDialect::kDataLayoutEndiannessKey) {
1955550c821STres Popp       auto value = cast<StringAttr>(entry.getValue());
196ea998709SAlex Zinenko       bool isLittleEndian =
197ea998709SAlex Zinenko           value.getValue() == DLTIDialect::kDataLayoutEndiannessLittle;
1989d69bca1STobias Gysi       layoutStream << "-" << (isLittleEndian ? "e" : "E");
199ea998709SAlex Zinenko       continue;
200ea998709SAlex Zinenko     }
201c1ed45a2Sagozillon     if (key.getValue() == DLTIDialect::kDataLayoutProgramMemorySpaceKey) {
202c1ed45a2Sagozillon       auto value = cast<IntegerAttr>(entry.getValue());
203c1ed45a2Sagozillon       uint64_t space = value.getValue().getZExtValue();
204c1ed45a2Sagozillon       // Skip the default address space.
205c1ed45a2Sagozillon       if (space == 0)
206c1ed45a2Sagozillon         continue;
207c1ed45a2Sagozillon       layoutStream << "-P" << space;
208c1ed45a2Sagozillon       continue;
209c1ed45a2Sagozillon     }
210c1ed45a2Sagozillon     if (key.getValue() == DLTIDialect::kDataLayoutGlobalMemorySpaceKey) {
211c1ed45a2Sagozillon       auto value = cast<IntegerAttr>(entry.getValue());
212c1ed45a2Sagozillon       uint64_t space = value.getValue().getZExtValue();
213c1ed45a2Sagozillon       // Skip the default address space.
214c1ed45a2Sagozillon       if (space == 0)
215c1ed45a2Sagozillon         continue;
216c1ed45a2Sagozillon       layoutStream << "-G" << space;
217c1ed45a2Sagozillon       continue;
218c1ed45a2Sagozillon     }
219382eb7c2SJan Sjodin     if (key.getValue() == DLTIDialect::kDataLayoutAllocaMemorySpaceKey) {
2205550c821STres Popp       auto value = cast<IntegerAttr>(entry.getValue());
2219d69bca1STobias Gysi       uint64_t space = value.getValue().getZExtValue();
2229d69bca1STobias Gysi       // Skip the default address space.
2239d69bca1STobias Gysi       if (space == 0)
2249d69bca1STobias Gysi         continue;
2259d69bca1STobias Gysi       layoutStream << "-A" << space;
2269d69bca1STobias Gysi       continue;
227382eb7c2SJan Sjodin     }
2289d69bca1STobias Gysi     if (key.getValue() == DLTIDialect::kDataLayoutStackAlignmentKey) {
2295550c821STres Popp       auto value = cast<IntegerAttr>(entry.getValue());
2309d69bca1STobias Gysi       uint64_t alignment = value.getValue().getZExtValue();
2319d69bca1STobias Gysi       // Skip the default stack alignment.
2329d69bca1STobias Gysi       if (alignment == 0)
2339d69bca1STobias Gysi         continue;
2349d69bca1STobias Gysi       layoutStream << "-S" << alignment;
235382eb7c2SJan Sjodin       continue;
236382eb7c2SJan Sjodin     }
237ea998709SAlex Zinenko     emitError(*loc) << "unsupported data layout key " << key;
238ea998709SAlex Zinenko     return failure();
239ea998709SAlex Zinenko   }
240ea998709SAlex Zinenko 
241ea998709SAlex Zinenko   // Go through the list of entries to check which types are explicitly
242aa00e3e6Srkayaith   // specified in entries. Where possible, data layout queries are used instead
243aa00e3e6Srkayaith   // of directly inspecting the entries.
244ea998709SAlex Zinenko   for (DataLayoutEntryInterface entry : attribute.getEntries()) {
24568f58812STres Popp     auto type = llvm::dyn_cast_if_present<Type>(entry.getKey());
246ea998709SAlex Zinenko     if (!type)
247ea998709SAlex Zinenko       continue;
248eb27da7dSAlex Zinenko     // Data layout for the index type is irrelevant at this point.
2495550c821STres Popp     if (isa<IndexType>(type))
250eb27da7dSAlex Zinenko       continue;
251aa00e3e6Srkayaith     layoutStream << "-";
252aa00e3e6Srkayaith     LogicalResult result =
253aa00e3e6Srkayaith         llvm::TypeSwitch<Type, LogicalResult>(type)
254aa00e3e6Srkayaith             .Case<IntegerType, Float16Type, Float32Type, Float64Type,
255aa00e3e6Srkayaith                   Float80Type, Float128Type>([&](Type type) -> LogicalResult {
2565550c821STres Popp               if (auto intType = dyn_cast<IntegerType>(type)) {
257aa00e3e6Srkayaith                 if (intType.getSignedness() != IntegerType::Signless)
258aa00e3e6Srkayaith                   return emitError(*loc)
259ea998709SAlex Zinenko                          << "unsupported data layout for non-signless integer "
260aa00e3e6Srkayaith                          << intType;
261aa00e3e6Srkayaith                 layoutStream << "i";
262aa00e3e6Srkayaith               } else {
263aa00e3e6Srkayaith                 layoutStream << "f";
264aa00e3e6Srkayaith               }
2658134a8fcSOleksandr "Alex" Zinenko               uint64_t size = dataLayout.getTypeSizeInBits(type);
2668134a8fcSOleksandr "Alex" Zinenko               uint64_t abi = dataLayout.getTypeABIAlignment(type) * 8u;
2678134a8fcSOleksandr "Alex" Zinenko               uint64_t preferred =
268aa00e3e6Srkayaith                   dataLayout.getTypePreferredAlignment(type) * 8u;
269aa00e3e6Srkayaith               layoutStream << size << ":" << abi;
270ea998709SAlex Zinenko               if (abi != preferred)
271ea998709SAlex Zinenko                 layoutStream << ":" << preferred;
272aa00e3e6Srkayaith               return success();
273aa00e3e6Srkayaith             })
274adda5973STobias Gysi             .Case([&](LLVMPointerType type) {
275adda5973STobias Gysi               layoutStream << "p" << type.getAddressSpace() << ":";
2768134a8fcSOleksandr "Alex" Zinenko               uint64_t size = dataLayout.getTypeSizeInBits(type);
2778134a8fcSOleksandr "Alex" Zinenko               uint64_t abi = dataLayout.getTypeABIAlignment(type) * 8u;
2788134a8fcSOleksandr "Alex" Zinenko               uint64_t preferred =
279aa00e3e6Srkayaith                   dataLayout.getTypePreferredAlignment(type) * 8u;
280adda5973STobias Gysi               uint64_t index = *dataLayout.getTypeIndexBitwidth(type);
281adda5973STobias Gysi               layoutStream << size << ":" << abi << ":" << preferred << ":"
282adda5973STobias Gysi                            << index;
283aa00e3e6Srkayaith               return success();
284aa00e3e6Srkayaith             })
285aa00e3e6Srkayaith             .Default([loc](Type type) {
286aa00e3e6Srkayaith               return emitError(*loc)
287aa00e3e6Srkayaith                      << "unsupported type in data layout: " << type;
288aa00e3e6Srkayaith             });
289aa00e3e6Srkayaith     if (failed(result))
290aa00e3e6Srkayaith       return failure();
291ea998709SAlex Zinenko   }
292ea998709SAlex Zinenko   StringRef layoutSpec(llvmDataLayout);
29388d319a2SKazu Hirata   if (layoutSpec.starts_with("-"))
294ea998709SAlex Zinenko     layoutSpec = layoutSpec.drop_front();
295ea998709SAlex Zinenko 
296ea998709SAlex Zinenko   return llvm::DataLayout(layoutSpec);
297ea998709SAlex Zinenko }
298ea998709SAlex Zinenko 
299a922e231SAlex Zinenko /// Builds a constant of a sequential LLVM type `type`, potentially containing
300a922e231SAlex Zinenko /// other sequential types recursively, from the individual constant values
301a922e231SAlex Zinenko /// provided in `constants`. `shape` contains the number of elements in nested
302a922e231SAlex Zinenko /// sequential types. Reports errors at `loc` and returns nullptr on error.
303a4a42160SAlex Zinenko static llvm::Constant *
304a4a42160SAlex Zinenko buildSequentialConstant(ArrayRef<llvm::Constant *> &constants,
305a4a42160SAlex Zinenko                         ArrayRef<int64_t> shape, llvm::Type *type,
306a4a42160SAlex Zinenko                         Location loc) {
307a4a42160SAlex Zinenko   if (shape.empty()) {
308a4a42160SAlex Zinenko     llvm::Constant *result = constants.front();
309a4a42160SAlex Zinenko     constants = constants.drop_front();
310a4a42160SAlex Zinenko     return result;
311a4a42160SAlex Zinenko   }
312a4a42160SAlex Zinenko 
31368b03aeeSEli Friedman   llvm::Type *elementType;
31468b03aeeSEli Friedman   if (auto *arrayTy = dyn_cast<llvm::ArrayType>(type)) {
31568b03aeeSEli Friedman     elementType = arrayTy->getElementType();
31668b03aeeSEli Friedman   } else if (auto *vectorTy = dyn_cast<llvm::VectorType>(type)) {
31768b03aeeSEli Friedman     elementType = vectorTy->getElementType();
31868b03aeeSEli Friedman   } else {
319a4a42160SAlex Zinenko     emitError(loc) << "expected sequential LLVM types wrapping a scalar";
320a4a42160SAlex Zinenko     return nullptr;
321a4a42160SAlex Zinenko   }
322a4a42160SAlex Zinenko 
323a4a42160SAlex Zinenko   SmallVector<llvm::Constant *, 8> nested;
324a4a42160SAlex Zinenko   nested.reserve(shape.front());
325a4a42160SAlex Zinenko   for (int64_t i = 0; i < shape.front(); ++i) {
326a4a42160SAlex Zinenko     nested.push_back(buildSequentialConstant(constants, shape.drop_front(),
327a4a42160SAlex Zinenko                                              elementType, loc));
328a4a42160SAlex Zinenko     if (!nested.back())
329a4a42160SAlex Zinenko       return nullptr;
330a4a42160SAlex Zinenko   }
331a4a42160SAlex Zinenko 
332a4a42160SAlex Zinenko   if (shape.size() == 1 && type->isVectorTy())
333a4a42160SAlex Zinenko     return llvm::ConstantVector::get(nested);
334a4a42160SAlex Zinenko   return llvm::ConstantArray::get(
335a4a42160SAlex Zinenko       llvm::ArrayType::get(elementType, shape.front()), nested);
336a4a42160SAlex Zinenko }
337a4a42160SAlex Zinenko 
338fc817b09SKazuaki Ishizaki /// Returns the first non-sequential type nested in sequential types.
339a4a42160SAlex Zinenko static llvm::Type *getInnermostElementType(llvm::Type *type) {
34068b03aeeSEli Friedman   do {
34168b03aeeSEli Friedman     if (auto *arrayTy = dyn_cast<llvm::ArrayType>(type)) {
34268b03aeeSEli Friedman       type = arrayTy->getElementType();
34368b03aeeSEli Friedman     } else if (auto *vectorTy = dyn_cast<llvm::VectorType>(type)) {
34468b03aeeSEli Friedman       type = vectorTy->getElementType();
34568b03aeeSEli Friedman     } else {
346a4a42160SAlex Zinenko       return type;
347a4a42160SAlex Zinenko     }
3480881a4f1SAlex Zinenko   } while (true);
34968b03aeeSEli Friedman }
350a4a42160SAlex Zinenko 
351f9be7a7aSAlex Zinenko /// Convert a dense elements attribute to an LLVM IR constant using its raw data
352f9be7a7aSAlex Zinenko /// storage if possible. This supports elements attributes of tensor or vector
353f9be7a7aSAlex Zinenko /// type and avoids constructing separate objects for individual values of the
354f9be7a7aSAlex Zinenko /// innermost dimension. Constants for other dimensions are still constructed
355f9be7a7aSAlex Zinenko /// recursively. Returns null if constructing from raw data is not supported for
356f9be7a7aSAlex Zinenko /// this type, e.g., element type is not a power-of-two-sized primitive. Reports
357f9be7a7aSAlex Zinenko /// other errors at `loc`.
358f9be7a7aSAlex Zinenko static llvm::Constant *
359f9be7a7aSAlex Zinenko convertDenseElementsAttr(Location loc, DenseElementsAttr denseElementsAttr,
360f9be7a7aSAlex Zinenko                          llvm::Type *llvmType,
361f9be7a7aSAlex Zinenko                          const ModuleTranslation &moduleTranslation) {
362f9be7a7aSAlex Zinenko   if (!denseElementsAttr)
363f9be7a7aSAlex Zinenko     return nullptr;
364f9be7a7aSAlex Zinenko 
365f9be7a7aSAlex Zinenko   llvm::Type *innermostLLVMType = getInnermostElementType(llvmType);
366f9be7a7aSAlex Zinenko   if (!llvm::ConstantDataSequential::isElementTypeCompatible(innermostLLVMType))
367f9be7a7aSAlex Zinenko     return nullptr;
368f9be7a7aSAlex Zinenko 
369898e8096SBenjamin Kramer   ShapedType type = denseElementsAttr.getType();
370898e8096SBenjamin Kramer   if (type.getNumElements() == 0)
371898e8096SBenjamin Kramer     return nullptr;
372898e8096SBenjamin Kramer 
3738c7cfa35SAlex Zinenko   // Check that the raw data size matches what is expected for the scalar size.
3748c7cfa35SAlex Zinenko   // TODO: in theory, we could repack the data here to keep constructing from
3758c7cfa35SAlex Zinenko   // raw data.
3768c7cfa35SAlex Zinenko   // TODO: we may also need to consider endianness when cross-compiling to an
3778c7cfa35SAlex Zinenko   // architecture where it is different.
3788134a8fcSOleksandr "Alex" Zinenko   int64_t elementByteSize = denseElementsAttr.getRawData().size() /
3798c7cfa35SAlex Zinenko                             denseElementsAttr.getNumElements();
3808c7cfa35SAlex Zinenko   if (8 * elementByteSize != innermostLLVMType->getScalarSizeInBits())
3818c7cfa35SAlex Zinenko     return nullptr;
3828c7cfa35SAlex Zinenko 
383f9be7a7aSAlex Zinenko   // Compute the shape of all dimensions but the innermost. Note that the
384f9be7a7aSAlex Zinenko   // innermost dimension may be that of the vector element type.
3855550c821STres Popp   bool hasVectorElementType = isa<VectorType>(type.getElementType());
3868134a8fcSOleksandr "Alex" Zinenko   int64_t numAggregates =
387f9be7a7aSAlex Zinenko       denseElementsAttr.getNumElements() /
388f9be7a7aSAlex Zinenko       (hasVectorElementType ? 1
389f9be7a7aSAlex Zinenko                             : denseElementsAttr.getType().getShape().back());
390f9be7a7aSAlex Zinenko   ArrayRef<int64_t> outerShape = type.getShape();
391f9be7a7aSAlex Zinenko   if (!hasVectorElementType)
392f9be7a7aSAlex Zinenko     outerShape = outerShape.drop_back();
393f9be7a7aSAlex Zinenko 
394f9be7a7aSAlex Zinenko   // Handle the case of vector splat, LLVM has special support for it.
395f9be7a7aSAlex Zinenko   if (denseElementsAttr.isSplat() &&
3965550c821STres Popp       (isa<VectorType>(type) || hasVectorElementType)) {
397f9be7a7aSAlex Zinenko     llvm::Constant *splatValue = LLVM::detail::getLLVMConstant(
398937e40a8SRiver Riddle         innermostLLVMType, denseElementsAttr.getSplatValue<Attribute>(), loc,
39927dad996SBenjamin Kramer         moduleTranslation);
400f9be7a7aSAlex Zinenko     llvm::Constant *splatVector =
401f9be7a7aSAlex Zinenko         llvm::ConstantDataVector::getSplat(0, splatValue);
402f9be7a7aSAlex Zinenko     SmallVector<llvm::Constant *> constants(numAggregates, splatVector);
403f9be7a7aSAlex Zinenko     ArrayRef<llvm::Constant *> constantsRef = constants;
404f9be7a7aSAlex Zinenko     return buildSequentialConstant(constantsRef, outerShape, llvmType, loc);
405f9be7a7aSAlex Zinenko   }
406f9be7a7aSAlex Zinenko   if (denseElementsAttr.isSplat())
407f9be7a7aSAlex Zinenko     return nullptr;
408f9be7a7aSAlex Zinenko 
409f9be7a7aSAlex Zinenko   // In case of non-splat, create a constructor for the innermost constant from
410f9be7a7aSAlex Zinenko   // a piece of raw data.
411f9be7a7aSAlex Zinenko   std::function<llvm::Constant *(StringRef)> buildCstData;
4125550c821STres Popp   if (isa<TensorType>(type)) {
4135550c821STres Popp     auto vectorElementType = dyn_cast<VectorType>(type.getElementType());
414f9be7a7aSAlex Zinenko     if (vectorElementType && vectorElementType.getRank() == 1) {
415f9be7a7aSAlex Zinenko       buildCstData = [&](StringRef data) {
416f9be7a7aSAlex Zinenko         return llvm::ConstantDataVector::getRaw(
417f9be7a7aSAlex Zinenko             data, vectorElementType.getShape().back(), innermostLLVMType);
418f9be7a7aSAlex Zinenko       };
419f9be7a7aSAlex Zinenko     } else if (!vectorElementType) {
420f9be7a7aSAlex Zinenko       buildCstData = [&](StringRef data) {
421f9be7a7aSAlex Zinenko         return llvm::ConstantDataArray::getRaw(data, type.getShape().back(),
422f9be7a7aSAlex Zinenko                                                innermostLLVMType);
423f9be7a7aSAlex Zinenko       };
424f9be7a7aSAlex Zinenko     }
4255550c821STres Popp   } else if (isa<VectorType>(type)) {
426f9be7a7aSAlex Zinenko     buildCstData = [&](StringRef data) {
427f9be7a7aSAlex Zinenko       return llvm::ConstantDataVector::getRaw(data, type.getShape().back(),
428f9be7a7aSAlex Zinenko                                               innermostLLVMType);
429f9be7a7aSAlex Zinenko     };
430f9be7a7aSAlex Zinenko   }
431f9be7a7aSAlex Zinenko   if (!buildCstData)
432f9be7a7aSAlex Zinenko     return nullptr;
433f9be7a7aSAlex Zinenko 
434f9be7a7aSAlex Zinenko   // Create innermost constants and defer to the default constant creation
435f9be7a7aSAlex Zinenko   // mechanism for other dimensions.
436f9be7a7aSAlex Zinenko   SmallVector<llvm::Constant *> constants;
4378134a8fcSOleksandr "Alex" Zinenko   int64_t aggregateSize = denseElementsAttr.getType().getShape().back() *
438f9be7a7aSAlex Zinenko                           (innermostLLVMType->getScalarSizeInBits() / 8);
439f9be7a7aSAlex Zinenko   constants.reserve(numAggregates);
440f9be7a7aSAlex Zinenko   for (unsigned i = 0; i < numAggregates; ++i) {
441f9be7a7aSAlex Zinenko     StringRef data(denseElementsAttr.getRawData().data() + i * aggregateSize,
442f9be7a7aSAlex Zinenko                    aggregateSize);
443f9be7a7aSAlex Zinenko     constants.push_back(buildCstData(data));
444f9be7a7aSAlex Zinenko   }
445f9be7a7aSAlex Zinenko 
446f9be7a7aSAlex Zinenko   ArrayRef<llvm::Constant *> constantsRef = constants;
447f9be7a7aSAlex Zinenko   return buildSequentialConstant(constantsRef, outerShape, llvmType, loc);
448f9be7a7aSAlex Zinenko }
449f9be7a7aSAlex Zinenko 
4509261ab70SKunwar Grover /// Convert a dense resource elements attribute to an LLVM IR constant using its
4519261ab70SKunwar Grover /// raw data storage if possible. This supports elements attributes of tensor or
4529261ab70SKunwar Grover /// vector type and avoids constructing separate objects for individual values
4539261ab70SKunwar Grover /// of the innermost dimension. Constants for other dimensions are still
4549261ab70SKunwar Grover /// constructed recursively. Returns nullptr on failure and emits errors at
4559261ab70SKunwar Grover /// `loc`.
4569261ab70SKunwar Grover static llvm::Constant *convertDenseResourceElementsAttr(
4579261ab70SKunwar Grover     Location loc, DenseResourceElementsAttr denseResourceAttr,
4589261ab70SKunwar Grover     llvm::Type *llvmType, const ModuleTranslation &moduleTranslation) {
4599261ab70SKunwar Grover   assert(denseResourceAttr && "expected non-null attribute");
4609261ab70SKunwar Grover 
4619261ab70SKunwar Grover   llvm::Type *innermostLLVMType = getInnermostElementType(llvmType);
4629261ab70SKunwar Grover   if (!llvm::ConstantDataSequential::isElementTypeCompatible(
4639261ab70SKunwar Grover           innermostLLVMType)) {
4649261ab70SKunwar Grover     emitError(loc, "no known conversion for innermost element type");
4659261ab70SKunwar Grover     return nullptr;
4669261ab70SKunwar Grover   }
4679261ab70SKunwar Grover 
4689261ab70SKunwar Grover   ShapedType type = denseResourceAttr.getType();
4699261ab70SKunwar Grover   assert(type.getNumElements() > 0 && "Expected non-empty elements attribute");
4709261ab70SKunwar Grover 
4719261ab70SKunwar Grover   AsmResourceBlob *blob = denseResourceAttr.getRawHandle().getBlob();
4729261ab70SKunwar Grover   if (!blob) {
4739261ab70SKunwar Grover     emitError(loc, "resource does not exist");
4749261ab70SKunwar Grover     return nullptr;
4759261ab70SKunwar Grover   }
4769261ab70SKunwar Grover 
4779261ab70SKunwar Grover   ArrayRef<char> rawData = blob->getData();
4789261ab70SKunwar Grover 
4799261ab70SKunwar Grover   // Check that the raw data size matches what is expected for the scalar size.
4809261ab70SKunwar Grover   // TODO: in theory, we could repack the data here to keep constructing from
4819261ab70SKunwar Grover   // raw data.
4829261ab70SKunwar Grover   // TODO: we may also need to consider endianness when cross-compiling to an
4839261ab70SKunwar Grover   // architecture where it is different.
4849261ab70SKunwar Grover   int64_t numElements = denseResourceAttr.getType().getNumElements();
4859261ab70SKunwar Grover   int64_t elementByteSize = rawData.size() / numElements;
4869261ab70SKunwar Grover   if (8 * elementByteSize != innermostLLVMType->getScalarSizeInBits()) {
4879261ab70SKunwar Grover     emitError(loc, "raw data size does not match element type size");
4889261ab70SKunwar Grover     return nullptr;
4899261ab70SKunwar Grover   }
4909261ab70SKunwar Grover 
4919261ab70SKunwar Grover   // Compute the shape of all dimensions but the innermost. Note that the
4929261ab70SKunwar Grover   // innermost dimension may be that of the vector element type.
4939261ab70SKunwar Grover   bool hasVectorElementType = isa<VectorType>(type.getElementType());
4949261ab70SKunwar Grover   int64_t numAggregates =
4959261ab70SKunwar Grover       numElements / (hasVectorElementType
4969261ab70SKunwar Grover                          ? 1
4979261ab70SKunwar Grover                          : denseResourceAttr.getType().getShape().back());
4989261ab70SKunwar Grover   ArrayRef<int64_t> outerShape = type.getShape();
4999261ab70SKunwar Grover   if (!hasVectorElementType)
5009261ab70SKunwar Grover     outerShape = outerShape.drop_back();
5019261ab70SKunwar Grover 
5029261ab70SKunwar Grover   // Create a constructor for the innermost constant from a piece of raw data.
5039261ab70SKunwar Grover   std::function<llvm::Constant *(StringRef)> buildCstData;
5049261ab70SKunwar Grover   if (isa<TensorType>(type)) {
5059261ab70SKunwar Grover     auto vectorElementType = dyn_cast<VectorType>(type.getElementType());
5069261ab70SKunwar Grover     if (vectorElementType && vectorElementType.getRank() == 1) {
5079261ab70SKunwar Grover       buildCstData = [&](StringRef data) {
5089261ab70SKunwar Grover         return llvm::ConstantDataVector::getRaw(
5099261ab70SKunwar Grover             data, vectorElementType.getShape().back(), innermostLLVMType);
5109261ab70SKunwar Grover       };
5119261ab70SKunwar Grover     } else if (!vectorElementType) {
5129261ab70SKunwar Grover       buildCstData = [&](StringRef data) {
5139261ab70SKunwar Grover         return llvm::ConstantDataArray::getRaw(data, type.getShape().back(),
5149261ab70SKunwar Grover                                                innermostLLVMType);
5159261ab70SKunwar Grover       };
5169261ab70SKunwar Grover     }
5179261ab70SKunwar Grover   } else if (isa<VectorType>(type)) {
5189261ab70SKunwar Grover     buildCstData = [&](StringRef data) {
5199261ab70SKunwar Grover       return llvm::ConstantDataVector::getRaw(data, type.getShape().back(),
5209261ab70SKunwar Grover                                               innermostLLVMType);
5219261ab70SKunwar Grover     };
5229261ab70SKunwar Grover   }
5239261ab70SKunwar Grover   if (!buildCstData) {
5249261ab70SKunwar Grover     emitError(loc, "unsupported dense_resource type");
5259261ab70SKunwar Grover     return nullptr;
5269261ab70SKunwar Grover   }
5279261ab70SKunwar Grover 
5289261ab70SKunwar Grover   // Create innermost constants and defer to the default constant creation
5299261ab70SKunwar Grover   // mechanism for other dimensions.
5309261ab70SKunwar Grover   SmallVector<llvm::Constant *> constants;
5319261ab70SKunwar Grover   int64_t aggregateSize = denseResourceAttr.getType().getShape().back() *
5329261ab70SKunwar Grover                           (innermostLLVMType->getScalarSizeInBits() / 8);
5339261ab70SKunwar Grover   constants.reserve(numAggregates);
5349261ab70SKunwar Grover   for (unsigned i = 0; i < numAggregates; ++i) {
5359261ab70SKunwar Grover     StringRef data(rawData.data() + i * aggregateSize, aggregateSize);
5369261ab70SKunwar Grover     constants.push_back(buildCstData(data));
5379261ab70SKunwar Grover   }
5389261ab70SKunwar Grover 
5399261ab70SKunwar Grover   ArrayRef<llvm::Constant *> constantsRef = constants;
5409261ab70SKunwar Grover   return buildSequentialConstant(constantsRef, outerShape, llvmType, loc);
5419261ab70SKunwar Grover }
5429261ab70SKunwar Grover 
5432666b973SRiver Riddle /// Create an LLVM IR constant of `llvmType` from the MLIR attribute `attr`.
5442666b973SRiver Riddle /// This currently supports integer, floating point, splat and dense element
5455ef21506SAdrian Kuegel /// attributes and combinations thereof. Also, an array attribute with two
5465ef21506SAdrian Kuegel /// elements is supported to represent a complex constant.  In case of error,
5475ef21506SAdrian Kuegel /// report it to `loc` and return nullptr.
548176379e0SAlex Zinenko llvm::Constant *mlir::LLVM::detail::getLLVMConstant(
549176379e0SAlex Zinenko     llvm::Type *llvmType, Attribute attr, Location loc,
55027dad996SBenjamin Kramer     const ModuleTranslation &moduleTranslation) {
55133a3a91bSChristian Sigg   if (!attr)
55233a3a91bSChristian Sigg     return llvm::UndefValue::get(llvmType);
5535ef21506SAdrian Kuegel   if (auto *structType = dyn_cast<::llvm::StructType>(llvmType)) {
5545550c821STres Popp     auto arrayAttr = dyn_cast<ArrayAttr>(attr);
555318b0678SSirui Mu     if (!arrayAttr) {
556318b0678SSirui Mu       emitError(loc, "expected an array attribute for a struct constant");
557a4a42160SAlex Zinenko       return nullptr;
558a4a42160SAlex Zinenko     }
559318b0678SSirui Mu     SmallVector<llvm::Constant *> structElements;
560318b0678SSirui Mu     structElements.reserve(structType->getNumElements());
561318b0678SSirui Mu     for (auto [elemType, elemAttr] :
562318b0678SSirui Mu          zip_equal(structType->elements(), arrayAttr)) {
563318b0678SSirui Mu       llvm::Constant *element =
564318b0678SSirui Mu           getLLVMConstant(elemType, elemAttr, loc, moduleTranslation);
565318b0678SSirui Mu       if (!element)
5665ef21506SAdrian Kuegel         return nullptr;
567318b0678SSirui Mu       structElements.push_back(element);
568318b0678SSirui Mu     }
569318b0678SSirui Mu     return llvm::ConstantStruct::get(structType, structElements);
5705ef21506SAdrian Kuegel   }
571ac9d742bSStephan Herhut   // For integer types, we allow a mismatch in sizes as the index type in
572ac9d742bSStephan Herhut   // MLIR might have a different size than the index type in the LLVM module.
5735550c821STres Popp   if (auto intAttr = dyn_cast<IntegerAttr>(attr))
574ac9d742bSStephan Herhut     return llvm::ConstantInt::get(
575ac9d742bSStephan Herhut         llvmType,
576ac9d742bSStephan Herhut         intAttr.getValue().sextOrTrunc(llvmType->getIntegerBitWidth()));
5775550c821STres Popp   if (auto floatAttr = dyn_cast<FloatAttr>(attr)) {
57873eecc9cSKrzysztof Drewniak     const llvm::fltSemantics &sem = floatAttr.getValue().getSemantics();
57973eecc9cSKrzysztof Drewniak     // Special case for 8-bit floats, which are represented by integers due to
58051b65d08SKrzysztof Drewniak     // the lack of native fp8 types in LLVM at the moment. Additionally, handle
58151b65d08SKrzysztof Drewniak     // targets (like AMDGPU) that don't implement bfloat and convert all bfloats
58251b65d08SKrzysztof Drewniak     // to i16.
58351b65d08SKrzysztof Drewniak     unsigned floatWidth = APFloat::getSizeInBits(sem);
58451b65d08SKrzysztof Drewniak     if (llvmType->isIntegerTy(floatWidth))
58573eecc9cSKrzysztof Drewniak       return llvm::ConstantInt::get(llvmType,
58673eecc9cSKrzysztof Drewniak                                     floatAttr.getValue().bitcastToAPInt());
5875ef21506SAdrian Kuegel     if (llvmType !=
5885ef21506SAdrian Kuegel         llvm::Type::getFloatingPointTy(llvmType->getContext(),
5895ef21506SAdrian Kuegel                                        floatAttr.getValue().getSemantics())) {
5905ef21506SAdrian Kuegel       emitError(loc, "FloatAttr does not match expected type of the constant");
5915ef21506SAdrian Kuegel       return nullptr;
5925ef21506SAdrian Kuegel     }
5935d7231d8SStephan Herhut     return llvm::ConstantFP::get(llvmType, floatAttr.getValue());
5945ef21506SAdrian Kuegel   }
5955550c821STres Popp   if (auto funcAttr = dyn_cast<FlatSymbolRefAttr>(attr))
596176379e0SAlex Zinenko     return llvm::ConstantExpr::getBitCast(
597176379e0SAlex Zinenko         moduleTranslation.lookupFunction(funcAttr.getValue()), llvmType);
5985550c821STres Popp   if (auto splatAttr = dyn_cast<SplatElementsAttr>(attr)) {
59968b03aeeSEli Friedman     llvm::Type *elementType;
60068b03aeeSEli Friedman     uint64_t numElements;
6017c564586SJavier Setoain     bool isScalable = false;
60268b03aeeSEli Friedman     if (auto *arrayTy = dyn_cast<llvm::ArrayType>(llvmType)) {
60368b03aeeSEli Friedman       elementType = arrayTy->getElementType();
60468b03aeeSEli Friedman       numElements = arrayTy->getNumElements();
60502b6fb21SMehdi Amini     } else if (auto *fVectorTy = dyn_cast<llvm::FixedVectorType>(llvmType)) {
606a4830d14SJavier Setoain       elementType = fVectorTy->getElementType();
607a4830d14SJavier Setoain       numElements = fVectorTy->getNumElements();
60802b6fb21SMehdi Amini     } else if (auto *sVectorTy = dyn_cast<llvm::ScalableVectorType>(llvmType)) {
609a4830d14SJavier Setoain       elementType = sVectorTy->getElementType();
610a4830d14SJavier Setoain       numElements = sVectorTy->getMinNumElements();
6117c564586SJavier Setoain       isScalable = true;
61268b03aeeSEli Friedman     } else {
613a4830d14SJavier Setoain       llvm_unreachable("unrecognized constant vector type");
61468b03aeeSEli Friedman     }
615d6ea8ff0SAlex Zinenko     // Splat value is a scalar. Extract it only if the element type is not
616d6ea8ff0SAlex Zinenko     // another sequence type. The recursion terminates because each step removes
617d6ea8ff0SAlex Zinenko     // one outer sequential type.
61868b03aeeSEli Friedman     bool elementTypeSequential =
619d891d738SRahul Joshi         isa<llvm::ArrayType, llvm::VectorType>(elementType);
620d6ea8ff0SAlex Zinenko     llvm::Constant *child = getLLVMConstant(
621d6ea8ff0SAlex Zinenko         elementType,
622937e40a8SRiver Riddle         elementTypeSequential ? splatAttr
623937e40a8SRiver Riddle                               : splatAttr.getSplatValue<Attribute>(),
62427dad996SBenjamin Kramer         loc, moduleTranslation);
625a4a42160SAlex Zinenko     if (!child)
626a4a42160SAlex Zinenko       return nullptr;
6272f13df13SMLIR Team     if (llvmType->isVectorTy())
628396a42d9SRiver Riddle       return llvm::ConstantVector::getSplat(
6297c564586SJavier Setoain           llvm::ElementCount::get(numElements, /*Scalable=*/isScalable), child);
6302f13df13SMLIR Team     if (llvmType->isArrayTy()) {
631ac9d742bSStephan Herhut       auto *arrayType = llvm::ArrayType::get(elementType, numElements);
632428b9be6SValentin Clement (バレンタイン クレメン)       if (child->isZeroValue()) {
633428b9be6SValentin Clement (バレンタイン クレメン)         return llvm::ConstantAggregateZero::get(arrayType);
634428b9be6SValentin Clement (バレンタイン クレメン)       } else {
635428b9be6SValentin Clement (バレンタイン クレメン)         if (llvm::ConstantDataSequential::isElementTypeCompatible(
636428b9be6SValentin Clement (バレンタイン クレメン)                 elementType)) {
637428b9be6SValentin Clement (バレンタイン クレメン)           // TODO: Handle all compatible types. This code only handles integer.
638ad315ebfSMats Petersson           if (isa<llvm::IntegerType>(elementType)) {
639428b9be6SValentin Clement (バレンタイン クレメン)             if (llvm::ConstantInt *ci = dyn_cast<llvm::ConstantInt>(child)) {
640428b9be6SValentin Clement (バレンタイン クレメン)               if (ci->getBitWidth() == 8) {
641428b9be6SValentin Clement (バレンタイン クレメン)                 SmallVector<int8_t> constants(numElements, ci->getZExtValue());
642428b9be6SValentin Clement (バレンタイン クレメン)                 return llvm::ConstantDataArray::get(elementType->getContext(),
643428b9be6SValentin Clement (バレンタイン クレメン)                                                     constants);
644428b9be6SValentin Clement (バレンタイン クレメン)               }
645428b9be6SValentin Clement (バレンタイン クレメン)               if (ci->getBitWidth() == 16) {
646428b9be6SValentin Clement (バレンタイン クレメン)                 SmallVector<int16_t> constants(numElements, ci->getZExtValue());
647428b9be6SValentin Clement (バレンタイン クレメン)                 return llvm::ConstantDataArray::get(elementType->getContext(),
648428b9be6SValentin Clement (バレンタイン クレメン)                                                     constants);
649428b9be6SValentin Clement (バレンタイン クレメン)               }
650428b9be6SValentin Clement (バレンタイン クレメン)               if (ci->getBitWidth() == 32) {
651428b9be6SValentin Clement (バレンタイン クレメン)                 SmallVector<int32_t> constants(numElements, ci->getZExtValue());
652428b9be6SValentin Clement (バレンタイン クレメン)                 return llvm::ConstantDataArray::get(elementType->getContext(),
653428b9be6SValentin Clement (バレンタイン クレメン)                                                     constants);
654428b9be6SValentin Clement (バレンタイン クレメン)               }
655428b9be6SValentin Clement (バレンタイン クレメン)               if (ci->getBitWidth() == 64) {
656428b9be6SValentin Clement (バレンタイン クレメン)                 SmallVector<int64_t> constants(numElements, ci->getZExtValue());
657428b9be6SValentin Clement (バレンタイン クレメン)                 return llvm::ConstantDataArray::get(elementType->getContext(),
658428b9be6SValentin Clement (バレンタイン クレメン)                                                     constants);
659428b9be6SValentin Clement (バレンタイン クレメン)               }
660428b9be6SValentin Clement (バレンタイン クレメン)             }
661428b9be6SValentin Clement (バレンタイン クレメン)           }
662428b9be6SValentin Clement (バレンタイン クレメン)         }
663428b9be6SValentin Clement (バレンタイン クレメン)         // std::vector is used here to accomodate large number of elements that
664428b9be6SValentin Clement (バレンタイン クレメン)         // exceed SmallVector capacity.
665428b9be6SValentin Clement (バレンタイン クレメン)         std::vector<llvm::Constant *> constants(numElements, child);
6662f13df13SMLIR Team         return llvm::ConstantArray::get(arrayType, constants);
6672f13df13SMLIR Team       }
6685d7231d8SStephan Herhut     }
669428b9be6SValentin Clement (バレンタイン クレメン)   }
670a4a42160SAlex Zinenko 
671f9be7a7aSAlex Zinenko   // Try using raw elements data if possible.
672f9be7a7aSAlex Zinenko   if (llvm::Constant *result =
6735550c821STres Popp           convertDenseElementsAttr(loc, dyn_cast<DenseElementsAttr>(attr),
674f9be7a7aSAlex Zinenko                                    llvmType, moduleTranslation)) {
675f9be7a7aSAlex Zinenko     return result;
676f9be7a7aSAlex Zinenko   }
677f9be7a7aSAlex Zinenko 
6789261ab70SKunwar Grover   if (auto denseResourceAttr = dyn_cast<DenseResourceElementsAttr>(attr)) {
6799261ab70SKunwar Grover     return convertDenseResourceElementsAttr(loc, denseResourceAttr, llvmType,
6809261ab70SKunwar Grover                                             moduleTranslation);
6819261ab70SKunwar Grover   }
6829261ab70SKunwar Grover 
683f9be7a7aSAlex Zinenko   // Fall back to element-by-element construction otherwise.
6845550c821STres Popp   if (auto elementsAttr = dyn_cast<ElementsAttr>(attr)) {
6858db947daSRahul Kayaith     assert(elementsAttr.getShapedType().hasStaticShape());
6868db947daSRahul Kayaith     assert(!elementsAttr.getShapedType().getShape().empty() &&
687a4a42160SAlex Zinenko            "unexpected empty elements attribute shape");
688a4a42160SAlex Zinenko 
6895d7231d8SStephan Herhut     SmallVector<llvm::Constant *, 8> constants;
690a4a42160SAlex Zinenko     constants.reserve(elementsAttr.getNumElements());
691a4a42160SAlex Zinenko     llvm::Type *innermostType = getInnermostElementType(llvmType);
692d906f84bSRiver Riddle     for (auto n : elementsAttr.getValues<Attribute>()) {
693176379e0SAlex Zinenko       constants.push_back(
69427dad996SBenjamin Kramer           getLLVMConstant(innermostType, n, loc, moduleTranslation));
6955d7231d8SStephan Herhut       if (!constants.back())
6965d7231d8SStephan Herhut         return nullptr;
6975d7231d8SStephan Herhut     }
698a4a42160SAlex Zinenko     ArrayRef<llvm::Constant *> constantsRef = constants;
699a4a42160SAlex Zinenko     llvm::Constant *result = buildSequentialConstant(
7008db947daSRahul Kayaith         constantsRef, elementsAttr.getShapedType().getShape(), llvmType, loc);
701a4a42160SAlex Zinenko     assert(constantsRef.empty() && "did not consume all elemental constants");
702a4a42160SAlex Zinenko     return result;
7032f13df13SMLIR Team   }
704a4a42160SAlex Zinenko 
7055550c821STres Popp   if (auto stringAttr = dyn_cast<StringAttr>(attr)) {
706cb348dffSStephan Herhut     return llvm::ConstantDataArray::get(
707176379e0SAlex Zinenko         moduleTranslation.getLLVMContext(),
708176379e0SAlex Zinenko         ArrayRef<char>{stringAttr.getValue().data(),
709cb348dffSStephan Herhut                        stringAttr.getValue().size()});
710cb348dffSStephan Herhut   }
711a4c3a645SRiver Riddle   emitError(loc, "unsupported constant value");
7125d7231d8SStephan Herhut   return nullptr;
7135d7231d8SStephan Herhut }
7145d7231d8SStephan Herhut 
715c33d6970SRiver Riddle ModuleTranslation::ModuleTranslation(Operation *module,
716c33d6970SRiver Riddle                                      std::unique_ptr<llvm::Module> llvmModule)
717c33d6970SRiver Riddle     : mlirModule(module), llvmModule(std::move(llvmModule)),
718c33d6970SRiver Riddle       debugTranslation(
71992a295ebSKiran Chandramohan           std::make_unique<DebugTranslation>(module, *this->llvmModule)),
72087a04795SChristian Ulmann       loopAnnotationTranslation(std::make_unique<LoopAnnotationTranslation>(
7219170fa58SMarkus Böck           *this, *this->llvmModule)),
722b77bac05SAlex Zinenko       typeTranslator(this->llvmModule->getContext()),
723b77bac05SAlex Zinenko       iface(module->getContext()) {
724c33d6970SRiver Riddle   assert(satisfiesLLVMModule(mlirModule) &&
725c33d6970SRiver Riddle          "mlirModule should honor LLVM's module semantics.");
726c33d6970SRiver Riddle }
727d3f9388fSJan Sjodin 
728d9067dcaSKiran Chandramohan ModuleTranslation::~ModuleTranslation() {
729d9067dcaSKiran Chandramohan   if (ompBuilder)
730d9067dcaSKiran Chandramohan     ompBuilder->finalize();
731d9067dcaSKiran Chandramohan }
732d9067dcaSKiran Chandramohan 
7338647e4c3SAlex Zinenko void ModuleTranslation::forgetMapping(Region &region) {
7348647e4c3SAlex Zinenko   SmallVector<Region *> toProcess;
7358647e4c3SAlex Zinenko   toProcess.push_back(&region);
7368647e4c3SAlex Zinenko   while (!toProcess.empty()) {
7378647e4c3SAlex Zinenko     Region *current = toProcess.pop_back_val();
7388647e4c3SAlex Zinenko     for (Block &block : *current) {
7398647e4c3SAlex Zinenko       blockMapping.erase(&block);
7408647e4c3SAlex Zinenko       for (Value arg : block.getArguments())
7418647e4c3SAlex Zinenko         valueMapping.erase(arg);
7428647e4c3SAlex Zinenko       for (Operation &op : block) {
7438647e4c3SAlex Zinenko         for (Value value : op.getResults())
7448647e4c3SAlex Zinenko           valueMapping.erase(value);
7458647e4c3SAlex Zinenko         if (op.hasSuccessors())
7468647e4c3SAlex Zinenko           branchMapping.erase(&op);
7478647e4c3SAlex Zinenko         if (isa<LLVM::GlobalOp>(op))
7488647e4c3SAlex Zinenko           globalsMapping.erase(&op);
74927534d69STom Eccles         if (isa<LLVM::CallOp>(op))
75027534d69STom Eccles           callMapping.erase(&op);
7518647e4c3SAlex Zinenko         llvm::append_range(
7528647e4c3SAlex Zinenko             toProcess,
7538647e4c3SAlex Zinenko             llvm::map_range(op.getRegions(), [](Region &r) { return &r; }));
7548647e4c3SAlex Zinenko       }
7558647e4c3SAlex Zinenko     }
7568647e4c3SAlex Zinenko   }
7578647e4c3SAlex Zinenko }
7588647e4c3SAlex Zinenko 
759d9067dcaSKiran Chandramohan /// Get the SSA value passed to the current block from the terminator operation
760d9067dcaSKiran Chandramohan /// of its predecessor.
761d9067dcaSKiran Chandramohan static Value getPHISourceValue(Block *current, Block *pred,
762d9067dcaSKiran Chandramohan                                unsigned numArguments, unsigned index) {
763d9067dcaSKiran Chandramohan   Operation &terminator = *pred->getTerminator();
764d9067dcaSKiran Chandramohan   if (isa<LLVM::BrOp>(terminator))
765d9067dcaSKiran Chandramohan     return terminator.getOperand(index);
766d9067dcaSKiran Chandramohan 
767bea16e72SAlex Zinenko #ifndef NDEBUG
768bea16e72SAlex Zinenko   llvm::SmallPtrSet<Block *, 4> seenSuccessors;
769bea16e72SAlex Zinenko   for (unsigned i = 0, e = terminator.getNumSuccessors(); i < e; ++i) {
770bea16e72SAlex Zinenko     Block *successor = terminator.getSuccessor(i);
771bea16e72SAlex Zinenko     auto branch = cast<BranchOpInterface>(terminator);
7720c789db5SMarkus Böck     SuccessorOperands successorOperands = branch.getSuccessorOperands(i);
773bea16e72SAlex Zinenko     assert(
7740c789db5SMarkus Böck         (!seenSuccessors.contains(successor) || successorOperands.empty()) &&
77514f24155SBrian Gesiak         "successors with arguments in LLVM branches must be different blocks");
776bea16e72SAlex Zinenko     seenSuccessors.insert(successor);
777bea16e72SAlex Zinenko   }
778bea16e72SAlex Zinenko #endif
779d9067dcaSKiran Chandramohan 
78014f24155SBrian Gesiak   // For instructions that branch based on a condition value, we need to take
78114f24155SBrian Gesiak   // the operands for the branch that was taken.
78214f24155SBrian Gesiak   if (auto condBranchOp = dyn_cast<LLVM::CondBrOp>(terminator)) {
78314f24155SBrian Gesiak     // For conditional branches, we take the operands from either the "true" or
78414f24155SBrian Gesiak     // the "false" branch.
785d9067dcaSKiran Chandramohan     return condBranchOp.getSuccessor(0) == current
786cfb72fd3SJacques Pienaar                ? condBranchOp.getTrueDestOperands()[index]
787cfb72fd3SJacques Pienaar                : condBranchOp.getFalseDestOperands()[index];
7880881a4f1SAlex Zinenko   }
7890881a4f1SAlex Zinenko 
7900881a4f1SAlex Zinenko   if (auto switchOp = dyn_cast<LLVM::SwitchOp>(terminator)) {
79114f24155SBrian Gesiak     // For switches, we take the operands from either the default case, or from
79214f24155SBrian Gesiak     // the case branch that was taken.
793dde96363SJacques Pienaar     if (switchOp.getDefaultDestination() == current)
794dde96363SJacques Pienaar       return switchOp.getDefaultOperands()[index];
795e4853be2SMehdi Amini     for (const auto &i : llvm::enumerate(switchOp.getCaseDestinations()))
79614f24155SBrian Gesiak       if (i.value() == current)
79714f24155SBrian Gesiak         return switchOp.getCaseOperands(i.index())[index];
79814f24155SBrian Gesiak   }
79914f24155SBrian Gesiak 
80056097205SMarkus Böck   if (auto invokeOp = dyn_cast<LLVM::InvokeOp>(terminator)) {
80156097205SMarkus Böck     return invokeOp.getNormalDest() == current
80256097205SMarkus Böck                ? invokeOp.getNormalDestOperands()[index]
80356097205SMarkus Böck                : invokeOp.getUnwindDestOperands()[index];
80456097205SMarkus Böck   }
80556097205SMarkus Böck 
80656097205SMarkus Böck   llvm_unreachable(
80756097205SMarkus Böck       "only branch, switch or invoke operations can be terminators "
80856097205SMarkus Böck       "of a block that has successors");
809d9067dcaSKiran Chandramohan }
810d9067dcaSKiran Chandramohan 
811d9067dcaSKiran Chandramohan /// Connect the PHI nodes to the results of preceding blocks.
81266900b3eSAlex Zinenko void mlir::LLVM::detail::connectPHINodes(Region &region,
81366900b3eSAlex Zinenko                                          const ModuleTranslation &state) {
814d9067dcaSKiran Chandramohan   // Skip the first block, it cannot be branched to and its arguments correspond
815d9067dcaSKiran Chandramohan   // to the arguments of the LLVM function.
8165605a1eeSKazu Hirata   for (Block &bb : llvm::drop_begin(region)) {
8175605a1eeSKazu Hirata     llvm::BasicBlock *llvmBB = state.lookupBlock(&bb);
818d9067dcaSKiran Chandramohan     auto phis = llvmBB->phis();
8195605a1eeSKazu Hirata     auto numArguments = bb.getNumArguments();
820d9067dcaSKiran Chandramohan     assert(numArguments == std::distance(phis.begin(), phis.end()));
8218c258fdaSJakub Kuderski     for (auto [index, phiNode] : llvm::enumerate(phis)) {
8225605a1eeSKazu Hirata       for (auto *pred : bb.getPredecessors()) {
823db884dafSAlex Zinenko         // Find the LLVM IR block that contains the converted terminator
824db884dafSAlex Zinenko         // instruction and use it in the PHI node. Note that this block is not
8250881a4f1SAlex Zinenko         // necessarily the same as state.lookupBlock(pred), some operations
826db884dafSAlex Zinenko         // (in particular, OpenMP operations using OpenMPIRBuilder) may have
827db884dafSAlex Zinenko         // split the blocks.
828db884dafSAlex Zinenko         llvm::Instruction *terminator =
8290881a4f1SAlex Zinenko             state.lookupBranch(pred->getTerminator());
830db884dafSAlex Zinenko         assert(terminator && "missing the mapping for a terminator");
8315605a1eeSKazu Hirata         phiNode.addIncoming(state.lookupValue(getPHISourceValue(
8325605a1eeSKazu Hirata                                 &bb, pred, numArguments, index)),
833db884dafSAlex Zinenko                             terminator->getParent());
834d9067dcaSKiran Chandramohan       }
835d9067dcaSKiran Chandramohan     }
836d9067dcaSKiran Chandramohan   }
837d9067dcaSKiran Chandramohan }
838d9067dcaSKiran Chandramohan 
83948b126e3SChristian Ulmann llvm::CallInst *mlir::LLVM::detail::createIntrinsicCall(
840176379e0SAlex Zinenko     llvm::IRBuilderBase &builder, llvm::Intrinsic::ID intrinsic,
841176379e0SAlex Zinenko     ArrayRef<llvm::Value *> args, ArrayRef<llvm::Type *> tys) {
842176379e0SAlex Zinenko   llvm::Module *module = builder.GetInsertBlock()->getModule();
843fa789dffSRahul Joshi   llvm::Function *fn =
844fa789dffSRahul Joshi       llvm::Intrinsic::getOrInsertDeclaration(module, intrinsic, tys);
845176379e0SAlex Zinenko   return builder.CreateCall(fn, args);
846176379e0SAlex Zinenko }
847176379e0SAlex Zinenko 
848dbb86433SBenjamin Maxwell llvm::CallInst *mlir::LLVM::detail::createIntrinsicCall(
849dbb86433SBenjamin Maxwell     llvm::IRBuilderBase &builder, ModuleTranslation &moduleTranslation,
850dbb86433SBenjamin Maxwell     Operation *intrOp, llvm::Intrinsic::ID intrinsic, unsigned numResults,
851dbb86433SBenjamin Maxwell     ArrayRef<unsigned> overloadedResults, ArrayRef<unsigned> overloadedOperands,
852dbb86433SBenjamin Maxwell     ArrayRef<unsigned> immArgPositions,
853dbb86433SBenjamin Maxwell     ArrayRef<StringLiteral> immArgAttrNames) {
854dbb86433SBenjamin Maxwell   assert(immArgPositions.size() == immArgAttrNames.size() &&
855dbb86433SBenjamin Maxwell          "LLVM `immArgPositions` and MLIR `immArgAttrNames` should have equal "
856dbb86433SBenjamin Maxwell          "length");
857dbb86433SBenjamin Maxwell 
8581dfb104eSSirui Mu   SmallVector<llvm::OperandBundleDef> opBundles;
8591dfb104eSSirui Mu   size_t numOpBundleOperands = 0;
8601dfb104eSSirui Mu   auto opBundleSizesAttr = cast_if_present<DenseI32ArrayAttr>(
8611dfb104eSSirui Mu       intrOp->getAttr(LLVMDialect::getOpBundleSizesAttrName()));
8621dfb104eSSirui Mu   auto opBundleTagsAttr = cast_if_present<ArrayAttr>(
8631dfb104eSSirui Mu       intrOp->getAttr(LLVMDialect::getOpBundleTagsAttrName()));
8641dfb104eSSirui Mu 
8651dfb104eSSirui Mu   if (opBundleSizesAttr && opBundleTagsAttr) {
8661dfb104eSSirui Mu     ArrayRef<int> opBundleSizes = opBundleSizesAttr.asArrayRef();
8671dfb104eSSirui Mu     assert(opBundleSizes.size() == opBundleTagsAttr.size() &&
8681dfb104eSSirui Mu            "operand bundles and tags do not match");
8691dfb104eSSirui Mu 
8701dfb104eSSirui Mu     numOpBundleOperands =
8711dfb104eSSirui Mu         std::accumulate(opBundleSizes.begin(), opBundleSizes.end(), size_t(0));
8721dfb104eSSirui Mu     assert(numOpBundleOperands <= intrOp->getNumOperands() &&
8731dfb104eSSirui Mu            "operand bundle operands is more than the number of operands");
8741dfb104eSSirui Mu 
8751dfb104eSSirui Mu     ValueRange operands = intrOp->getOperands().take_back(numOpBundleOperands);
8761dfb104eSSirui Mu     size_t nextOperandIdx = 0;
8771dfb104eSSirui Mu     opBundles.reserve(opBundleSizesAttr.size());
8781dfb104eSSirui Mu 
8791dfb104eSSirui Mu     for (auto [opBundleTagAttr, bundleSize] :
8801dfb104eSSirui Mu          llvm::zip(opBundleTagsAttr, opBundleSizes)) {
8811dfb104eSSirui Mu       auto bundleTag = cast<StringAttr>(opBundleTagAttr).str();
8821dfb104eSSirui Mu       auto bundleOperands = moduleTranslation.lookupValues(
8831dfb104eSSirui Mu           operands.slice(nextOperandIdx, bundleSize));
8841dfb104eSSirui Mu       opBundles.emplace_back(std::move(bundleTag), std::move(bundleOperands));
8851dfb104eSSirui Mu       nextOperandIdx += bundleSize;
8861dfb104eSSirui Mu     }
8871dfb104eSSirui Mu   }
8881dfb104eSSirui Mu 
889dbb86433SBenjamin Maxwell   // Map operands and attributes to LLVM values.
8901dfb104eSSirui Mu   auto opOperands = intrOp->getOperands().drop_back(numOpBundleOperands);
8911dfb104eSSirui Mu   auto operands = moduleTranslation.lookupValues(opOperands);
892dbb86433SBenjamin Maxwell   SmallVector<llvm::Value *> args(immArgPositions.size() + operands.size());
893dbb86433SBenjamin Maxwell   for (auto [immArgPos, immArgName] :
894dbb86433SBenjamin Maxwell        llvm::zip(immArgPositions, immArgAttrNames)) {
895dbb86433SBenjamin Maxwell     auto attr = llvm::cast<TypedAttr>(intrOp->getAttr(immArgName));
896dbb86433SBenjamin Maxwell     assert(attr.getType().isIntOrFloat() && "expected int or float immarg");
897dbb86433SBenjamin Maxwell     auto *type = moduleTranslation.convertType(attr.getType());
898dbb86433SBenjamin Maxwell     args[immArgPos] = LLVM::detail::getLLVMConstant(
899dbb86433SBenjamin Maxwell         type, attr, intrOp->getLoc(), moduleTranslation);
900dbb86433SBenjamin Maxwell   }
901dbb86433SBenjamin Maxwell   unsigned opArg = 0;
902dbb86433SBenjamin Maxwell   for (auto &arg : args) {
903dbb86433SBenjamin Maxwell     if (!arg)
904dbb86433SBenjamin Maxwell       arg = operands[opArg++];
905dbb86433SBenjamin Maxwell   }
906dbb86433SBenjamin Maxwell 
907dbb86433SBenjamin Maxwell   // Resolve overloaded intrinsic declaration.
908dbb86433SBenjamin Maxwell   SmallVector<llvm::Type *> overloadedTypes;
909dbb86433SBenjamin Maxwell   for (unsigned overloadedResultIdx : overloadedResults) {
910dbb86433SBenjamin Maxwell     if (numResults > 1) {
911dbb86433SBenjamin Maxwell       // More than one result is mapped to an LLVM struct.
912dbb86433SBenjamin Maxwell       overloadedTypes.push_back(moduleTranslation.convertType(
913dbb86433SBenjamin Maxwell           llvm::cast<LLVM::LLVMStructType>(intrOp->getResult(0).getType())
914dbb86433SBenjamin Maxwell               .getBody()[overloadedResultIdx]));
915dbb86433SBenjamin Maxwell     } else {
916dbb86433SBenjamin Maxwell       overloadedTypes.push_back(
917dbb86433SBenjamin Maxwell           moduleTranslation.convertType(intrOp->getResult(0).getType()));
918dbb86433SBenjamin Maxwell     }
919dbb86433SBenjamin Maxwell   }
920dbb86433SBenjamin Maxwell   for (unsigned overloadedOperandIdx : overloadedOperands)
921dbb86433SBenjamin Maxwell     overloadedTypes.push_back(args[overloadedOperandIdx]->getType());
922dbb86433SBenjamin Maxwell   llvm::Module *module = builder.GetInsertBlock()->getModule();
923fa789dffSRahul Joshi   llvm::Function *llvmIntr = llvm::Intrinsic::getOrInsertDeclaration(
924fa789dffSRahul Joshi       module, intrinsic, overloadedTypes);
925dbb86433SBenjamin Maxwell 
9261dfb104eSSirui Mu   return builder.CreateCall(llvmIntr, args, opBundles);
927dbb86433SBenjamin Maxwell }
928dbb86433SBenjamin Maxwell 
9292666b973SRiver Riddle /// Given a single MLIR operation, create the corresponding LLVM IR operation
930176379e0SAlex Zinenko /// using the `builder`.
9319519e3ecSOleksandr "Alex" Zinenko LogicalResult ModuleTranslation::convertOperation(Operation &op,
9329519e3ecSOleksandr "Alex" Zinenko                                                   llvm::IRBuilderBase &builder,
9339519e3ecSOleksandr "Alex" Zinenko                                                   bool recordInsertions) {
93438b106f6SMehdi Amini   const LLVMTranslationDialectInterface *opIface = iface.getInterfaceFor(&op);
93538b106f6SMehdi Amini   if (!opIface)
93638b106f6SMehdi Amini     return op.emitError("cannot be converted to LLVM IR: missing "
93738b106f6SMehdi Amini                         "`LLVMTranslationDialectInterface` registration for "
93838b106f6SMehdi Amini                         "dialect for op: ")
93938b106f6SMehdi Amini            << op.getName();
940176379e0SAlex Zinenko 
9419519e3ecSOleksandr "Alex" Zinenko   InstructionCapturingInserter::CollectionScope scope(builder,
9429519e3ecSOleksandr "Alex" Zinenko                                                       recordInsertions);
94338b106f6SMehdi Amini   if (failed(opIface->convertOperation(&op, builder, *this)))
94438b106f6SMehdi Amini     return op.emitError("LLVM Translation failed for operation: ")
94538b106f6SMehdi Amini            << op.getName();
94638b106f6SMehdi Amini 
9479519e3ecSOleksandr "Alex" Zinenko   return convertDialectAttributes(&op, scope.getCapturedInstructions());
9485d7231d8SStephan Herhut }
9495d7231d8SStephan Herhut 
9502666b973SRiver Riddle /// Convert block to LLVM IR.  Unless `ignoreArguments` is set, emit PHI nodes
9512666b973SRiver Riddle /// to define values corresponding to the MLIR block arguments.  These nodes
95210164a2eSAlex Zinenko /// are not connected to the source basic blocks, which may not exist yet.  Uses
95310164a2eSAlex Zinenko /// `builder` to construct the LLVM IR. Expects the LLVM IR basic block to have
95410164a2eSAlex Zinenko /// been created for `bb` and included in the block mapping.  Inserts new
95510164a2eSAlex Zinenko /// instructions at the end of the block and leaves `builder` in a state
95610164a2eSAlex Zinenko /// suitable for further insertion into the end of the block.
9579519e3ecSOleksandr "Alex" Zinenko LogicalResult ModuleTranslation::convertBlockImpl(Block &bb,
9589519e3ecSOleksandr "Alex" Zinenko                                                   bool ignoreArguments,
9599519e3ecSOleksandr "Alex" Zinenko                                                   llvm::IRBuilderBase &builder,
9609519e3ecSOleksandr "Alex" Zinenko                                                   bool recordInsertions) {
9610881a4f1SAlex Zinenko   builder.SetInsertPoint(lookupBlock(&bb));
962c33d6970SRiver Riddle   auto *subprogram = builder.GetInsertBlock()->getParent()->getSubprogram();
9635d7231d8SStephan Herhut 
9645d7231d8SStephan Herhut   // Before traversing operations, make block arguments available through
9655d7231d8SStephan Herhut   // value remapping and PHI nodes, but do not add incoming edges for the PHI
9665d7231d8SStephan Herhut   // nodes just yet: those values may be defined by this or following blocks.
9675d7231d8SStephan Herhut   // This step is omitted if "ignoreArguments" is set.  The arguments of the
9685d7231d8SStephan Herhut   // first block have been already made available through the remapping of
9695d7231d8SStephan Herhut   // LLVM function arguments.
9705d7231d8SStephan Herhut   if (!ignoreArguments) {
9715d7231d8SStephan Herhut     auto predecessors = bb.getPredecessors();
9725d7231d8SStephan Herhut     unsigned numPredecessors =
9735d7231d8SStephan Herhut         std::distance(predecessors.begin(), predecessors.end());
97435807bc4SRiver Riddle     for (auto arg : bb.getArguments()) {
975c69c9e0fSAlex Zinenko       auto wrappedType = arg.getType();
976c69c9e0fSAlex Zinenko       if (!isCompatibleType(wrappedType))
977baa1ec22SAlex Zinenko         return emitError(bb.front().getLoc(),
978a4c3a645SRiver Riddle                          "block argument does not have an LLVM type");
97900a1a45aSAbid Qadeer       builder.SetCurrentDebugLocation(
98000a1a45aSAbid Qadeer           debugTranslation->translateLoc(arg.getLoc(), subprogram));
981aec38c61SAlex Zinenko       llvm::Type *type = convertType(wrappedType);
9825d7231d8SStephan Herhut       llvm::PHINode *phi = builder.CreatePHI(type, numPredecessors);
9830881a4f1SAlex Zinenko       mapValue(arg, phi);
9845d7231d8SStephan Herhut     }
9855d7231d8SStephan Herhut   }
9865d7231d8SStephan Herhut 
9875d7231d8SStephan Herhut   // Traverse operations.
9885d7231d8SStephan Herhut   for (auto &op : bb) {
989c33d6970SRiver Riddle     // Set the current debug location within the builder.
990c33d6970SRiver Riddle     builder.SetCurrentDebugLocation(
991c33d6970SRiver Riddle         debugTranslation->translateLoc(op.getLoc(), subprogram));
992c33d6970SRiver Riddle 
9939519e3ecSOleksandr "Alex" Zinenko     if (failed(convertOperation(op, builder, recordInsertions)))
994baa1ec22SAlex Zinenko       return failure();
99510fa2770STobias Gysi 
99610fa2770STobias Gysi     // Set the branch weight metadata on the translated instruction.
99710fa2770STobias Gysi     if (auto iface = dyn_cast<BranchWeightOpInterface>(op))
99810fa2770STobias Gysi       setBranchWeightsMetadata(iface);
9995d7231d8SStephan Herhut   }
10005d7231d8SStephan Herhut 
1001baa1ec22SAlex Zinenko   return success();
10025d7231d8SStephan Herhut }
10035d7231d8SStephan Herhut 
1004ce8f10d6SAlex Zinenko /// A helper method to get the single Block in an operation honoring LLVM's
1005ce8f10d6SAlex Zinenko /// module requirements.
1006ce8f10d6SAlex Zinenko static Block &getModuleBody(Operation *module) {
1007ce8f10d6SAlex Zinenko   return module->getRegion(0).front();
1008ce8f10d6SAlex Zinenko }
1009ce8f10d6SAlex Zinenko 
1010ffa455d4SJean Perier /// A helper method to decide if a constant must not be set as a global variable
1011d4df3825SAlex Zinenko /// initializer. For an external linkage variable, the variable with an
1012d4df3825SAlex Zinenko /// initializer is considered externally visible and defined in this module, the
1013d4df3825SAlex Zinenko /// variable without an initializer is externally available and is defined
1014d4df3825SAlex Zinenko /// elsewhere.
1015ffa455d4SJean Perier static bool shouldDropGlobalInitializer(llvm::GlobalValue::LinkageTypes linkage,
1016ffa455d4SJean Perier                                         llvm::Constant *cst) {
1017d4df3825SAlex Zinenko   return (linkage == llvm::GlobalVariable::ExternalLinkage && !cst) ||
1018ffa455d4SJean Perier          linkage == llvm::GlobalVariable::ExternalWeakLinkage;
1019ffa455d4SJean Perier }
1020ffa455d4SJean Perier 
10218ca04b05SFelipe de Azevedo Piovezan /// Sets the runtime preemption specifier of `gv` to dso_local if
10228ca04b05SFelipe de Azevedo Piovezan /// `dsoLocalRequested` is true, otherwise it is left unchanged.
10238ca04b05SFelipe de Azevedo Piovezan static void addRuntimePreemptionSpecifier(bool dsoLocalRequested,
10248ca04b05SFelipe de Azevedo Piovezan                                           llvm::GlobalValue *gv) {
10258ca04b05SFelipe de Azevedo Piovezan   if (dsoLocalRequested)
10268ca04b05SFelipe de Azevedo Piovezan     gv->setDSOLocal(true);
10278ca04b05SFelipe de Azevedo Piovezan }
10288ca04b05SFelipe de Azevedo Piovezan 
10292666b973SRiver Riddle /// Create named global variables that correspond to llvm.mlir.global
103057b9b296SUday Bondhugula /// definitions. Convert llvm.global_ctors and global_dtors ops.
1031efa2d533SAlex Zinenko LogicalResult ModuleTranslation::convertGlobals() {
10326da578ceSJustin Wilson   // Mapping from compile unit to its respective set of global variables.
10336da578ceSJustin Wilson   DenseMap<llvm::DICompileUnit *, SmallVector<llvm::Metadata *>> allGVars;
10346da578ceSJustin Wilson 
103544fc7d72STres Popp   for (auto op : getModuleBody(mlirModule).getOps<LLVM::GlobalOp>()) {
1036aec38c61SAlex Zinenko     llvm::Type *type = convertType(op.getType());
1037d4df3825SAlex Zinenko     llvm::Constant *cst = nullptr;
1038250a11aeSJames Molloy     if (op.getValueOrNull()) {
103968451df2SAlex Zinenko       // String attributes are treated separately because they cannot appear as
104068451df2SAlex Zinenko       // in-function constants and are thus not supported by getLLVMConstant.
10415550c821STres Popp       if (auto strAttr = dyn_cast_or_null<StringAttr>(op.getValueOrNull())) {
10422dd38b09SAlex Zinenko         cst = llvm::ConstantDataArray::getString(
104368451df2SAlex Zinenko             llvmModule->getContext(), strAttr.getValue(), /*AddNull=*/false);
10442dd38b09SAlex Zinenko         type = cst->getType();
1045176379e0SAlex Zinenko       } else if (!(cst = getLLVMConstant(type, op.getValueOrNull(), op.getLoc(),
1046176379e0SAlex Zinenko                                          *this))) {
1047efa2d533SAlex Zinenko         return failure();
104868451df2SAlex Zinenko       }
1049ffa455d4SJean Perier     }
1050ffa455d4SJean Perier 
1051cfb72fd3SJacques Pienaar     auto linkage = convertLinkageToLLVM(op.getLinkage());
1052d4df3825SAlex Zinenko 
1053d4df3825SAlex Zinenko     // LLVM IR requires constant with linkage other than external or weak
1054d4df3825SAlex Zinenko     // external to have initializers. If MLIR does not provide an initializer,
1055d4df3825SAlex Zinenko     // default to undef.
1056d4df3825SAlex Zinenko     bool dropInitializer = shouldDropGlobalInitializer(linkage, cst);
1057d4df3825SAlex Zinenko     if (!dropInitializer && !cst)
1058d4df3825SAlex Zinenko       cst = llvm::UndefValue::get(type);
1059d4df3825SAlex Zinenko     else if (dropInitializer && cst)
1060d4df3825SAlex Zinenko       cst = nullptr;
1061d4df3825SAlex Zinenko 
1062ffa455d4SJean Perier     auto *var = new llvm::GlobalVariable(
1063cfb72fd3SJacques Pienaar         *llvmModule, type, op.getConstant(), linkage, cst, op.getSymName(),
1064f0ba32d6SShraiysh Vaishay         /*InsertBefore=*/nullptr,
1065f0ba32d6SShraiysh Vaishay         op.getThreadLocal_() ? llvm::GlobalValue::GeneralDynamicTLSModel
1066f0ba32d6SShraiysh Vaishay                              : llvm::GlobalValue::NotThreadLocal,
106780cd2141SMogball         op.getAddrSpace(), op.getExternallyInitialized());
1068ffa455d4SJean Perier 
10699d4c1be8SDavid Truby     if (std::optional<mlir::SymbolRefAttr> comdat = op.getComdat()) {
1070b126ee65STobias Gysi       auto selectorOp = cast<ComdatSelectorOp>(
1071b126ee65STobias Gysi           SymbolTable::lookupNearestSymbolFrom(op, *comdat));
1072b126ee65STobias Gysi       var->setComdat(comdatMapping.lookup(selectorOp));
10739d4c1be8SDavid Truby     }
10749d4c1be8SDavid Truby 
1075491d2701SKazu Hirata     if (op.getUnnamedAddr().has_value())
1076cfb72fd3SJacques Pienaar       var->setUnnamedAddr(convertUnnamedAddrToLLVM(*op.getUnnamedAddr()));
1077c46a8862Sclementval 
1078491d2701SKazu Hirata     if (op.getSection().has_value())
1079cfb72fd3SJacques Pienaar       var->setSection(*op.getSection());
1080b65472d6SRanjith Kumar H 
1081cfb72fd3SJacques Pienaar     addRuntimePreemptionSpecifier(op.getDsoLocal(), var);
10828ca04b05SFelipe de Azevedo Piovezan 
108322426110SRamkumar Ramachandra     std::optional<uint64_t> alignment = op.getAlignment();
1084491d2701SKazu Hirata     if (alignment.has_value())
1085c27d8152SKazu Hirata       var->setAlignment(llvm::MaybeAlign(alignment.value()));
10869a0ea599SDumitru Potop 
10876628767eSChristian Ulmann     var->setVisibility(convertVisibilityToLLVM(op.getVisibility_()));
10886628767eSChristian Ulmann 
1089ffa455d4SJean Perier     globalsMapping.try_emplace(op, var);
10906da578ceSJustin Wilson 
10916da578ceSJustin Wilson     // Add debug information if present.
1092cd12ffb6SAbid Qadeer     if (op.getDbgExprs()) {
1093cd12ffb6SAbid Qadeer       for (auto exprAttr :
1094cd12ffb6SAbid Qadeer            op.getDbgExprs()->getAsRange<DIGlobalVariableExpressionAttr>()) {
10956da578ceSJustin Wilson         llvm::DIGlobalVariableExpression *diGlobalExpr =
1096cd12ffb6SAbid Qadeer             debugTranslation->translateGlobalVariableExpression(exprAttr);
10976da578ceSJustin Wilson         llvm::DIGlobalVariable *diGlobalVar = diGlobalExpr->getVariable();
10986da578ceSJustin Wilson         var->addDebugInfo(diGlobalExpr);
10996da578ceSJustin Wilson 
1100cd12ffb6SAbid Qadeer         // There is no `globals` field in DICompileUnitAttr which can be
1101cd12ffb6SAbid Qadeer         // directly assigned to DICompileUnit. We have to build the list by
1102cd12ffb6SAbid Qadeer         // looking at the dbgExpr of all the GlobalOps. The scope of the
1103cd12ffb6SAbid Qadeer         // variable is used to get the DICompileUnit in which to add it. But
1104cd12ffb6SAbid Qadeer         // there are cases where the scope of a global does not directly point
1105cd12ffb6SAbid Qadeer         // to the DICompileUnit and we have to do a bit more work to get to
1106cd12ffb6SAbid Qadeer         // it. Some of those cases are:
110736c34ec9SAbid Qadeer         //
1108cd12ffb6SAbid Qadeer         // 1. For the languages that support modules, the scope hierarchy can
1109cd12ffb6SAbid Qadeer         // be variable -> DIModule -> DICompileUnit
111036c34ec9SAbid Qadeer         //
1111cd12ffb6SAbid Qadeer         // 2. For the Fortran common block variable, the scope hierarchy can
1112cd12ffb6SAbid Qadeer         // be variable -> DICommonBlock -> DISubprogram -> DICompileUnit
111336c34ec9SAbid Qadeer         //
111436c34ec9SAbid Qadeer         // 3. For entities like static local variables in C or variable with
111536c34ec9SAbid Qadeer         // SAVE attribute in Fortran, the scope hierarchy can be
111636c34ec9SAbid Qadeer         // variable -> DISubprogram -> DICompileUnit
111777b80bd8SAbid Qadeer         llvm::DIScope *scope = diGlobalVar->getScope();
1118dab36b28SAbid Qadeer         if (auto *mod = dyn_cast_if_present<llvm::DIModule>(scope))
111977b80bd8SAbid Qadeer           scope = mod->getScope();
112036c34ec9SAbid Qadeer         else if (auto *cb = dyn_cast_if_present<llvm::DICommonBlock>(scope)) {
1121cd12ffb6SAbid Qadeer           if (auto *sp =
1122cd12ffb6SAbid Qadeer                   dyn_cast_if_present<llvm::DISubprogram>(cb->getScope()))
112336c34ec9SAbid Qadeer             scope = sp->getUnit();
112436c34ec9SAbid Qadeer         } else if (auto *sp = dyn_cast_if_present<llvm::DISubprogram>(scope))
1125dab36b28SAbid Qadeer           scope = sp->getUnit();
112677b80bd8SAbid Qadeer 
11276da578ceSJustin Wilson         // Get the compile unit (scope) of the the global variable.
11286da578ceSJustin Wilson         if (llvm::DICompileUnit *compileUnit =
112977b80bd8SAbid Qadeer                 dyn_cast_if_present<llvm::DICompileUnit>(scope)) {
1130cd12ffb6SAbid Qadeer           // Update the compile unit with this incoming global variable
1131cd12ffb6SAbid Qadeer           // expression during the finalizing step later.
11326da578ceSJustin Wilson           allGVars[compileUnit].push_back(diGlobalExpr);
11336da578ceSJustin Wilson         }
11346da578ceSJustin Wilson       }
1135ffa455d4SJean Perier     }
1136cd12ffb6SAbid Qadeer   }
1137ffa455d4SJean Perier 
1138ffa455d4SJean Perier   // Convert global variable bodies. This is done after all global variables
1139ffa455d4SJean Perier   // have been created in LLVM IR because a global body may refer to another
1140ffa455d4SJean Perier   // global or itself. So all global variables need to be mapped first.
1141ffa455d4SJean Perier   for (auto op : getModuleBody(mlirModule).getOps<LLVM::GlobalOp>()) {
1142ffa455d4SJean Perier     if (Block *initializer = op.getInitializerBlock()) {
1143250a11aeSJames Molloy       llvm::IRBuilder<> builder(llvmModule->getContext());
1144c11627c2SXiang Li 
1145ef7417fbSJie Fu       [[maybe_unused]] int numConstantsHit = 0;
1146ef7417fbSJie Fu       [[maybe_unused]] int numConstantsErased = 0;
1147c11627c2SXiang Li       DenseMap<llvm::ConstantAggregate *, int> constantAggregateUseMap;
1148c11627c2SXiang Li 
1149250a11aeSJames Molloy       for (auto &op : initializer->without_terminator()) {
1150c11627c2SXiang Li         if (failed(convertOperation(op, builder)))
1151c11627c2SXiang Li           return emitError(op.getLoc(), "fail to convert global initializer");
1152c11627c2SXiang Li         auto *cst = dyn_cast<llvm::Constant>(lookupValue(op.getResult(0)));
1153c11627c2SXiang Li         if (!cst)
1154efa2d533SAlex Zinenko           return emitError(op.getLoc(), "unemittable constant value");
1155c11627c2SXiang Li 
1156c11627c2SXiang Li         // When emitting an LLVM constant, a new constant is created and the old
1157c11627c2SXiang Li         // constant may become dangling and take space. We should remove the
1158c11627c2SXiang Li         // dangling constants to avoid memory explosion especially for constant
1159c11627c2SXiang Li         // arrays whose number of elements is large.
1160c11627c2SXiang Li         // Because multiple operations may refer to the same constant, we need
1161c11627c2SXiang Li         // to count the number of uses of each constant array and remove it only
1162c11627c2SXiang Li         // when the count becomes zero.
1163c11627c2SXiang Li         if (auto *agg = dyn_cast<llvm::ConstantAggregate>(cst)) {
1164c11627c2SXiang Li           numConstantsHit++;
1165c11627c2SXiang Li           Value result = op.getResult(0);
1166c11627c2SXiang Li           int numUsers = std::distance(result.use_begin(), result.use_end());
1167c11627c2SXiang Li           auto [iterator, inserted] =
1168c11627c2SXiang Li               constantAggregateUseMap.try_emplace(agg, numUsers);
1169c11627c2SXiang Li           if (!inserted) {
1170c11627c2SXiang Li             // Key already exists, update the value
1171c11627c2SXiang Li             iterator->second += numUsers;
1172250a11aeSJames Molloy           }
1173c11627c2SXiang Li         }
1174c11627c2SXiang Li         // Scan the operands of the operation to decrement the use count of
1175c11627c2SXiang Li         // constants. Erase the constant if the use count becomes zero.
1176c11627c2SXiang Li         for (Value v : op.getOperands()) {
1177c11627c2SXiang Li           auto cst = dyn_cast<llvm::ConstantAggregate>(lookupValue(v));
1178c11627c2SXiang Li           if (!cst)
1179c11627c2SXiang Li             continue;
1180c11627c2SXiang Li           auto iter = constantAggregateUseMap.find(cst);
1181c11627c2SXiang Li           assert(iter != constantAggregateUseMap.end() && "constant not found");
1182c11627c2SXiang Li           iter->second--;
1183c11627c2SXiang Li           if (iter->second == 0) {
1184c11627c2SXiang Li             // NOTE: cannot call removeDeadConstantUsers() here because it
1185c11627c2SXiang Li             // may remove the constant which has uses not be converted yet.
1186c11627c2SXiang Li             if (cst->user_empty()) {
1187c11627c2SXiang Li               cst->destroyConstant();
1188c11627c2SXiang Li               numConstantsErased++;
1189c11627c2SXiang Li             }
1190c11627c2SXiang Li             constantAggregateUseMap.erase(iter);
1191c11627c2SXiang Li           }
1192c11627c2SXiang Li         }
1193c11627c2SXiang Li       }
1194c11627c2SXiang Li 
1195250a11aeSJames Molloy       ReturnOp ret = cast<ReturnOp>(initializer->getTerminator());
1196ffa455d4SJean Perier       llvm::Constant *cst =
1197ffa455d4SJean Perier           cast<llvm::Constant>(lookupValue(ret.getOperand(0)));
1198ffa455d4SJean Perier       auto *global = cast<llvm::GlobalVariable>(lookupGlobal(op));
1199ffa455d4SJean Perier       if (!shouldDropGlobalInitializer(global->getLinkage(), cst))
1200ffa455d4SJean Perier         global->setInitializer(cst);
1201c11627c2SXiang Li 
1202c11627c2SXiang Li       // Try to remove the dangling constants again after all operations are
1203c11627c2SXiang Li       // converted.
1204c11627c2SXiang Li       for (auto it : constantAggregateUseMap) {
1205c11627c2SXiang Li         auto cst = it.first;
1206c11627c2SXiang Li         cst->removeDeadConstantUsers();
1207c11627c2SXiang Li         if (cst->user_empty()) {
1208c11627c2SXiang Li           cst->destroyConstant();
1209c11627c2SXiang Li           numConstantsErased++;
1210c11627c2SXiang Li         }
1211c11627c2SXiang Li       }
1212c11627c2SXiang Li 
1213c11627c2SXiang Li       LLVM_DEBUG(llvm::dbgs()
1214c11627c2SXiang Li                      << "Convert initializer for " << op.getName() << "\n";
1215c11627c2SXiang Li                  llvm::dbgs() << numConstantsHit << " new constants hit\n";
1216c11627c2SXiang Li                  llvm::dbgs()
1217c11627c2SXiang Li                  << numConstantsErased << " dangling constants erased\n";);
1218250a11aeSJames Molloy     }
1219b9ff2dd8SAlex Zinenko   }
1220efa2d533SAlex Zinenko 
122157b9b296SUday Bondhugula   // Convert llvm.mlir.global_ctors and dtors.
122257b9b296SUday Bondhugula   for (Operation &op : getModuleBody(mlirModule)) {
122357b9b296SUday Bondhugula     auto ctorOp = dyn_cast<GlobalCtorsOp>(op);
122457b9b296SUday Bondhugula     auto dtorOp = dyn_cast<GlobalDtorsOp>(op);
122557b9b296SUday Bondhugula     if (!ctorOp && !dtorOp)
122657b9b296SUday Bondhugula       continue;
122762fea88bSJacques Pienaar     auto range = ctorOp ? llvm::zip(ctorOp.getCtors(), ctorOp.getPriorities())
122862fea88bSJacques Pienaar                         : llvm::zip(dtorOp.getDtors(), dtorOp.getPriorities());
122957b9b296SUday Bondhugula     auto appendGlobalFn =
123057b9b296SUday Bondhugula         ctorOp ? llvm::appendToGlobalCtors : llvm::appendToGlobalDtors;
123157b9b296SUday Bondhugula     for (auto symbolAndPriority : range) {
123257b9b296SUday Bondhugula       llvm::Function *f = lookupFunction(
12335550c821STres Popp           cast<FlatSymbolRefAttr>(std::get<0>(symbolAndPriority)).getValue());
12345550c821STres Popp       appendGlobalFn(*llvmModule, f,
12355550c821STres Popp                      cast<IntegerAttr>(std::get<1>(symbolAndPriority)).getInt(),
123657b9b296SUday Bondhugula                      /*Data=*/nullptr);
123757b9b296SUday Bondhugula     }
123857b9b296SUday Bondhugula   }
123957b9b296SUday Bondhugula 
1240f4787212SAndrew Gozillon   for (auto op : getModuleBody(mlirModule).getOps<LLVM::GlobalOp>())
12419519e3ecSOleksandr "Alex" Zinenko     if (failed(convertDialectAttributes(op, {})))
1242f4787212SAndrew Gozillon       return failure();
1243f4787212SAndrew Gozillon 
12446da578ceSJustin Wilson   // Finally, update the compile units their respective sets of global variables
12456da578ceSJustin Wilson   // created earlier.
12466da578ceSJustin Wilson   for (const auto &[compileUnit, globals] : allGVars) {
12476da578ceSJustin Wilson     compileUnit->replaceGlobalVariables(
12486da578ceSJustin Wilson         llvm::MDTuple::get(getLLVMContext(), globals));
12496da578ceSJustin Wilson   }
12506da578ceSJustin Wilson 
1251efa2d533SAlex Zinenko   return success();
1252b9ff2dd8SAlex Zinenko }
1253b9ff2dd8SAlex Zinenko 
12540a2131b7SAlex Zinenko /// Attempts to add an attribute identified by `key`, optionally with the given
12550a2131b7SAlex Zinenko /// `value` to LLVM function `llvmFunc`. Reports errors at `loc` if any. If the
12560a2131b7SAlex Zinenko /// attribute has a kind known to LLVM IR, create the attribute of this kind,
12570a2131b7SAlex Zinenko /// otherwise keep it as a string attribute. Performs additional checks for
12580a2131b7SAlex Zinenko /// attributes known to have or not have a value in order to avoid assertions
12590a2131b7SAlex Zinenko /// inside LLVM upon construction.
12600a2131b7SAlex Zinenko static LogicalResult checkedAddLLVMFnAttribute(Location loc,
12610a2131b7SAlex Zinenko                                                llvm::Function *llvmFunc,
12620a2131b7SAlex Zinenko                                                StringRef key,
12630a2131b7SAlex Zinenko                                                StringRef value = StringRef()) {
12640a2131b7SAlex Zinenko   auto kind = llvm::Attribute::getAttrKindFromName(key);
12650a2131b7SAlex Zinenko   if (kind == llvm::Attribute::None) {
12660a2131b7SAlex Zinenko     llvmFunc->addFnAttr(key, value);
12670a2131b7SAlex Zinenko     return success();
12680a2131b7SAlex Zinenko   }
12690a2131b7SAlex Zinenko 
12706ac32872SNikita Popov   if (llvm::Attribute::isIntAttrKind(kind)) {
12710a2131b7SAlex Zinenko     if (value.empty())
12720a2131b7SAlex Zinenko       return emitError(loc) << "LLVM attribute '" << key << "' expects a value";
12730a2131b7SAlex Zinenko 
12744f52210aSMogball     int64_t result;
12750a2131b7SAlex Zinenko     if (!value.getAsInteger(/*Radix=*/0, result))
12760a2131b7SAlex Zinenko       llvmFunc->addFnAttr(
12770a2131b7SAlex Zinenko           llvm::Attribute::get(llvmFunc->getContext(), kind, result));
12780a2131b7SAlex Zinenko     else
12790a2131b7SAlex Zinenko       llvmFunc->addFnAttr(key, value);
12800a2131b7SAlex Zinenko     return success();
12810a2131b7SAlex Zinenko   }
12820a2131b7SAlex Zinenko 
12830a2131b7SAlex Zinenko   if (!value.empty())
12840a2131b7SAlex Zinenko     return emitError(loc) << "LLVM attribute '" << key
12850a2131b7SAlex Zinenko                           << "' does not expect a value, found '" << value
12860a2131b7SAlex Zinenko                           << "'";
12870a2131b7SAlex Zinenko 
12880a2131b7SAlex Zinenko   llvmFunc->addFnAttr(kind);
12890a2131b7SAlex Zinenko   return success();
12900a2131b7SAlex Zinenko }
12910a2131b7SAlex Zinenko 
12926d2bbba1SVictor Perez /// Return a representation of `value` as metadata.
12936d2bbba1SVictor Perez static llvm::Metadata *convertIntegerToMetadata(llvm::LLVMContext &context,
12946d2bbba1SVictor Perez                                                 const llvm::APInt &value) {
12956d2bbba1SVictor Perez   llvm::Constant *constant = llvm::ConstantInt::get(context, value);
12966d2bbba1SVictor Perez   return llvm::ConstantAsMetadata::get(constant);
12976d2bbba1SVictor Perez }
12986d2bbba1SVictor Perez 
12996d2bbba1SVictor Perez /// Return a representation of `value` as an MDNode.
13006d2bbba1SVictor Perez static llvm::MDNode *convertIntegerToMDNode(llvm::LLVMContext &context,
13016d2bbba1SVictor Perez                                             const llvm::APInt &value) {
13026d2bbba1SVictor Perez   return llvm::MDNode::get(context, convertIntegerToMetadata(context, value));
13036d2bbba1SVictor Perez }
13046d2bbba1SVictor Perez 
13056d2bbba1SVictor Perez /// Return an MDNode encoding `vec_type_hint` metadata.
13066d2bbba1SVictor Perez static llvm::MDNode *convertVecTypeHintToMDNode(llvm::LLVMContext &context,
13076d2bbba1SVictor Perez                                                 llvm::Type *type,
13086d2bbba1SVictor Perez                                                 bool isSigned) {
13096d2bbba1SVictor Perez   llvm::Metadata *typeMD =
13106d2bbba1SVictor Perez       llvm::ConstantAsMetadata::get(llvm::UndefValue::get(type));
13116d2bbba1SVictor Perez   llvm::Metadata *isSignedMD =
13126d2bbba1SVictor Perez       convertIntegerToMetadata(context, llvm::APInt(32, isSigned ? 1 : 0));
13136d2bbba1SVictor Perez   return llvm::MDNode::get(context, {typeMD, isSignedMD});
13146d2bbba1SVictor Perez }
13156d2bbba1SVictor Perez 
13166d2bbba1SVictor Perez /// Return an MDNode with a tuple given by the values in `values`.
13176d2bbba1SVictor Perez static llvm::MDNode *convertIntegerArrayToMDNode(llvm::LLVMContext &context,
13186d2bbba1SVictor Perez                                                  ArrayRef<int32_t> values) {
13196d2bbba1SVictor Perez   SmallVector<llvm::Metadata *> mdValues;
13206d2bbba1SVictor Perez   llvm::transform(
13216d2bbba1SVictor Perez       values, std::back_inserter(mdValues), [&context](int32_t value) {
13226d2bbba1SVictor Perez         return convertIntegerToMetadata(context, llvm::APInt(32, value));
13236d2bbba1SVictor Perez       });
13246d2bbba1SVictor Perez   return llvm::MDNode::get(context, mdValues);
13256d2bbba1SVictor Perez }
13266d2bbba1SVictor Perez 
13270a2131b7SAlex Zinenko /// Attaches the attributes listed in the given array attribute to `llvmFunc`.
13280a2131b7SAlex Zinenko /// Reports error to `loc` if any and returns immediately. Expects `attributes`
13290a2131b7SAlex Zinenko /// to be an array attribute containing either string attributes, treated as
13300a2131b7SAlex Zinenko /// value-less LLVM attributes, or array attributes containing two string
13310a2131b7SAlex Zinenko /// attributes, with the first string being the name of the corresponding LLVM
13320a2131b7SAlex Zinenko /// attribute and the second string beings its value. Note that even integer
13330a2131b7SAlex Zinenko /// attributes are expected to have their values expressed as strings.
13340a2131b7SAlex Zinenko static LogicalResult
133522426110SRamkumar Ramachandra forwardPassthroughAttributes(Location loc, std::optional<ArrayAttr> attributes,
13360a2131b7SAlex Zinenko                              llvm::Function *llvmFunc) {
13370a2131b7SAlex Zinenko   if (!attributes)
13380a2131b7SAlex Zinenko     return success();
13390a2131b7SAlex Zinenko 
13400a2131b7SAlex Zinenko   for (Attribute attr : *attributes) {
13415550c821STres Popp     if (auto stringAttr = dyn_cast<StringAttr>(attr)) {
13420a2131b7SAlex Zinenko       if (failed(
13430a2131b7SAlex Zinenko               checkedAddLLVMFnAttribute(loc, llvmFunc, stringAttr.getValue())))
13440a2131b7SAlex Zinenko         return failure();
13450a2131b7SAlex Zinenko       continue;
13460a2131b7SAlex Zinenko     }
13470a2131b7SAlex Zinenko 
13485550c821STres Popp     auto arrayAttr = dyn_cast<ArrayAttr>(attr);
13490a2131b7SAlex Zinenko     if (!arrayAttr || arrayAttr.size() != 2)
13500a2131b7SAlex Zinenko       return emitError(loc)
13510a2131b7SAlex Zinenko              << "expected 'passthrough' to contain string or array attributes";
13520a2131b7SAlex Zinenko 
13535550c821STres Popp     auto keyAttr = dyn_cast<StringAttr>(arrayAttr[0]);
13545550c821STres Popp     auto valueAttr = dyn_cast<StringAttr>(arrayAttr[1]);
13550a2131b7SAlex Zinenko     if (!keyAttr || !valueAttr)
13560a2131b7SAlex Zinenko       return emitError(loc)
13570a2131b7SAlex Zinenko              << "expected arrays within 'passthrough' to contain two strings";
13580a2131b7SAlex Zinenko 
13590a2131b7SAlex Zinenko     if (failed(checkedAddLLVMFnAttribute(loc, llvmFunc, keyAttr.getValue(),
13600a2131b7SAlex Zinenko                                          valueAttr.getValue())))
13610a2131b7SAlex Zinenko       return failure();
13620a2131b7SAlex Zinenko   }
13630a2131b7SAlex Zinenko   return success();
13640a2131b7SAlex Zinenko }
13650a2131b7SAlex Zinenko 
13665e7959a3SAlex Zinenko LogicalResult ModuleTranslation::convertOneFunction(LLVMFuncOp func) {
1367db884dafSAlex Zinenko   // Clear the block, branch value mappings, they are only relevant within one
13685d7231d8SStephan Herhut   // function.
13695d7231d8SStephan Herhut   blockMapping.clear();
13705d7231d8SStephan Herhut   valueMapping.clear();
1371db884dafSAlex Zinenko   branchMapping.clear();
13720881a4f1SAlex Zinenko   llvm::Function *llvmFunc = lookupFunction(func.getName());
1373c33d6970SRiver Riddle 
13745d7231d8SStephan Herhut   // Add function arguments to the value remapping table.
1375473d0011SSlava Zakharin   for (auto [mlirArg, llvmArg] :
1376473d0011SSlava Zakharin        llvm::zip(func.getArguments(), llvmFunc->args()))
13770881a4f1SAlex Zinenko     mapValue(mlirArg, &llvmArg);
13785d7231d8SStephan Herhut 
1379ff77397fSShraiysh Vaishay   // Check the personality and set it.
1380037f0995SKazu Hirata   if (func.getPersonality()) {
13817b9d73c2SPaulo Matos     llvm::Type *ty = llvm::PointerType::getUnqual(llvmFunc->getContext());
1382dde96363SJacques Pienaar     if (llvm::Constant *pfunc = getLLVMConstant(ty, func.getPersonalityAttr(),
1383dde96363SJacques Pienaar                                                 func.getLoc(), *this))
1384ff77397fSShraiysh Vaishay       llvmFunc->setPersonalityFn(pfunc);
1385ff77397fSShraiysh Vaishay   }
1386ff77397fSShraiysh Vaishay 
1387bc609640SChristian Ulmann   if (std::optional<StringRef> section = func.getSection())
1388bc609640SChristian Ulmann     llvmFunc->setSection(*section);
1389bc609640SChristian Ulmann 
13900a0aff2dSMikhail Goncharov   if (func.getArmStreaming())
13917d465909SCullen Rhodes     llvmFunc->addFnAttr("aarch64_pstate_sm_enabled");
13920a0aff2dSMikhail Goncharov   else if (func.getArmLocallyStreaming())
13937d465909SCullen Rhodes     llvmFunc->addFnAttr("aarch64_pstate_sm_body");
139479524ba5STom Eccles   else if (func.getArmStreamingCompatible())
139579524ba5STom Eccles     llvmFunc->addFnAttr("aarch64_pstate_sm_compatible");
13967d465909SCullen Rhodes 
1397783ac3b6SBenjamin Maxwell   if (func.getArmNewZa())
1398d313614bSSander de Smalen     llvmFunc->addFnAttr("aarch64_new_za");
1399d313614bSSander de Smalen   else if (func.getArmInZa())
1400d313614bSSander de Smalen     llvmFunc->addFnAttr("aarch64_in_za");
1401d313614bSSander de Smalen   else if (func.getArmOutZa())
1402d313614bSSander de Smalen     llvmFunc->addFnAttr("aarch64_out_za");
1403d313614bSSander de Smalen   else if (func.getArmInoutZa())
1404d313614bSSander de Smalen     llvmFunc->addFnAttr("aarch64_inout_za");
1405d313614bSSander de Smalen   else if (func.getArmPreservesZa())
1406d313614bSSander de Smalen     llvmFunc->addFnAttr("aarch64_preserves_za");
1407783ac3b6SBenjamin Maxwell 
14088fb685fbSSergio Afonso   if (auto targetCpu = func.getTargetCpu())
14098fb685fbSSergio Afonso     llvmFunc->addFnAttr("target-cpu", *targetCpu);
14108fb685fbSSergio Afonso 
1411f1d3fe7aSAlexis Perry-Holby   if (auto tuneCpu = func.getTuneCpu())
1412f1d3fe7aSAlexis Perry-Holby     llvmFunc->addFnAttr("tune-cpu", *tuneCpu);
1413f1d3fe7aSAlexis Perry-Holby 
141417de468dSBenjamin Maxwell   if (auto targetFeatures = func.getTargetFeatures())
141517de468dSBenjamin Maxwell     llvmFunc->addFnAttr("target-features", targetFeatures->getFeaturesString());
141617de468dSBenjamin Maxwell 
14175bfd5c60SMats Petersson   if (auto attr = func.getVscaleRange())
14185bfd5c60SMats Petersson     llvmFunc->addFnAttr(llvm::Attribute::getWithVScaleRangeArgs(
14195bfd5c60SMats Petersson         getLLVMContext(), attr->getMinRange().getInt(),
14205bfd5c60SMats Petersson         attr->getMaxRange().getInt()));
14215bfd5c60SMats Petersson 
1422748c2959SAlex Bradbury   if (auto unsafeFpMath = func.getUnsafeFpMath())
1423748c2959SAlex Bradbury     llvmFunc->addFnAttr("unsafe-fp-math", llvm::toStringRef(*unsafeFpMath));
1424748c2959SAlex Bradbury 
1425748c2959SAlex Bradbury   if (auto noInfsFpMath = func.getNoInfsFpMath())
1426748c2959SAlex Bradbury     llvmFunc->addFnAttr("no-infs-fp-math", llvm::toStringRef(*noInfsFpMath));
1427748c2959SAlex Bradbury 
1428748c2959SAlex Bradbury   if (auto noNansFpMath = func.getNoNansFpMath())
1429748c2959SAlex Bradbury     llvmFunc->addFnAttr("no-nans-fp-math", llvm::toStringRef(*noNansFpMath));
1430748c2959SAlex Bradbury 
1431748c2959SAlex Bradbury   if (auto approxFuncFpMath = func.getApproxFuncFpMath())
1432748c2959SAlex Bradbury     llvmFunc->addFnAttr("approx-func-fp-math",
1433748c2959SAlex Bradbury                         llvm::toStringRef(*approxFuncFpMath));
1434748c2959SAlex Bradbury 
1435748c2959SAlex Bradbury   if (auto noSignedZerosFpMath = func.getNoSignedZerosFpMath())
1436748c2959SAlex Bradbury     llvmFunc->addFnAttr("no-signed-zeros-fp-math",
1437748c2959SAlex Bradbury                         llvm::toStringRef(*noSignedZerosFpMath));
1438748c2959SAlex Bradbury 
1439e5865ec9Srunseny   if (auto denormalFpMath = func.getDenormalFpMath())
1440e5865ec9Srunseny     llvmFunc->addFnAttr("denormal-fp-math", *denormalFpMath);
1441e5865ec9Srunseny 
1442e5865ec9Srunseny   if (auto denormalFpMathF32 = func.getDenormalFpMathF32())
1443e5865ec9Srunseny     llvmFunc->addFnAttr("denormal-fp-math-f32", *denormalFpMathF32);
1444e5865ec9Srunseny 
1445e5865ec9Srunseny   if (auto fpContract = func.getFpContract())
1446e5865ec9Srunseny     llvmFunc->addFnAttr("fp-contract", *fpContract);
1447e5865ec9Srunseny 
14483257e4caSRadu Salavat   // Add function attribute frame-pointer, if found.
14493257e4caSRadu Salavat   if (FramePointerKindAttr attr = func.getFramePointerAttr())
14503257e4caSRadu Salavat     llvmFunc->addFnAttr("frame-pointer",
14513257e4caSRadu Salavat                         LLVM::framePointerKind::stringifyFramePointerKind(
14523257e4caSRadu Salavat                             (attr.getFramePointerKind())));
14533257e4caSRadu Salavat 
14545d7231d8SStephan Herhut   // First, create all blocks so we can jump to them.
14555d7231d8SStephan Herhut   llvm::LLVMContext &llvmContext = llvmFunc->getContext();
14565d7231d8SStephan Herhut   for (auto &bb : func) {
14575d7231d8SStephan Herhut     auto *llvmBB = llvm::BasicBlock::Create(llvmContext);
14585d7231d8SStephan Herhut     llvmBB->insertInto(llvmFunc);
14590881a4f1SAlex Zinenko     mapBlock(&bb, llvmBB);
14605d7231d8SStephan Herhut   }
14615d7231d8SStephan Herhut 
14625d7231d8SStephan Herhut   // Then, convert blocks one by one in topological order to ensure defs are
14635d7231d8SStephan Herhut   // converted before uses.
1464e919df57SChristian Ulmann   auto blocks = getBlocksSortedByDominance(func.getBody());
146510164a2eSAlex Zinenko   for (Block *bb : blocks) {
14669519e3ecSOleksandr "Alex" Zinenko     CapturingIRBuilder builder(llvmContext);
14679519e3ecSOleksandr "Alex" Zinenko     if (failed(convertBlockImpl(*bb, bb->isEntryBlock(), builder,
14689519e3ecSOleksandr "Alex" Zinenko                                 /*recordInsertions=*/true)))
1469baa1ec22SAlex Zinenko       return failure();
14705d7231d8SStephan Herhut   }
14715d7231d8SStephan Herhut 
1472176379e0SAlex Zinenko   // After all blocks have been traversed and values mapped, connect the PHI
1473176379e0SAlex Zinenko   // nodes to the results of preceding blocks.
147466900b3eSAlex Zinenko   detail::connectPHINodes(func.getBody(), *this);
1475176379e0SAlex Zinenko 
1476176379e0SAlex Zinenko   // Finally, convert dialect attributes attached to the function.
14779519e3ecSOleksandr "Alex" Zinenko   return convertDialectAttributes(func, {});
1478176379e0SAlex Zinenko }
1479176379e0SAlex Zinenko 
14809519e3ecSOleksandr "Alex" Zinenko LogicalResult ModuleTranslation::convertDialectAttributes(
14819519e3ecSOleksandr "Alex" Zinenko     Operation *op, ArrayRef<llvm::Instruction *> instructions) {
1482176379e0SAlex Zinenko   for (NamedAttribute attribute : op->getDialectAttrs())
14839519e3ecSOleksandr "Alex" Zinenko     if (failed(iface.amendOperation(op, instructions, attribute, *this)))
1484176379e0SAlex Zinenko       return failure();
1485baa1ec22SAlex Zinenko   return success();
14865d7231d8SStephan Herhut }
14875d7231d8SStephan Herhut 
1488c012e487SJohannes de Fine Licht /// Converts memory effect attributes from `func` and attaches them to
1489c012e487SJohannes de Fine Licht /// `llvmFunc`.
1490c012e487SJohannes de Fine Licht static void convertFunctionMemoryAttributes(LLVMFuncOp func,
14919b9cfe77SChristian Ulmann                                             llvm::Function *llvmFunc) {
14922eea9d6aSFinlay   if (!func.getMemoryEffects())
14939b9cfe77SChristian Ulmann     return;
14949b9cfe77SChristian Ulmann 
14952eea9d6aSFinlay   MemoryEffectsAttr memEffects = func.getMemoryEffectsAttr();
14969b9cfe77SChristian Ulmann 
14979b9cfe77SChristian Ulmann   // Add memory effects incrementally.
14989b9cfe77SChristian Ulmann   llvm::MemoryEffects newMemEffects =
14999b9cfe77SChristian Ulmann       llvm::MemoryEffects(llvm::MemoryEffects::Location::ArgMem,
15009b9cfe77SChristian Ulmann                           convertModRefInfoToLLVM(memEffects.getArgMem()));
15019b9cfe77SChristian Ulmann   newMemEffects |= llvm::MemoryEffects(
15029b9cfe77SChristian Ulmann       llvm::MemoryEffects::Location::InaccessibleMem,
15039b9cfe77SChristian Ulmann       convertModRefInfoToLLVM(memEffects.getInaccessibleMem()));
15049b9cfe77SChristian Ulmann   newMemEffects |=
15059b9cfe77SChristian Ulmann       llvm::MemoryEffects(llvm::MemoryEffects::Location::Other,
15069b9cfe77SChristian Ulmann                           convertModRefInfoToLLVM(memEffects.getOther()));
15079b9cfe77SChristian Ulmann   llvmFunc->setMemoryEffects(newMemEffects);
15089b9cfe77SChristian Ulmann }
15099b9cfe77SChristian Ulmann 
1510c012e487SJohannes de Fine Licht /// Converts function attributes from `func` and attaches them to `llvmFunc`.
1511c012e487SJohannes de Fine Licht static void convertFunctionAttributes(LLVMFuncOp func,
1512c012e487SJohannes de Fine Licht                                       llvm::Function *llvmFunc) {
1513c012e487SJohannes de Fine Licht   if (func.getNoInlineAttr())
1514c012e487SJohannes de Fine Licht     llvmFunc->addFnAttr(llvm::Attribute::NoInline);
1515c012e487SJohannes de Fine Licht   if (func.getAlwaysInlineAttr())
1516c012e487SJohannes de Fine Licht     llvmFunc->addFnAttr(llvm::Attribute::AlwaysInline);
1517c012e487SJohannes de Fine Licht   if (func.getOptimizeNoneAttr())
1518c012e487SJohannes de Fine Licht     llvmFunc->addFnAttr(llvm::Attribute::OptimizeNone);
1519d6df0187SFinlay   if (func.getConvergentAttr())
1520d6df0187SFinlay     llvmFunc->addFnAttr(llvm::Attribute::Convergent);
1521aa21ee79SFinlay   if (func.getNoUnwindAttr())
1522aa21ee79SFinlay     llvmFunc->addFnAttr(llvm::Attribute::NoUnwind);
1523aa21ee79SFinlay   if (func.getWillReturnAttr())
1524aa21ee79SFinlay     llvmFunc->addFnAttr(llvm::Attribute::WillReturn);
1525c012e487SJohannes de Fine Licht   convertFunctionMemoryAttributes(func, llvmFunc);
1526c012e487SJohannes de Fine Licht }
1527c012e487SJohannes de Fine Licht 
15286d2bbba1SVictor Perez /// Converts function attributes from `func` and attaches them to `llvmFunc`.
15296d2bbba1SVictor Perez static void convertFunctionKernelAttributes(LLVMFuncOp func,
15306d2bbba1SVictor Perez                                             llvm::Function *llvmFunc,
15316d2bbba1SVictor Perez                                             ModuleTranslation &translation) {
15326d2bbba1SVictor Perez   llvm::LLVMContext &llvmContext = llvmFunc->getContext();
15336d2bbba1SVictor Perez 
15346d2bbba1SVictor Perez   if (VecTypeHintAttr vecTypeHint = func.getVecTypeHintAttr()) {
15356d2bbba1SVictor Perez     Type type = vecTypeHint.getHint().getValue();
15366d2bbba1SVictor Perez     llvm::Type *llvmType = translation.convertType(type);
15376d2bbba1SVictor Perez     bool isSigned = vecTypeHint.getIsSigned();
15386d2bbba1SVictor Perez     llvmFunc->setMetadata(
15396d2bbba1SVictor Perez         func.getVecTypeHintAttrName(),
15406d2bbba1SVictor Perez         convertVecTypeHintToMDNode(llvmContext, llvmType, isSigned));
15416d2bbba1SVictor Perez   }
15426d2bbba1SVictor Perez 
15436d2bbba1SVictor Perez   if (std::optional<ArrayRef<int32_t>> workGroupSizeHint =
15446d2bbba1SVictor Perez           func.getWorkGroupSizeHint()) {
15456d2bbba1SVictor Perez     llvmFunc->setMetadata(
15466d2bbba1SVictor Perez         func.getWorkGroupSizeHintAttrName(),
15476d2bbba1SVictor Perez         convertIntegerArrayToMDNode(llvmContext, *workGroupSizeHint));
15486d2bbba1SVictor Perez   }
15496d2bbba1SVictor Perez 
15506d2bbba1SVictor Perez   if (std::optional<ArrayRef<int32_t>> reqdWorkGroupSize =
15516d2bbba1SVictor Perez           func.getReqdWorkGroupSize()) {
15526d2bbba1SVictor Perez     llvmFunc->setMetadata(
15536d2bbba1SVictor Perez         func.getReqdWorkGroupSizeAttrName(),
15546d2bbba1SVictor Perez         convertIntegerArrayToMDNode(llvmContext, *reqdWorkGroupSize));
15556d2bbba1SVictor Perez   }
15566d2bbba1SVictor Perez 
15576d2bbba1SVictor Perez   if (std::optional<uint32_t> intelReqdSubGroupSize =
15586d2bbba1SVictor Perez           func.getIntelReqdSubGroupSize()) {
15596d2bbba1SVictor Perez     llvmFunc->setMetadata(
15606d2bbba1SVictor Perez         func.getIntelReqdSubGroupSizeAttrName(),
15616d2bbba1SVictor Perez         convertIntegerToMDNode(llvmContext,
15626d2bbba1SVictor Perez                                llvm::APInt(32, *intelReqdSubGroupSize)));
15636d2bbba1SVictor Perez   }
15646d2bbba1SVictor Perez }
15656d2bbba1SVictor Perez 
1566fa6850a9SRishi Surendran FailureOr<llvm::AttrBuilder>
1567fa6850a9SRishi Surendran ModuleTranslation::convertParameterAttrs(LLVMFuncOp func, int argIdx,
1568fa6850a9SRishi Surendran                                          DictionaryAttr paramAttrs) {
1569be4b8735SChristian Ulmann   llvm::AttrBuilder attrBuilder(llvmModule->getContext());
1570fa6850a9SRishi Surendran   auto attrNameToKindMapping = getAttrNameToKindMapping();
1571be4b8735SChristian Ulmann 
1572fa6850a9SRishi Surendran   for (auto namedAttr : paramAttrs) {
1573fa6850a9SRishi Surendran     auto it = attrNameToKindMapping.find(namedAttr.getName());
1574fa6850a9SRishi Surendran     if (it != attrNameToKindMapping.end()) {
1575fa6850a9SRishi Surendran       llvm::Attribute::AttrKind llvmKind = it->second;
1576be4b8735SChristian Ulmann 
1577fa6850a9SRishi Surendran       llvm::TypeSwitch<Attribute>(namedAttr.getValue())
157852120584SChristian Ulmann           .Case<TypeAttr>([&](auto typeAttr) {
1579fa6850a9SRishi Surendran             attrBuilder.addTypeAttr(llvmKind, convertType(typeAttr.getValue()));
158052120584SChristian Ulmann           })
158152120584SChristian Ulmann           .Case<IntegerAttr>([&](auto intAttr) {
1582fa6850a9SRishi Surendran             attrBuilder.addRawIntAttr(llvmKind, intAttr.getInt());
158352120584SChristian Ulmann           })
158492a15dd7SKrzysztof Drewniak           .Case<UnitAttr>([&](auto) { attrBuilder.addAttribute(llvmKind); })
158592a15dd7SKrzysztof Drewniak           .Case<LLVM::ConstantRangeAttr>([&](auto rangeAttr) {
158692a15dd7SKrzysztof Drewniak             attrBuilder.addConstantRangeAttr(
158792a15dd7SKrzysztof Drewniak                 llvmKind, llvm::ConstantRange(rangeAttr.getLower(),
158892a15dd7SKrzysztof Drewniak                                               rangeAttr.getUpper()));
158992a15dd7SKrzysztof Drewniak           });
1590fa6850a9SRishi Surendran     } else if (namedAttr.getNameDialect()) {
1591fa6850a9SRishi Surendran       if (failed(iface.convertParameterAttr(func, argIdx, namedAttr, *this)))
1592fa6850a9SRishi Surendran         return failure();
1593fa6850a9SRishi Surendran     }
159452120584SChristian Ulmann   }
1595be4b8735SChristian Ulmann 
1596be4b8735SChristian Ulmann   return attrBuilder;
1597be4b8735SChristian Ulmann }
1598be4b8735SChristian Ulmann 
1599a084b94fSSean Silva LogicalResult ModuleTranslation::convertFunctionSignatures() {
16005d7231d8SStephan Herhut   // Declare all functions first because there may be function calls that form a
1601a084b94fSSean Silva   // call graph with cycles, or global initializers that reference functions.
160244fc7d72STres Popp   for (auto function : getModuleBody(mlirModule).getOps<LLVMFuncOp>()) {
16035e7959a3SAlex Zinenko     llvm::FunctionCallee llvmFuncCst = llvmModule->getOrInsertFunction(
16045e7959a3SAlex Zinenko         function.getName(),
16054a3460a7SRiver Riddle         cast<llvm::FunctionType>(convertType(function.getFunctionType())));
16060a2131b7SAlex Zinenko     llvm::Function *llvmFunc = cast<llvm::Function>(llvmFuncCst.getCallee());
1607dde96363SJacques Pienaar     llvmFunc->setLinkage(convertLinkageToLLVM(function.getLinkage()));
160837c750a5SHendrik Greving     llvmFunc->setCallingConv(convertCConvToLLVM(function.getCConv()));
16090881a4f1SAlex Zinenko     mapFunction(function.getName(), llvmFunc);
1610dde96363SJacques Pienaar     addRuntimePreemptionSpecifier(function.getDsoLocal(), llvmFunc);
16110a2131b7SAlex Zinenko 
161229016d28SSlava Zakharin     // Convert function attributes.
16139b9cfe77SChristian Ulmann     convertFunctionAttributes(function, llvmFunc);
161413cb085cSSlava Zakharin 
16156d2bbba1SVictor Perez     // Convert function kernel attributes to metadata.
16166d2bbba1SVictor Perez     convertFunctionKernelAttributes(function, llvmFunc, *this);
16176d2bbba1SVictor Perez 
1618b72dd6f7SChristian Ulmann     // Convert function_entry_count attribute to metadata.
1619b72dd6f7SChristian Ulmann     if (std::optional<uint64_t> entryCount = function.getFunctionEntryCount())
1620b72dd6f7SChristian Ulmann       llvmFunc->setEntryCount(entryCount.value());
1621b72dd6f7SChristian Ulmann 
162229016d28SSlava Zakharin     // Convert result attributes.
162329016d28SSlava Zakharin     if (ArrayAttr allResultAttrs = function.getAllResultAttrs()) {
16245550c821STres Popp       DictionaryAttr resultAttrs = cast<DictionaryAttr>(allResultAttrs[0]);
1625fa6850a9SRishi Surendran       FailureOr<llvm::AttrBuilder> attrBuilder =
1626fa6850a9SRishi Surendran           convertParameterAttrs(function, -1, resultAttrs);
1627fa6850a9SRishi Surendran       if (failed(attrBuilder))
1628fa6850a9SRishi Surendran         return failure();
1629fa6850a9SRishi Surendran       llvmFunc->addRetAttrs(*attrBuilder);
163029016d28SSlava Zakharin     }
163129016d28SSlava Zakharin 
1632473d0011SSlava Zakharin     // Convert argument attributes.
1633be4b8735SChristian Ulmann     for (auto [argIdx, llvmArg] : llvm::enumerate(llvmFunc->args())) {
1634be4b8735SChristian Ulmann       if (DictionaryAttr argAttrs = function.getArgAttrDict(argIdx)) {
1635fa6850a9SRishi Surendran         FailureOr<llvm::AttrBuilder> attrBuilder =
1636fa6850a9SRishi Surendran             convertParameterAttrs(function, argIdx, argAttrs);
1637fa6850a9SRishi Surendran         if (failed(attrBuilder))
1638fa6850a9SRishi Surendran           return failure();
1639fa6850a9SRishi Surendran         llvmArg.addAttrs(*attrBuilder);
1640473d0011SSlava Zakharin       }
1641473d0011SSlava Zakharin     }
1642473d0011SSlava Zakharin 
16430a2131b7SAlex Zinenko     // Forward the pass-through attributes to LLVM.
1644dde96363SJacques Pienaar     if (failed(forwardPassthroughAttributes(
1645dde96363SJacques Pienaar             function.getLoc(), function.getPassthrough(), llvmFunc)))
16460a2131b7SAlex Zinenko       return failure();
16476628767eSChristian Ulmann 
16486628767eSChristian Ulmann     // Convert visibility attribute.
16496628767eSChristian Ulmann     llvmFunc->setVisibility(convertVisibilityToLLVM(function.getVisibility_()));
1650b126ee65STobias Gysi 
1651b126ee65STobias Gysi     // Convert the comdat attribute.
1652b126ee65STobias Gysi     if (std::optional<mlir::SymbolRefAttr> comdat = function.getComdat()) {
1653b126ee65STobias Gysi       auto selectorOp = cast<ComdatSelectorOp>(
1654b126ee65STobias Gysi           SymbolTable::lookupNearestSymbolFrom(function, *comdat));
1655b126ee65STobias Gysi       llvmFunc->setComdat(comdatMapping.lookup(selectorOp));
1656b126ee65STobias Gysi     }
1657a3e48ad9SChristian Ulmann 
1658a3e48ad9SChristian Ulmann     if (auto gc = function.getGarbageCollector())
1659a3e48ad9SChristian Ulmann       llvmFunc->setGC(gc->str());
166010417b13SChristian Ulmann 
166110417b13SChristian Ulmann     if (auto unnamedAddr = function.getUnnamedAddr())
166210417b13SChristian Ulmann       llvmFunc->setUnnamedAddr(convertUnnamedAddrToLLVM(*unnamedAddr));
1663c55a8861SChristian Ulmann 
1664c55a8861SChristian Ulmann     if (auto alignment = function.getAlignment())
1665c55a8861SChristian Ulmann       llvmFunc->setAlignment(llvm::MaybeAlign(*alignment));
1666fa5255eeSChristian Ulmann 
1667fa5255eeSChristian Ulmann     // Translate the debug information for this function.
1668fa5255eeSChristian Ulmann     debugTranslation->translate(function, *llvmFunc);
16695d7231d8SStephan Herhut   }
16705d7231d8SStephan Herhut 
1671a084b94fSSean Silva   return success();
1672a084b94fSSean Silva }
1673a084b94fSSean Silva 
1674a084b94fSSean Silva LogicalResult ModuleTranslation::convertFunctions() {
16755d7231d8SStephan Herhut   // Convert functions.
167644fc7d72STres Popp   for (auto function : getModuleBody(mlirModule).getOps<LLVMFuncOp>()) {
16772ef7e208SSergio Afonso     // Do not convert external functions, but do process dialect attributes
16782ef7e208SSergio Afonso     // attached to them.
16792ef7e208SSergio Afonso     if (function.isExternal()) {
16809519e3ecSOleksandr "Alex" Zinenko       if (failed(convertDialectAttributes(function, {})))
16812ef7e208SSergio Afonso         return failure();
16825d7231d8SStephan Herhut       continue;
16832ef7e208SSergio Afonso     }
16845d7231d8SStephan Herhut 
1685baa1ec22SAlex Zinenko     if (failed(convertOneFunction(function)))
1686baa1ec22SAlex Zinenko       return failure();
16875d7231d8SStephan Herhut   }
16885d7231d8SStephan Herhut 
1689baa1ec22SAlex Zinenko   return success();
16905d7231d8SStephan Herhut }
16915d7231d8SStephan Herhut 
16929d4c1be8SDavid Truby LogicalResult ModuleTranslation::convertComdats() {
1693b126ee65STobias Gysi   for (auto comdatOp : getModuleBody(mlirModule).getOps<ComdatOp>()) {
1694b126ee65STobias Gysi     for (auto selectorOp : comdatOp.getOps<ComdatSelectorOp>()) {
16959d4c1be8SDavid Truby       llvm::Module *module = getLLVMModule();
1696b126ee65STobias Gysi       if (module->getComdatSymbolTable().contains(selectorOp.getSymName()))
1697b126ee65STobias Gysi         return emitError(selectorOp.getLoc())
16989d4c1be8SDavid Truby                << "comdat selection symbols must be unique even in different "
16999d4c1be8SDavid Truby                   "comdat regions";
1700b126ee65STobias Gysi       llvm::Comdat *comdat = module->getOrInsertComdat(selectorOp.getSymName());
1701b126ee65STobias Gysi       comdat->setSelectionKind(convertComdatToLLVM(selectorOp.getComdat()));
1702b126ee65STobias Gysi       comdatMapping.try_emplace(selectorOp, comdat);
17039d4c1be8SDavid Truby     }
17049d4c1be8SDavid Truby   }
17059d4c1be8SDavid Truby   return success();
17069d4c1be8SDavid Truby }
17079d4c1be8SDavid Truby 
17082ea6bb64STobias Gysi void ModuleTranslation::setAccessGroupsMetadata(AccessGroupOpInterface op,
17094e393350SArpith C. Jacob                                                 llvm::Instruction *inst) {
17102ea6bb64STobias Gysi   if (llvm::MDNode *node = loopAnnotationTranslation->getAccessGroups(op))
1711fef08da4STobias Gysi     inst->setMetadata(llvm::LLVMContext::MD_access_group, node);
17124e393350SArpith C. Jacob }
17134e393350SArpith C. Jacob 
1714d25e91d7STyler Augustine llvm::MDNode *
17155f230ed7STobias Gysi ModuleTranslation::getOrCreateAliasScope(AliasScopeAttr aliasScopeAttr) {
17165f230ed7STobias Gysi   auto [scopeIt, scopeInserted] =
17175f230ed7STobias Gysi       aliasScopeMetadataMapping.try_emplace(aliasScopeAttr, nullptr);
17185f230ed7STobias Gysi   if (!scopeInserted)
17195f230ed7STobias Gysi     return scopeIt->second;
17205f230ed7STobias Gysi   llvm::LLVMContext &ctx = llvmModule->getContext();
1721e39e30e9STobias Gysi   auto dummy = llvm::MDNode::getTemporary(ctx, std::nullopt);
17225f230ed7STobias Gysi   // Convert the domain metadata node if necessary.
17235f230ed7STobias Gysi   auto [domainIt, insertedDomain] = aliasDomainMetadataMapping.try_emplace(
17245f230ed7STobias Gysi       aliasScopeAttr.getDomain(), nullptr);
17255f230ed7STobias Gysi   if (insertedDomain) {
17265f230ed7STobias Gysi     llvm::SmallVector<llvm::Metadata *, 2> operands;
1727*1c067a51SWilliam Moses     // Placeholder for potential self-reference.
1728e39e30e9STobias Gysi     operands.push_back(dummy.get());
17295f230ed7STobias Gysi     if (StringAttr description = aliasScopeAttr.getDomain().getDescription())
17305f230ed7STobias Gysi       operands.push_back(llvm::MDString::get(ctx, description));
17315f230ed7STobias Gysi     domainIt->second = llvm::MDNode::get(ctx, operands);
17325f230ed7STobias Gysi     // Self-reference for uniqueness.
1733*1c067a51SWilliam Moses     llvm::Metadata *replacement;
1734*1c067a51SWilliam Moses     if (auto stringAttr =
1735*1c067a51SWilliam Moses             dyn_cast<StringAttr>(aliasScopeAttr.getDomain().getId()))
1736*1c067a51SWilliam Moses       replacement = llvm::MDString::get(ctx, stringAttr.getValue());
1737*1c067a51SWilliam Moses     else
1738*1c067a51SWilliam Moses       replacement = domainIt->second;
1739*1c067a51SWilliam Moses     domainIt->second->replaceOperandWith(0, replacement);
17405f230ed7STobias Gysi   }
17415f230ed7STobias Gysi   // Convert the scope metadata node.
17425f230ed7STobias Gysi   assert(domainIt->second && "Scope's domain should already be valid");
17435f230ed7STobias Gysi   llvm::SmallVector<llvm::Metadata *, 3> operands;
1744*1c067a51SWilliam Moses   // Placeholder for potential self-reference.
1745e39e30e9STobias Gysi   operands.push_back(dummy.get());
17465f230ed7STobias Gysi   operands.push_back(domainIt->second);
17475f230ed7STobias Gysi   if (StringAttr description = aliasScopeAttr.getDescription())
17485f230ed7STobias Gysi     operands.push_back(llvm::MDString::get(ctx, description));
17495f230ed7STobias Gysi   scopeIt->second = llvm::MDNode::get(ctx, operands);
17505f230ed7STobias Gysi   // Self-reference for uniqueness.
1751*1c067a51SWilliam Moses   llvm::Metadata *replacement;
1752*1c067a51SWilliam Moses   if (auto stringAttr = dyn_cast<StringAttr>(aliasScopeAttr.getId()))
1753*1c067a51SWilliam Moses     replacement = llvm::MDString::get(ctx, stringAttr.getValue());
1754*1c067a51SWilliam Moses   else
1755*1c067a51SWilliam Moses     replacement = scopeIt->second;
1756*1c067a51SWilliam Moses   scopeIt->second->replaceOperandWith(0, replacement);
17575f230ed7STobias Gysi   return scopeIt->second;
1758d25e91d7STyler Augustine }
1759d25e91d7STyler Augustine 
17605f230ed7STobias Gysi llvm::MDNode *ModuleTranslation::getOrCreateAliasScopes(
17615f230ed7STobias Gysi     ArrayRef<AliasScopeAttr> aliasScopeAttrs) {
176256d94a90STobias Gysi   SmallVector<llvm::Metadata *> nodes;
176378d00a16SMarkus Böck   nodes.reserve(aliasScopeAttrs.size());
17640fc8d9e4STobias Gysi   for (AliasScopeAttr aliasScopeAttr : aliasScopeAttrs)
17655f230ed7STobias Gysi     nodes.push_back(getOrCreateAliasScope(aliasScopeAttr));
176656d94a90STobias Gysi   return llvm::MDNode::get(getLLVMContext(), nodes);
176756d94a90STobias Gysi }
176856d94a90STobias Gysi 
17692ea6bb64STobias Gysi void ModuleTranslation::setAliasScopeMetadata(AliasAnalysisOpInterface op,
1770d25e91d7STyler Augustine                                               llvm::Instruction *inst) {
17710fc8d9e4STobias Gysi   auto populateScopeMetadata = [&](ArrayAttr aliasScopeAttrs, unsigned kind) {
17720fc8d9e4STobias Gysi     if (!aliasScopeAttrs || aliasScopeAttrs.empty())
1773d25e91d7STyler Augustine       return;
17745f230ed7STobias Gysi     llvm::MDNode *node = getOrCreateAliasScopes(
17750fc8d9e4STobias Gysi         llvm::to_vector(aliasScopeAttrs.getAsRange<AliasScopeAttr>()));
1776fef08da4STobias Gysi     inst->setMetadata(kind, node);
1777d25e91d7STyler Augustine   };
1778d25e91d7STyler Augustine 
17792ea6bb64STobias Gysi   populateScopeMetadata(op.getAliasScopesOrNull(),
17802ea6bb64STobias Gysi                         llvm::LLVMContext::MD_alias_scope);
17812ea6bb64STobias Gysi   populateScopeMetadata(op.getNoAliasScopesOrNull(),
17822ea6bb64STobias Gysi                         llvm::LLVMContext::MD_noalias);
1783d25e91d7STyler Augustine }
1784d25e91d7STyler Augustine 
17851dda134fSMarkus Böck llvm::MDNode *ModuleTranslation::getTBAANode(TBAATagAttr tbaaAttr) const {
17861dda134fSMarkus Böck   return tbaaMetadataMapping.lookup(tbaaAttr);
17872f66c891SSlava Zakharin }
17882f66c891SSlava Zakharin 
1789edfefd7fSTobias Gysi void ModuleTranslation::setTBAAMetadata(AliasAnalysisOpInterface op,
17902f66c891SSlava Zakharin                                         llvm::Instruction *inst) {
1791edfefd7fSTobias Gysi   ArrayAttr tagRefs = op.getTBAATagsOrNull();
1792edfefd7fSTobias Gysi   if (!tagRefs || tagRefs.empty())
17932f66c891SSlava Zakharin     return;
1794fef08da4STobias Gysi 
1795edfefd7fSTobias Gysi   // LLVM IR currently does not support attaching more than one TBAA access tag
1796edfefd7fSTobias Gysi   // to a memory accessing instruction. It may be useful to support this in
1797edfefd7fSTobias Gysi   // future, but for the time being just ignore the metadata if MLIR operation
1798edfefd7fSTobias Gysi   // has multiple access tags.
1799edfefd7fSTobias Gysi   if (tagRefs.size() > 1) {
1800edfefd7fSTobias Gysi     op.emitWarning() << "TBAA access tags were not translated, because LLVM "
18012f66c891SSlava Zakharin                         "IR only supports a single tag per instruction";
18022f66c891SSlava Zakharin     return;
18032f66c891SSlava Zakharin   }
1804fef08da4STobias Gysi 
18051dda134fSMarkus Böck   llvm::MDNode *node = getTBAANode(cast<TBAATagAttr>(tagRefs[0]));
1806fef08da4STobias Gysi   inst->setMetadata(llvm::LLVMContext::MD_tbaa, node);
18072f66c891SSlava Zakharin }
18082f66c891SSlava Zakharin 
180910fa2770STobias Gysi void ModuleTranslation::setBranchWeightsMetadata(BranchWeightOpInterface op) {
181010fa2770STobias Gysi   DenseI32ArrayAttr weightsAttr = op.getBranchWeightsOrNull();
181110fa2770STobias Gysi   if (!weightsAttr)
181210fa2770STobias Gysi     return;
181310fa2770STobias Gysi 
181410fa2770STobias Gysi   llvm::Instruction *inst = isa<CallOp>(op) ? lookupCall(op) : lookupBranch(op);
181510fa2770STobias Gysi   assert(inst && "expected the operation to have a mapping to an instruction");
181610fa2770STobias Gysi   SmallVector<uint32_t> weights(weightsAttr.asArrayRef());
181710fa2770STobias Gysi   inst->setMetadata(
181810fa2770STobias Gysi       llvm::LLVMContext::MD_prof,
181910fa2770STobias Gysi       llvm::MDBuilder(getLLVMContext()).createBranchWeights(weights));
182010fa2770STobias Gysi }
182110fa2770STobias Gysi 
18222f66c891SSlava Zakharin LogicalResult ModuleTranslation::createTBAAMetadata() {
18232f66c891SSlava Zakharin   llvm::LLVMContext &ctx = llvmModule->getContext();
18242f66c891SSlava Zakharin   llvm::IntegerType *offsetTy = llvm::IntegerType::get(ctx, 64);
18252f66c891SSlava Zakharin 
18261dda134fSMarkus Böck   // Walk the entire module and create all metadata nodes for the TBAA
18271dda134fSMarkus Böck   // attributes. The code below relies on two invariants of the
18281dda134fSMarkus Böck   // `AttrTypeWalker`:
18291dda134fSMarkus Böck   // 1. Attributes are visited in post-order: Since the attributes create a DAG,
18301dda134fSMarkus Böck   //    this ensures that any lookups into `tbaaMetadataMapping` for child
18311dda134fSMarkus Böck   //    attributes succeed.
18321dda134fSMarkus Böck   // 2. Attributes are only ever visited once: This way we don't leak any
18331dda134fSMarkus Böck   //    LLVM metadata instances.
18341dda134fSMarkus Böck   AttrTypeWalker walker;
18351dda134fSMarkus Böck   walker.addWalk([&](TBAARootAttr root) {
18361dda134fSMarkus Böck     tbaaMetadataMapping.insert(
18371dda134fSMarkus Böck         {root, llvm::MDNode::get(ctx, llvm::MDString::get(ctx, root.getId()))});
18381dda134fSMarkus Böck   });
18391dda134fSMarkus Böck 
18401dda134fSMarkus Böck   walker.addWalk([&](TBAATypeDescriptorAttr descriptor) {
18412f66c891SSlava Zakharin     SmallVector<llvm::Metadata *> operands;
18421dda134fSMarkus Böck     operands.push_back(llvm::MDString::get(ctx, descriptor.getId()));
18431dda134fSMarkus Böck     for (TBAAMemberAttr member : descriptor.getMembers()) {
18441dda134fSMarkus Böck       operands.push_back(tbaaMetadataMapping.lookup(member.getTypeDesc()));
18452f66c891SSlava Zakharin       operands.push_back(llvm::ConstantAsMetadata::get(
18461dda134fSMarkus Böck           llvm::ConstantInt::get(offsetTy, member.getOffset())));
18472f66c891SSlava Zakharin     }
18481dda134fSMarkus Böck 
18491dda134fSMarkus Böck     tbaaMetadataMapping.insert({descriptor, llvm::MDNode::get(ctx, operands)});
18501dda134fSMarkus Böck   });
18511dda134fSMarkus Böck 
18521dda134fSMarkus Böck   walker.addWalk([&](TBAATagAttr tag) {
18531dda134fSMarkus Böck     SmallVector<llvm::Metadata *> operands;
18541dda134fSMarkus Böck 
18551dda134fSMarkus Böck     operands.push_back(tbaaMetadataMapping.lookup(tag.getBaseType()));
18561dda134fSMarkus Böck     operands.push_back(tbaaMetadataMapping.lookup(tag.getAccessType()));
18571dda134fSMarkus Böck 
18582f66c891SSlava Zakharin     operands.push_back(llvm::ConstantAsMetadata::get(
18591dda134fSMarkus Böck         llvm::ConstantInt::get(offsetTy, tag.getOffset())));
18601dda134fSMarkus Böck     if (tag.getConstant())
18611dda134fSMarkus Böck       operands.push_back(
18621dda134fSMarkus Böck           llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(offsetTy, 1)));
18632f66c891SSlava Zakharin 
18641dda134fSMarkus Böck     tbaaMetadataMapping.insert({tag, llvm::MDNode::get(ctx, operands)});
18651dda134fSMarkus Böck   });
18662f66c891SSlava Zakharin 
18671dda134fSMarkus Böck   mlirModule->walk([&](AliasAnalysisOpInterface analysisOpInterface) {
18681dda134fSMarkus Böck     if (auto attr = analysisOpInterface.getTBAATagsOrNull())
18691dda134fSMarkus Böck       walker.walk(attr);
18701dda134fSMarkus Böck   });
18712f66c891SSlava Zakharin 
18722f66c891SSlava Zakharin   return success();
18732f66c891SSlava Zakharin }
18742f66c891SSlava Zakharin 
187590aac06cSTarun Prabhu LogicalResult ModuleTranslation::createIdentMetadata() {
187690aac06cSTarun Prabhu   if (auto attr = mlirModule->getAttrOfType<StringAttr>(
187790aac06cSTarun Prabhu           LLVMDialect::getIdentAttrName())) {
187890aac06cSTarun Prabhu     StringRef ident = attr;
187990aac06cSTarun Prabhu     llvm::LLVMContext &ctx = llvmModule->getContext();
188090aac06cSTarun Prabhu     llvm::NamedMDNode *namedMd =
188190aac06cSTarun Prabhu         llvmModule->getOrInsertNamedMetadata(LLVMDialect::getIdentAttrName());
188290aac06cSTarun Prabhu     llvm::MDNode *md = llvm::MDNode::get(ctx, llvm::MDString::get(ctx, ident));
188390aac06cSTarun Prabhu     namedMd->addOperand(md);
188490aac06cSTarun Prabhu   }
188590aac06cSTarun Prabhu 
188690aac06cSTarun Prabhu   return success();
188790aac06cSTarun Prabhu }
188890aac06cSTarun Prabhu 
1889839344f0STarun Prabhu LogicalResult ModuleTranslation::createCommandlineMetadata() {
1890839344f0STarun Prabhu   if (auto attr = mlirModule->getAttrOfType<StringAttr>(
1891839344f0STarun Prabhu           LLVMDialect::getCommandlineAttrName())) {
1892839344f0STarun Prabhu     StringRef cmdLine = attr;
1893839344f0STarun Prabhu     llvm::LLVMContext &ctx = llvmModule->getContext();
1894839344f0STarun Prabhu     llvm::NamedMDNode *nmd = llvmModule->getOrInsertNamedMetadata(
1895839344f0STarun Prabhu         LLVMDialect::getCommandlineAttrName());
1896839344f0STarun Prabhu     llvm::MDNode *md =
1897839344f0STarun Prabhu         llvm::MDNode::get(ctx, llvm::MDString::get(ctx, cmdLine));
1898839344f0STarun Prabhu     nmd->addOperand(md);
1899839344f0STarun Prabhu   }
1900839344f0STarun Prabhu 
1901839344f0STarun Prabhu   return success();
1902839344f0STarun Prabhu }
1903839344f0STarun Prabhu 
1904889a1178SChristian Ulmann void ModuleTranslation::setLoopMetadata(Operation *op,
1905889a1178SChristian Ulmann                                         llvm::Instruction *inst) {
1906d94399c6SChristian Ulmann   LoopAnnotationAttr attr =
1907d94399c6SChristian Ulmann       TypeSwitch<Operation *, LoopAnnotationAttr>(op)
1908d94399c6SChristian Ulmann           .Case<LLVM::BrOp, LLVM::CondBrOp>(
1909d94399c6SChristian Ulmann               [](auto branchOp) { return branchOp.getLoopAnnotationAttr(); });
1910889a1178SChristian Ulmann   if (!attr)
1911889a1178SChristian Ulmann     return;
191287a04795SChristian Ulmann   llvm::MDNode *loopMD =
191387a04795SChristian Ulmann       loopAnnotationTranslation->translateLoopAnnotation(attr, op);
1914889a1178SChristian Ulmann   inst->setMetadata(llvm::LLVMContext::MD_loop, loopMD);
1915889a1178SChristian Ulmann }
1916889a1178SChristian Ulmann 
191740afff7bSlfrenot void ModuleTranslation::setDisjointFlag(Operation *op, llvm::Value *value) {
191840afff7bSlfrenot   auto iface = cast<DisjointFlagInterface>(op);
191940afff7bSlfrenot   // We do a dyn_cast here in case the value got folded into a constant.
192040afff7bSlfrenot   if (auto disjointInst = dyn_cast<llvm::PossiblyDisjointInst>(value))
192140afff7bSlfrenot     disjointInst->setIsDisjoint(iface.getIsDisjoint());
192240afff7bSlfrenot }
192340afff7bSlfrenot 
1924c69c9e0fSAlex Zinenko llvm::Type *ModuleTranslation::convertType(Type type) {
1925b2ab375dSAlex Zinenko   return typeTranslator.translateType(type);
1926aec38c61SAlex Zinenko }
1927aec38c61SAlex Zinenko 
19288647e4c3SAlex Zinenko /// A helper to look up remapped operands in the value remapping table.
19298647e4c3SAlex Zinenko SmallVector<llvm::Value *> ModuleTranslation::lookupValues(ValueRange values) {
19308647e4c3SAlex Zinenko   SmallVector<llvm::Value *> remapped;
1931efadb6b8SAlex Zinenko   remapped.reserve(values.size());
19320881a4f1SAlex Zinenko   for (Value v : values)
19330881a4f1SAlex Zinenko     remapped.push_back(lookupValue(v));
1934efadb6b8SAlex Zinenko   return remapped;
1935efadb6b8SAlex Zinenko }
1936efadb6b8SAlex Zinenko 
1937d3f9388fSJan Sjodin llvm::OpenMPIRBuilder *ModuleTranslation::getOpenMPBuilder() {
1938d3f9388fSJan Sjodin   if (!ompBuilder) {
1939d3f9388fSJan Sjodin     ompBuilder = std::make_unique<llvm::OpenMPIRBuilder>(*llvmModule);
194090587627SSergio Afonso     ompBuilder->initialize();
1941d3f9388fSJan Sjodin 
194290587627SSergio Afonso     // Flags represented as top-level OpenMP dialect attributes are set in
194390587627SSergio Afonso     // `OpenMPDialectLLVMIRTranslationInterface::amendOperation()`. Here we set
194490587627SSergio Afonso     // the default configuration.
194590587627SSergio Afonso     ompBuilder->setConfig(llvm::OpenMPIRBuilderConfig(
194690587627SSergio Afonso         /* IsTargetDevice = */ false, /* IsGPU = */ false,
1947094a63a2SSergio Afonso         /* OpenMPOffloadMandatory = */ false,
1948094a63a2SSergio Afonso         /* HasRequiresReverseOffload = */ false,
1949094a63a2SSergio Afonso         /* HasRequiresUnifiedAddress = */ false,
1950094a63a2SSergio Afonso         /* HasRequiresUnifiedSharedMemory = */ false,
195190587627SSergio Afonso         /* HasRequiresDynamicAllocators = */ false));
1952d3f9388fSJan Sjodin   }
1953d3f9388fSJan Sjodin   return ompBuilder.get();
1954d3f9388fSJan Sjodin }
1955d3f9388fSJan Sjodin 
1956794b58b4SChristian Ulmann llvm::DILocation *ModuleTranslation::translateLoc(Location loc,
1957794b58b4SChristian Ulmann                                                   llvm::DILocalScope *scope) {
195866900b3eSAlex Zinenko   return debugTranslation->translateLoc(loc, scope);
195966900b3eSAlex Zinenko }
196066900b3eSAlex Zinenko 
19616da578ceSJustin Wilson llvm::DIExpression *
19626da578ceSJustin Wilson ModuleTranslation::translateExpression(LLVM::DIExpressionAttr attr) {
19636da578ceSJustin Wilson   return debugTranslation->translateExpression(attr);
19646da578ceSJustin Wilson }
19656da578ceSJustin Wilson 
19666da578ceSJustin Wilson llvm::DIGlobalVariableExpression *
19676da578ceSJustin Wilson ModuleTranslation::translateGlobalVariableExpression(
19686da578ceSJustin Wilson     LLVM::DIGlobalVariableExpressionAttr attr) {
19696da578ceSJustin Wilson   return debugTranslation->translateGlobalVariableExpression(attr);
19706da578ceSJustin Wilson }
19716da578ceSJustin Wilson 
19729af92ed8SRiver Riddle llvm::Metadata *ModuleTranslation::translateDebugInfo(LLVM::DINodeAttr attr) {
19739af92ed8SRiver Riddle   return debugTranslation->translate(attr);
19749af92ed8SRiver Riddle }
19759af92ed8SRiver Riddle 
197677cbc9bfSVictor Perez llvm::RoundingMode
197777cbc9bfSVictor Perez ModuleTranslation::translateRoundingMode(LLVM::RoundingMode rounding) {
197877cbc9bfSVictor Perez   return convertRoundingModeToLLVM(rounding);
197977cbc9bfSVictor Perez }
198077cbc9bfSVictor Perez 
198177cbc9bfSVictor Perez llvm::fp::ExceptionBehavior ModuleTranslation::translateFPExceptionBehavior(
198277cbc9bfSVictor Perez     LLVM::FPExceptionBehavior exceptionBehavior) {
198377cbc9bfSVictor Perez   return convertFPExceptionBehaviorToLLVM(exceptionBehavior);
198477cbc9bfSVictor Perez }
198577cbc9bfSVictor Perez 
1986176379e0SAlex Zinenko llvm::NamedMDNode *
1987176379e0SAlex Zinenko ModuleTranslation::getOrInsertNamedModuleMetadata(StringRef name) {
1988176379e0SAlex Zinenko   return llvmModule->getOrInsertNamedMetadata(name);
1989176379e0SAlex Zinenko }
1990176379e0SAlex Zinenko 
199172d013ddSAlex Zinenko void ModuleTranslation::StackFrame::anchor() {}
199272d013ddSAlex Zinenko 
1993ce8f10d6SAlex Zinenko static std::unique_ptr<llvm::Module>
1994ce8f10d6SAlex Zinenko prepareLLVMModule(Operation *m, llvm::LLVMContext &llvmContext,
1995ce8f10d6SAlex Zinenko                   StringRef name) {
1996f9dc2b70SMehdi Amini   m->getContext()->getOrLoadDialect<LLVM::LLVMDialect>();
1997db1c197bSAlex Zinenko   auto llvmModule = std::make_unique<llvm::Module>(name, llvmContext);
199848f8d95fSStephen Tozer   // ModuleTranslation can currently only construct modules in the old debug
199948f8d95fSStephen Tozer   // info format, so set the flag accordingly.
200048f8d95fSStephen Tozer   llvmModule->setNewDbgInfoFormatFlag(false);
2001168213f9SAlex Zinenko   if (auto dataLayoutAttr =
2002830b9b07SMehdi Amini           m->getDiscardableAttr(LLVM::LLVMDialect::getDataLayoutAttrName())) {
20035550c821STres Popp     llvmModule->setDataLayout(cast<StringAttr>(dataLayoutAttr).getValue());
2004ea998709SAlex Zinenko   } else {
2005ea998709SAlex Zinenko     FailureOr<llvm::DataLayout> llvmDataLayout(llvm::DataLayout(""));
2006ea998709SAlex Zinenko     if (auto iface = dyn_cast<DataLayoutOpInterface>(m)) {
2007ea998709SAlex Zinenko       if (DataLayoutSpecInterface spec = iface.getDataLayoutSpec()) {
2008ea998709SAlex Zinenko         llvmDataLayout =
2009ea998709SAlex Zinenko             translateDataLayout(spec, DataLayout(iface), m->getLoc());
2010ea998709SAlex Zinenko       }
2011ea998709SAlex Zinenko     } else if (auto mod = dyn_cast<ModuleOp>(m)) {
2012ea998709SAlex Zinenko       if (DataLayoutSpecInterface spec = mod.getDataLayoutSpec()) {
2013ea998709SAlex Zinenko         llvmDataLayout =
2014ea998709SAlex Zinenko             translateDataLayout(spec, DataLayout(mod), m->getLoc());
2015ea998709SAlex Zinenko       }
2016ea998709SAlex Zinenko     }
2017ea998709SAlex Zinenko     if (failed(llvmDataLayout))
2018ea998709SAlex Zinenko       return nullptr;
2019ea998709SAlex Zinenko     llvmModule->setDataLayout(*llvmDataLayout);
2020ea998709SAlex Zinenko   }
20215dd5a083SNicolas Vasilache   if (auto targetTripleAttr =
2022830b9b07SMehdi Amini           m->getDiscardableAttr(LLVM::LLVMDialect::getTargetTripleAttrName()))
20235550c821STres Popp     llvmModule->setTargetTriple(cast<StringAttr>(targetTripleAttr).getValue());
20245d7231d8SStephan Herhut 
20255d7231d8SStephan Herhut   return llvmModule;
20265d7231d8SStephan Herhut }
2027ce8f10d6SAlex Zinenko 
2028ce8f10d6SAlex Zinenko std::unique_ptr<llvm::Module>
2029ce8f10d6SAlex Zinenko mlir::translateModuleToLLVMIR(Operation *module, llvm::LLVMContext &llvmContext,
20309b2a3499SChristian Ulmann                               StringRef name, bool disableVerification) {
2031ed90f802Srkayaith   if (!satisfiesLLVMModule(module)) {
2032ed90f802Srkayaith     module->emitOpError("can not be translated to an LLVMIR module");
2033ce8f10d6SAlex Zinenko     return nullptr;
2034ed90f802Srkayaith   }
2035ea998709SAlex Zinenko 
2036ce8f10d6SAlex Zinenko   std::unique_ptr<llvm::Module> llvmModule =
2037ce8f10d6SAlex Zinenko       prepareLLVMModule(module, llvmContext, name);
2038ea998709SAlex Zinenko   if (!llvmModule)
2039ea998709SAlex Zinenko     return nullptr;
2040ce8f10d6SAlex Zinenko 
2041ce8f10d6SAlex Zinenko   LLVM::ensureDistinctSuccessors(module);
2042422b84a7SBilly Zhu   LLVM::legalizeDIExpressionsRecursively(module);
2043ce8f10d6SAlex Zinenko 
2044ce8f10d6SAlex Zinenko   ModuleTranslation translator(module, std::move(llvmModule));
20452ae5d1c7SSergio Afonso   llvm::IRBuilder<> llvmBuilder(llvmContext);
20462ae5d1c7SSergio Afonso 
20472ae5d1c7SSergio Afonso   // Convert module before functions and operations inside, so dialect
20482ae5d1c7SSergio Afonso   // attributes can be used to change dialect-specific global configurations via
20492ae5d1c7SSergio Afonso   // `amendOperation()`. These configurations can then influence the translation
20502ae5d1c7SSergio Afonso   // of operations afterwards.
20512ae5d1c7SSergio Afonso   if (failed(translator.convertOperation(*module, llvmBuilder)))
20522ae5d1c7SSergio Afonso     return nullptr;
20532ae5d1c7SSergio Afonso 
20549d4c1be8SDavid Truby   if (failed(translator.convertComdats()))
20559d4c1be8SDavid Truby     return nullptr;
2056b126ee65STobias Gysi   if (failed(translator.convertFunctionSignatures()))
2057b126ee65STobias Gysi     return nullptr;
2058ce8f10d6SAlex Zinenko   if (failed(translator.convertGlobals()))
2059ce8f10d6SAlex Zinenko     return nullptr;
20602f66c891SSlava Zakharin   if (failed(translator.createTBAAMetadata()))
20612f66c891SSlava Zakharin     return nullptr;
206290aac06cSTarun Prabhu   if (failed(translator.createIdentMetadata()))
206390aac06cSTarun Prabhu     return nullptr;
2064839344f0STarun Prabhu   if (failed(translator.createCommandlineMetadata()))
2065839344f0STarun Prabhu     return nullptr;
20668647e4c3SAlex Zinenko 
20678647e4c3SAlex Zinenko   // Convert other top-level operations if possible.
20688647e4c3SAlex Zinenko   for (Operation &o : getModuleBody(module).getOperations()) {
206957b9b296SUday Bondhugula     if (!isa<LLVM::LLVMFuncOp, LLVM::GlobalOp, LLVM::GlobalCtorsOp,
20700fc8d9e4STobias Gysi              LLVM::GlobalDtorsOp, LLVM::ComdatOp>(&o) &&
20718647e4c3SAlex Zinenko         !o.hasTrait<OpTrait::IsTerminator>() &&
20728647e4c3SAlex Zinenko         failed(translator.convertOperation(o, llvmBuilder))) {
20738647e4c3SAlex Zinenko       return nullptr;
20748647e4c3SAlex Zinenko     }
20758647e4c3SAlex Zinenko   }
20768647e4c3SAlex Zinenko 
2077a428b5afSFabian Mora   // Operations in function bodies with symbolic references must be converted
2078a428b5afSFabian Mora   // after the top-level operations they refer to are declared, so we do it
2079a428b5afSFabian Mora   // last.
2080a428b5afSFabian Mora   if (failed(translator.convertFunctions()))
2081a428b5afSFabian Mora     return nullptr;
2082a428b5afSFabian Mora 
208348f8d95fSStephen Tozer   // Once we've finished constructing elements in the module, we should convert
208448f8d95fSStephen Tozer   // it to use the debug info format desired by LLVM.
208548f8d95fSStephen Tozer   // See https://llvm.org/docs/RemoveDIsDebugInfo.html
208648f8d95fSStephen Tozer   translator.llvmModule->setIsNewDbgInfoFormat(UseNewDbgInfoFormat);
208748f8d95fSStephen Tozer 
20889b2a3499SChristian Ulmann   if (!disableVerification &&
20899b2a3499SChristian Ulmann       llvm::verifyModule(*translator.llvmModule, &llvm::errs()))
2090ce8f10d6SAlex Zinenko     return nullptr;
2091ce8f10d6SAlex Zinenko 
2092ce8f10d6SAlex Zinenko   return std::move(translator.llvmModule);
2093ce8f10d6SAlex Zinenko }
2094