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 ®ion) { 7348647e4c3SAlex Zinenko SmallVector<Region *> toProcess; 7358647e4c3SAlex Zinenko toProcess.push_back(®ion); 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 ®ion, 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