MLIR  18.0.0git
ModuleTranslation.cpp
Go to the documentation of this file.
1 //===- ModuleTranslation.cpp - MLIR to LLVM conversion --------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements the translation between an MLIR LLVM dialect module and
10 // the corresponding LLVMIR module. It only handles core LLVM IR operations.
11 //
12 //===----------------------------------------------------------------------===//
13 
15 
16 #include "AttrKindDetail.h"
17 #include "DebugTranslation.h"
19 #include "mlir/Dialect/DLTI/DLTI.h"
26 #include "mlir/IR/Attributes.h"
27 #include "mlir/IR/BuiltinOps.h"
28 #include "mlir/IR/BuiltinTypes.h"
30 #include "mlir/Support/LLVM.h"
34 
35 #include "llvm/ADT/PostOrderIterator.h"
36 #include "llvm/ADT/SetVector.h"
37 #include "llvm/ADT/TypeSwitch.h"
38 #include "llvm/Frontend/OpenMP/OMPIRBuilder.h"
39 #include "llvm/IR/BasicBlock.h"
40 #include "llvm/IR/CFG.h"
41 #include "llvm/IR/Constants.h"
42 #include "llvm/IR/DerivedTypes.h"
43 #include "llvm/IR/IRBuilder.h"
44 #include "llvm/IR/InlineAsm.h"
45 #include "llvm/IR/IntrinsicsNVPTX.h"
46 #include "llvm/IR/LLVMContext.h"
47 #include "llvm/IR/MDBuilder.h"
48 #include "llvm/IR/Module.h"
49 #include "llvm/IR/Verifier.h"
50 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
51 #include "llvm/Transforms/Utils/Cloning.h"
52 #include "llvm/Transforms/Utils/ModuleUtils.h"
53 #include <optional>
54 
55 using namespace mlir;
56 using namespace mlir::LLVM;
57 using namespace mlir::LLVM::detail;
58 
59 #include "mlir/Dialect/LLVMIR/LLVMConversionEnumsToLLVM.inc"
60 
61 /// Translates the given data layout spec attribute to the LLVM IR data layout.
62 /// Only integer, float, pointer and endianness entries are currently supported.
64 translateDataLayout(DataLayoutSpecInterface attribute,
65  const DataLayout &dataLayout,
66  std::optional<Location> loc = std::nullopt) {
67  if (!loc)
68  loc = UnknownLoc::get(attribute.getContext());
69 
70  // Translate the endianness attribute.
71  std::string llvmDataLayout;
72  llvm::raw_string_ostream layoutStream(llvmDataLayout);
73  for (DataLayoutEntryInterface entry : attribute.getEntries()) {
74  auto key = llvm::dyn_cast_if_present<StringAttr>(entry.getKey());
75  if (!key)
76  continue;
77  if (key.getValue() == DLTIDialect::kDataLayoutEndiannessKey) {
78  auto value = cast<StringAttr>(entry.getValue());
79  bool isLittleEndian =
80  value.getValue() == DLTIDialect::kDataLayoutEndiannessLittle;
81  layoutStream << "-" << (isLittleEndian ? "e" : "E");
82  layoutStream.flush();
83  continue;
84  }
85  if (key.getValue() == DLTIDialect::kDataLayoutAllocaMemorySpaceKey) {
86  auto value = cast<IntegerAttr>(entry.getValue());
87  uint64_t space = value.getValue().getZExtValue();
88  // Skip the default address space.
89  if (space == 0)
90  continue;
91  layoutStream << "-A" << space;
92  layoutStream.flush();
93  continue;
94  }
95  if (key.getValue() == DLTIDialect::kDataLayoutStackAlignmentKey) {
96  auto value = cast<IntegerAttr>(entry.getValue());
97  uint64_t alignment = value.getValue().getZExtValue();
98  // Skip the default stack alignment.
99  if (alignment == 0)
100  continue;
101  layoutStream << "-S" << alignment;
102  layoutStream.flush();
103  continue;
104  }
105  emitError(*loc) << "unsupported data layout key " << key;
106  return failure();
107  }
108 
109  // Go through the list of entries to check which types are explicitly
110  // specified in entries. Where possible, data layout queries are used instead
111  // of directly inspecting the entries.
112  for (DataLayoutEntryInterface entry : attribute.getEntries()) {
113  auto type = llvm::dyn_cast_if_present<Type>(entry.getKey());
114  if (!type)
115  continue;
116  // Data layout for the index type is irrelevant at this point.
117  if (isa<IndexType>(type))
118  continue;
119  layoutStream << "-";
120  LogicalResult result =
122  .Case<IntegerType, Float16Type, Float32Type, Float64Type,
123  Float80Type, Float128Type>([&](Type type) -> LogicalResult {
124  if (auto intType = dyn_cast<IntegerType>(type)) {
125  if (intType.getSignedness() != IntegerType::Signless)
126  return emitError(*loc)
127  << "unsupported data layout for non-signless integer "
128  << intType;
129  layoutStream << "i";
130  } else {
131  layoutStream << "f";
132  }
133  unsigned size = dataLayout.getTypeSizeInBits(type);
134  unsigned abi = dataLayout.getTypeABIAlignment(type) * 8u;
135  unsigned preferred =
136  dataLayout.getTypePreferredAlignment(type) * 8u;
137  layoutStream << size << ":" << abi;
138  if (abi != preferred)
139  layoutStream << ":" << preferred;
140  return success();
141  })
142  .Case([&](LLVMPointerType ptrType) {
143  layoutStream << "p" << ptrType.getAddressSpace() << ":";
144  unsigned size = dataLayout.getTypeSizeInBits(type);
145  unsigned abi = dataLayout.getTypeABIAlignment(type) * 8u;
146  unsigned preferred =
147  dataLayout.getTypePreferredAlignment(type) * 8u;
148  layoutStream << size << ":" << abi << ":" << preferred;
149  if (std::optional<unsigned> index = extractPointerSpecValue(
150  entry.getValue(), PtrDLEntryPos::Index))
151  layoutStream << ":" << *index;
152  return success();
153  })
154  .Default([loc](Type type) {
155  return emitError(*loc)
156  << "unsupported type in data layout: " << type;
157  });
158  if (failed(result))
159  return failure();
160  }
161  layoutStream.flush();
162  StringRef layoutSpec(llvmDataLayout);
163  if (layoutSpec.startswith("-"))
164  layoutSpec = layoutSpec.drop_front();
165 
166  return llvm::DataLayout(layoutSpec);
167 }
168 
169 /// Builds a constant of a sequential LLVM type `type`, potentially containing
170 /// other sequential types recursively, from the individual constant values
171 /// provided in `constants`. `shape` contains the number of elements in nested
172 /// sequential types. Reports errors at `loc` and returns nullptr on error.
173 static llvm::Constant *
175  ArrayRef<int64_t> shape, llvm::Type *type,
176  Location loc) {
177  if (shape.empty()) {
178  llvm::Constant *result = constants.front();
179  constants = constants.drop_front();
180  return result;
181  }
182 
183  llvm::Type *elementType;
184  if (auto *arrayTy = dyn_cast<llvm::ArrayType>(type)) {
185  elementType = arrayTy->getElementType();
186  } else if (auto *vectorTy = dyn_cast<llvm::VectorType>(type)) {
187  elementType = vectorTy->getElementType();
188  } else {
189  emitError(loc) << "expected sequential LLVM types wrapping a scalar";
190  return nullptr;
191  }
192 
194  nested.reserve(shape.front());
195  for (int64_t i = 0; i < shape.front(); ++i) {
196  nested.push_back(buildSequentialConstant(constants, shape.drop_front(),
197  elementType, loc));
198  if (!nested.back())
199  return nullptr;
200  }
201 
202  if (shape.size() == 1 && type->isVectorTy())
203  return llvm::ConstantVector::get(nested);
205  llvm::ArrayType::get(elementType, shape.front()), nested);
206 }
207 
208 /// Returns the first non-sequential type nested in sequential types.
209 static llvm::Type *getInnermostElementType(llvm::Type *type) {
210  do {
211  if (auto *arrayTy = dyn_cast<llvm::ArrayType>(type)) {
212  type = arrayTy->getElementType();
213  } else if (auto *vectorTy = dyn_cast<llvm::VectorType>(type)) {
214  type = vectorTy->getElementType();
215  } else {
216  return type;
217  }
218  } while (true);
219 }
220 
221 /// Convert a dense elements attribute to an LLVM IR constant using its raw data
222 /// storage if possible. This supports elements attributes of tensor or vector
223 /// type and avoids constructing separate objects for individual values of the
224 /// innermost dimension. Constants for other dimensions are still constructed
225 /// recursively. Returns null if constructing from raw data is not supported for
226 /// this type, e.g., element type is not a power-of-two-sized primitive. Reports
227 /// other errors at `loc`.
228 static llvm::Constant *
230  llvm::Type *llvmType,
231  const ModuleTranslation &moduleTranslation) {
232  if (!denseElementsAttr)
233  return nullptr;
234 
235  llvm::Type *innermostLLVMType = getInnermostElementType(llvmType);
236  if (!llvm::ConstantDataSequential::isElementTypeCompatible(innermostLLVMType))
237  return nullptr;
238 
239  ShapedType type = denseElementsAttr.getType();
240  if (type.getNumElements() == 0)
241  return nullptr;
242 
243  // Check that the raw data size matches what is expected for the scalar size.
244  // TODO: in theory, we could repack the data here to keep constructing from
245  // raw data.
246  // TODO: we may also need to consider endianness when cross-compiling to an
247  // architecture where it is different.
248  unsigned elementByteSize = denseElementsAttr.getRawData().size() /
249  denseElementsAttr.getNumElements();
250  if (8 * elementByteSize != innermostLLVMType->getScalarSizeInBits())
251  return nullptr;
252 
253  // Compute the shape of all dimensions but the innermost. Note that the
254  // innermost dimension may be that of the vector element type.
255  bool hasVectorElementType = isa<VectorType>(type.getElementType());
256  unsigned numAggregates =
257  denseElementsAttr.getNumElements() /
258  (hasVectorElementType ? 1
259  : denseElementsAttr.getType().getShape().back());
260  ArrayRef<int64_t> outerShape = type.getShape();
261  if (!hasVectorElementType)
262  outerShape = outerShape.drop_back();
263 
264  // Handle the case of vector splat, LLVM has special support for it.
265  if (denseElementsAttr.isSplat() &&
266  (isa<VectorType>(type) || hasVectorElementType)) {
267  llvm::Constant *splatValue = LLVM::detail::getLLVMConstant(
268  innermostLLVMType, denseElementsAttr.getSplatValue<Attribute>(), loc,
269  moduleTranslation);
270  llvm::Constant *splatVector =
271  llvm::ConstantDataVector::getSplat(0, splatValue);
272  SmallVector<llvm::Constant *> constants(numAggregates, splatVector);
273  ArrayRef<llvm::Constant *> constantsRef = constants;
274  return buildSequentialConstant(constantsRef, outerShape, llvmType, loc);
275  }
276  if (denseElementsAttr.isSplat())
277  return nullptr;
278 
279  // In case of non-splat, create a constructor for the innermost constant from
280  // a piece of raw data.
281  std::function<llvm::Constant *(StringRef)> buildCstData;
282  if (isa<TensorType>(type)) {
283  auto vectorElementType = dyn_cast<VectorType>(type.getElementType());
284  if (vectorElementType && vectorElementType.getRank() == 1) {
285  buildCstData = [&](StringRef data) {
286  return llvm::ConstantDataVector::getRaw(
287  data, vectorElementType.getShape().back(), innermostLLVMType);
288  };
289  } else if (!vectorElementType) {
290  buildCstData = [&](StringRef data) {
291  return llvm::ConstantDataArray::getRaw(data, type.getShape().back(),
292  innermostLLVMType);
293  };
294  }
295  } else if (isa<VectorType>(type)) {
296  buildCstData = [&](StringRef data) {
297  return llvm::ConstantDataVector::getRaw(data, type.getShape().back(),
298  innermostLLVMType);
299  };
300  }
301  if (!buildCstData)
302  return nullptr;
303 
304  // Create innermost constants and defer to the default constant creation
305  // mechanism for other dimensions.
307  unsigned aggregateSize = denseElementsAttr.getType().getShape().back() *
308  (innermostLLVMType->getScalarSizeInBits() / 8);
309  constants.reserve(numAggregates);
310  for (unsigned i = 0; i < numAggregates; ++i) {
311  StringRef data(denseElementsAttr.getRawData().data() + i * aggregateSize,
312  aggregateSize);
313  constants.push_back(buildCstData(data));
314  }
315 
316  ArrayRef<llvm::Constant *> constantsRef = constants;
317  return buildSequentialConstant(constantsRef, outerShape, llvmType, loc);
318 }
319 
320 /// Create an LLVM IR constant of `llvmType` from the MLIR attribute `attr`.
321 /// This currently supports integer, floating point, splat and dense element
322 /// attributes and combinations thereof. Also, an array attribute with two
323 /// elements is supported to represent a complex constant. In case of error,
324 /// report it to `loc` and return nullptr.
326  llvm::Type *llvmType, Attribute attr, Location loc,
327  const ModuleTranslation &moduleTranslation) {
328  if (!attr)
329  return llvm::UndefValue::get(llvmType);
330  if (auto *structType = dyn_cast<::llvm::StructType>(llvmType)) {
331  auto arrayAttr = dyn_cast<ArrayAttr>(attr);
332  if (!arrayAttr || arrayAttr.size() != 2) {
333  emitError(loc, "expected struct type to be a complex number");
334  return nullptr;
335  }
336  llvm::Type *elementType = structType->getElementType(0);
337  llvm::Constant *real =
338  getLLVMConstant(elementType, arrayAttr[0], loc, moduleTranslation);
339  if (!real)
340  return nullptr;
341  llvm::Constant *imag =
342  getLLVMConstant(elementType, arrayAttr[1], loc, moduleTranslation);
343  if (!imag)
344  return nullptr;
345  return llvm::ConstantStruct::get(structType, {real, imag});
346  }
347  // For integer types, we allow a mismatch in sizes as the index type in
348  // MLIR might have a different size than the index type in the LLVM module.
349  if (auto intAttr = dyn_cast<IntegerAttr>(attr))
350  return llvm::ConstantInt::get(
351  llvmType,
352  intAttr.getValue().sextOrTrunc(llvmType->getIntegerBitWidth()));
353  if (auto floatAttr = dyn_cast<FloatAttr>(attr)) {
354  const llvm::fltSemantics &sem = floatAttr.getValue().getSemantics();
355  // Special case for 8-bit floats, which are represented by integers due to
356  // the lack of native fp8 types in LLVM at the moment. Additionally, handle
357  // targets (like AMDGPU) that don't implement bfloat and convert all bfloats
358  // to i16.
359  unsigned floatWidth = APFloat::getSizeInBits(sem);
360  if (llvmType->isIntegerTy(floatWidth))
361  return llvm::ConstantInt::get(llvmType,
362  floatAttr.getValue().bitcastToAPInt());
363  if (llvmType !=
364  llvm::Type::getFloatingPointTy(llvmType->getContext(),
365  floatAttr.getValue().getSemantics())) {
366  emitError(loc, "FloatAttr does not match expected type of the constant");
367  return nullptr;
368  }
369  return llvm::ConstantFP::get(llvmType, floatAttr.getValue());
370  }
371  if (auto funcAttr = dyn_cast<FlatSymbolRefAttr>(attr))
372  return llvm::ConstantExpr::getBitCast(
373  moduleTranslation.lookupFunction(funcAttr.getValue()), llvmType);
374  if (auto splatAttr = dyn_cast<SplatElementsAttr>(attr)) {
375  llvm::Type *elementType;
376  uint64_t numElements;
377  bool isScalable = false;
378  if (auto *arrayTy = dyn_cast<llvm::ArrayType>(llvmType)) {
379  elementType = arrayTy->getElementType();
380  numElements = arrayTy->getNumElements();
381  } else if (auto *fVectorTy = dyn_cast<llvm::FixedVectorType>(llvmType)) {
382  elementType = fVectorTy->getElementType();
383  numElements = fVectorTy->getNumElements();
384  } else if (auto *sVectorTy = dyn_cast<llvm::ScalableVectorType>(llvmType)) {
385  elementType = sVectorTy->getElementType();
386  numElements = sVectorTy->getMinNumElements();
387  isScalable = true;
388  } else {
389  llvm_unreachable("unrecognized constant vector type");
390  }
391  // Splat value is a scalar. Extract it only if the element type is not
392  // another sequence type. The recursion terminates because each step removes
393  // one outer sequential type.
394  bool elementTypeSequential =
395  isa<llvm::ArrayType, llvm::VectorType>(elementType);
396  llvm::Constant *child = getLLVMConstant(
397  elementType,
398  elementTypeSequential ? splatAttr
399  : splatAttr.getSplatValue<Attribute>(),
400  loc, moduleTranslation);
401  if (!child)
402  return nullptr;
403  if (llvmType->isVectorTy())
404  return llvm::ConstantVector::getSplat(
405  llvm::ElementCount::get(numElements, /*Scalable=*/isScalable), child);
406  if (llvmType->isArrayTy()) {
407  auto *arrayType = llvm::ArrayType::get(elementType, numElements);
408  SmallVector<llvm::Constant *, 8> constants(numElements, child);
409  return llvm::ConstantArray::get(arrayType, constants);
410  }
411  }
412 
413  // Try using raw elements data if possible.
414  if (llvm::Constant *result =
415  convertDenseElementsAttr(loc, dyn_cast<DenseElementsAttr>(attr),
416  llvmType, moduleTranslation)) {
417  return result;
418  }
419 
420  // Fall back to element-by-element construction otherwise.
421  if (auto elementsAttr = dyn_cast<ElementsAttr>(attr)) {
422  assert(elementsAttr.getShapedType().hasStaticShape());
423  assert(!elementsAttr.getShapedType().getShape().empty() &&
424  "unexpected empty elements attribute shape");
425 
427  constants.reserve(elementsAttr.getNumElements());
428  llvm::Type *innermostType = getInnermostElementType(llvmType);
429  for (auto n : elementsAttr.getValues<Attribute>()) {
430  constants.push_back(
431  getLLVMConstant(innermostType, n, loc, moduleTranslation));
432  if (!constants.back())
433  return nullptr;
434  }
435  ArrayRef<llvm::Constant *> constantsRef = constants;
436  llvm::Constant *result = buildSequentialConstant(
437  constantsRef, elementsAttr.getShapedType().getShape(), llvmType, loc);
438  assert(constantsRef.empty() && "did not consume all elemental constants");
439  return result;
440  }
441 
442  if (auto stringAttr = dyn_cast<StringAttr>(attr)) {
444  moduleTranslation.getLLVMContext(),
445  ArrayRef<char>{stringAttr.getValue().data(),
446  stringAttr.getValue().size()});
447  }
448  emitError(loc, "unsupported constant value");
449  return nullptr;
450 }
451 
452 ModuleTranslation::ModuleTranslation(Operation *module,
453  std::unique_ptr<llvm::Module> llvmModule)
454  : mlirModule(module), llvmModule(std::move(llvmModule)),
455  debugTranslation(
456  std::make_unique<DebugTranslation>(module, *this->llvmModule)),
457  loopAnnotationTranslation(std::make_unique<LoopAnnotationTranslation>(
458  *this, *this->llvmModule)),
459  typeTranslator(this->llvmModule->getContext()),
460  iface(module->getContext()) {
461  assert(satisfiesLLVMModule(mlirModule) &&
462  "mlirModule should honor LLVM's module semantics.");
463 }
464 
465 ModuleTranslation::~ModuleTranslation() {
466  if (ompBuilder)
467  ompBuilder->finalize();
468 }
469 
471  SmallVector<Region *> toProcess;
472  toProcess.push_back(&region);
473  while (!toProcess.empty()) {
474  Region *current = toProcess.pop_back_val();
475  for (Block &block : *current) {
476  blockMapping.erase(&block);
477  for (Value arg : block.getArguments())
478  valueMapping.erase(arg);
479  for (Operation &op : block) {
480  for (Value value : op.getResults())
481  valueMapping.erase(value);
482  if (op.hasSuccessors())
483  branchMapping.erase(&op);
484  if (isa<LLVM::GlobalOp>(op))
485  globalsMapping.erase(&op);
486  llvm::append_range(
487  toProcess,
488  llvm::map_range(op.getRegions(), [](Region &r) { return &r; }));
489  }
490  }
491  }
492 }
493 
494 /// Get the SSA value passed to the current block from the terminator operation
495 /// of its predecessor.
496 static Value getPHISourceValue(Block *current, Block *pred,
497  unsigned numArguments, unsigned index) {
498  Operation &terminator = *pred->getTerminator();
499  if (isa<LLVM::BrOp>(terminator))
500  return terminator.getOperand(index);
501 
502 #ifndef NDEBUG
503  llvm::SmallPtrSet<Block *, 4> seenSuccessors;
504  for (unsigned i = 0, e = terminator.getNumSuccessors(); i < e; ++i) {
505  Block *successor = terminator.getSuccessor(i);
506  auto branch = cast<BranchOpInterface>(terminator);
507  SuccessorOperands successorOperands = branch.getSuccessorOperands(i);
508  assert(
509  (!seenSuccessors.contains(successor) || successorOperands.empty()) &&
510  "successors with arguments in LLVM branches must be different blocks");
511  seenSuccessors.insert(successor);
512  }
513 #endif
514 
515  // For instructions that branch based on a condition value, we need to take
516  // the operands for the branch that was taken.
517  if (auto condBranchOp = dyn_cast<LLVM::CondBrOp>(terminator)) {
518  // For conditional branches, we take the operands from either the "true" or
519  // the "false" branch.
520  return condBranchOp.getSuccessor(0) == current
521  ? condBranchOp.getTrueDestOperands()[index]
522  : condBranchOp.getFalseDestOperands()[index];
523  }
524 
525  if (auto switchOp = dyn_cast<LLVM::SwitchOp>(terminator)) {
526  // For switches, we take the operands from either the default case, or from
527  // the case branch that was taken.
528  if (switchOp.getDefaultDestination() == current)
529  return switchOp.getDefaultOperands()[index];
530  for (const auto &i : llvm::enumerate(switchOp.getCaseDestinations()))
531  if (i.value() == current)
532  return switchOp.getCaseOperands(i.index())[index];
533  }
534 
535  if (auto invokeOp = dyn_cast<LLVM::InvokeOp>(terminator)) {
536  return invokeOp.getNormalDest() == current
537  ? invokeOp.getNormalDestOperands()[index]
538  : invokeOp.getUnwindDestOperands()[index];
539  }
540 
541  llvm_unreachable(
542  "only branch, switch or invoke operations can be terminators "
543  "of a block that has successors");
544 }
545 
546 /// Connect the PHI nodes to the results of preceding blocks.
548  const ModuleTranslation &state) {
549  // Skip the first block, it cannot be branched to and its arguments correspond
550  // to the arguments of the LLVM function.
551  for (Block &bb : llvm::drop_begin(region)) {
552  llvm::BasicBlock *llvmBB = state.lookupBlock(&bb);
553  auto phis = llvmBB->phis();
554  auto numArguments = bb.getNumArguments();
555  assert(numArguments == std::distance(phis.begin(), phis.end()));
556  for (auto [index, phiNode] : llvm::enumerate(phis)) {
557  for (auto *pred : bb.getPredecessors()) {
558  // Find the LLVM IR block that contains the converted terminator
559  // instruction and use it in the PHI node. Note that this block is not
560  // necessarily the same as state.lookupBlock(pred), some operations
561  // (in particular, OpenMP operations using OpenMPIRBuilder) may have
562  // split the blocks.
563  llvm::Instruction *terminator =
564  state.lookupBranch(pred->getTerminator());
565  assert(terminator && "missing the mapping for a terminator");
566  phiNode.addIncoming(state.lookupValue(getPHISourceValue(
567  &bb, pred, numArguments, index)),
568  terminator->getParent());
569  }
570  }
571  }
572 }
573 
574 /// Sort function blocks topologically.
577  // For each block that has not been visited yet (i.e. that has no
578  // predecessors), add it to the list as well as its successors.
579  SetVector<Block *> blocks;
580  for (Block &b : region) {
581  if (blocks.count(&b) == 0) {
582  llvm::ReversePostOrderTraversal<Block *> traversal(&b);
583  blocks.insert(traversal.begin(), traversal.end());
584  }
585  }
586  assert(blocks.size() == region.getBlocks().size() &&
587  "some blocks are not sorted");
588 
589  return blocks;
590 }
591 
593  llvm::IRBuilderBase &builder, llvm::Intrinsic::ID intrinsic,
595  llvm::Module *module = builder.GetInsertBlock()->getModule();
596  llvm::Function *fn = llvm::Intrinsic::getDeclaration(module, intrinsic, tys);
597  return builder.CreateCall(fn, args);
598 }
599 
600 /// Given a single MLIR operation, create the corresponding LLVM IR operation
601 /// using the `builder`.
603 ModuleTranslation::convertOperation(Operation &op,
604  llvm::IRBuilderBase &builder) {
605  const LLVMTranslationDialectInterface *opIface = iface.getInterfaceFor(&op);
606  if (!opIface)
607  return op.emitError("cannot be converted to LLVM IR: missing "
608  "`LLVMTranslationDialectInterface` registration for "
609  "dialect for op: ")
610  << op.getName();
611 
612  if (failed(opIface->convertOperation(&op, builder, *this)))
613  return op.emitError("LLVM Translation failed for operation: ")
614  << op.getName();
615 
616  return convertDialectAttributes(&op);
617 }
618 
619 /// Convert block to LLVM IR. Unless `ignoreArguments` is set, emit PHI nodes
620 /// to define values corresponding to the MLIR block arguments. These nodes
621 /// are not connected to the source basic blocks, which may not exist yet. Uses
622 /// `builder` to construct the LLVM IR. Expects the LLVM IR basic block to have
623 /// been created for `bb` and included in the block mapping. Inserts new
624 /// instructions at the end of the block and leaves `builder` in a state
625 /// suitable for further insertion into the end of the block.
627  llvm::IRBuilderBase &builder) {
628  builder.SetInsertPoint(lookupBlock(&bb));
629  auto *subprogram = builder.GetInsertBlock()->getParent()->getSubprogram();
630 
631  // Before traversing operations, make block arguments available through
632  // value remapping and PHI nodes, but do not add incoming edges for the PHI
633  // nodes just yet: those values may be defined by this or following blocks.
634  // This step is omitted if "ignoreArguments" is set. The arguments of the
635  // first block have been already made available through the remapping of
636  // LLVM function arguments.
637  if (!ignoreArguments) {
638  auto predecessors = bb.getPredecessors();
639  unsigned numPredecessors =
640  std::distance(predecessors.begin(), predecessors.end());
641  for (auto arg : bb.getArguments()) {
642  auto wrappedType = arg.getType();
643  if (!isCompatibleType(wrappedType))
644  return emitError(bb.front().getLoc(),
645  "block argument does not have an LLVM type");
646  llvm::Type *type = convertType(wrappedType);
647  llvm::PHINode *phi = builder.CreatePHI(type, numPredecessors);
648  mapValue(arg, phi);
649  }
650  }
651 
652  // Traverse operations.
653  for (auto &op : bb) {
654  // Set the current debug location within the builder.
655  builder.SetCurrentDebugLocation(
656  debugTranslation->translateLoc(op.getLoc(), subprogram));
657 
658  if (failed(convertOperation(op, builder)))
659  return failure();
660 
661  // Set the branch weight metadata on the translated instruction.
662  if (auto iface = dyn_cast<BranchWeightOpInterface>(op))
664  }
665 
666  return success();
667 }
668 
669 /// A helper method to get the single Block in an operation honoring LLVM's
670 /// module requirements.
671 static Block &getModuleBody(Operation *module) {
672  return module->getRegion(0).front();
673 }
674 
675 /// A helper method to decide if a constant must not be set as a global variable
676 /// initializer. For an external linkage variable, the variable with an
677 /// initializer is considered externally visible and defined in this module, the
678 /// variable without an initializer is externally available and is defined
679 /// elsewhere.
680 static bool shouldDropGlobalInitializer(llvm::GlobalValue::LinkageTypes linkage,
681  llvm::Constant *cst) {
682  return (linkage == llvm::GlobalVariable::ExternalLinkage && !cst) ||
683  linkage == llvm::GlobalVariable::ExternalWeakLinkage;
684 }
685 
686 /// Sets the runtime preemption specifier of `gv` to dso_local if
687 /// `dsoLocalRequested` is true, otherwise it is left unchanged.
688 static void addRuntimePreemptionSpecifier(bool dsoLocalRequested,
689  llvm::GlobalValue *gv) {
690  if (dsoLocalRequested)
691  gv->setDSOLocal(true);
692 }
693 
694 /// Create named global variables that correspond to llvm.mlir.global
695 /// definitions. Convert llvm.global_ctors and global_dtors ops.
696 LogicalResult ModuleTranslation::convertGlobals() {
697  for (auto op : getModuleBody(mlirModule).getOps<LLVM::GlobalOp>()) {
698  llvm::Type *type = convertType(op.getType());
699  llvm::Constant *cst = nullptr;
700  if (op.getValueOrNull()) {
701  // String attributes are treated separately because they cannot appear as
702  // in-function constants and are thus not supported by getLLVMConstant.
703  if (auto strAttr = dyn_cast_or_null<StringAttr>(op.getValueOrNull())) {
704  cst = llvm::ConstantDataArray::getString(
705  llvmModule->getContext(), strAttr.getValue(), /*AddNull=*/false);
706  type = cst->getType();
707  } else if (!(cst = getLLVMConstant(type, op.getValueOrNull(), op.getLoc(),
708  *this))) {
709  return failure();
710  }
711  }
712 
713  auto linkage = convertLinkageToLLVM(op.getLinkage());
714  auto addrSpace = op.getAddrSpace();
715 
716  // LLVM IR requires constant with linkage other than external or weak
717  // external to have initializers. If MLIR does not provide an initializer,
718  // default to undef.
719  bool dropInitializer = shouldDropGlobalInitializer(linkage, cst);
720  if (!dropInitializer && !cst)
721  cst = llvm::UndefValue::get(type);
722  else if (dropInitializer && cst)
723  cst = nullptr;
724 
725  auto *var = new llvm::GlobalVariable(
726  *llvmModule, type, op.getConstant(), linkage, cst, op.getSymName(),
727  /*InsertBefore=*/nullptr,
728  op.getThreadLocal_() ? llvm::GlobalValue::GeneralDynamicTLSModel
729  : llvm::GlobalValue::NotThreadLocal,
730  addrSpace);
731 
732  if (std::optional<mlir::SymbolRefAttr> comdat = op.getComdat()) {
733  auto selectorOp = cast<ComdatSelectorOp>(
735  var->setComdat(comdatMapping.lookup(selectorOp));
736  }
737 
738  if (op.getUnnamedAddr().has_value())
739  var->setUnnamedAddr(convertUnnamedAddrToLLVM(*op.getUnnamedAddr()));
740 
741  if (op.getSection().has_value())
742  var->setSection(*op.getSection());
743 
744  addRuntimePreemptionSpecifier(op.getDsoLocal(), var);
745 
746  std::optional<uint64_t> alignment = op.getAlignment();
747  if (alignment.has_value())
748  var->setAlignment(llvm::MaybeAlign(alignment.value()));
749 
750  var->setVisibility(convertVisibilityToLLVM(op.getVisibility_()));
751 
752  globalsMapping.try_emplace(op, var);
753  }
754 
755  // Convert global variable bodies. This is done after all global variables
756  // have been created in LLVM IR because a global body may refer to another
757  // global or itself. So all global variables need to be mapped first.
758  for (auto op : getModuleBody(mlirModule).getOps<LLVM::GlobalOp>()) {
759  if (Block *initializer = op.getInitializerBlock()) {
760  llvm::IRBuilder<> builder(llvmModule->getContext());
761  for (auto &op : initializer->without_terminator()) {
762  if (failed(convertOperation(op, builder)) ||
763  !isa<llvm::Constant>(lookupValue(op.getResult(0))))
764  return emitError(op.getLoc(), "unemittable constant value");
765  }
766  ReturnOp ret = cast<ReturnOp>(initializer->getTerminator());
767  llvm::Constant *cst =
768  cast<llvm::Constant>(lookupValue(ret.getOperand(0)));
769  auto *global = cast<llvm::GlobalVariable>(lookupGlobal(op));
770  if (!shouldDropGlobalInitializer(global->getLinkage(), cst))
771  global->setInitializer(cst);
772  }
773  }
774 
775  // Convert llvm.mlir.global_ctors and dtors.
776  for (Operation &op : getModuleBody(mlirModule)) {
777  auto ctorOp = dyn_cast<GlobalCtorsOp>(op);
778  auto dtorOp = dyn_cast<GlobalDtorsOp>(op);
779  if (!ctorOp && !dtorOp)
780  continue;
781  auto range = ctorOp ? llvm::zip(ctorOp.getCtors(), ctorOp.getPriorities())
782  : llvm::zip(dtorOp.getDtors(), dtorOp.getPriorities());
783  auto appendGlobalFn =
784  ctorOp ? llvm::appendToGlobalCtors : llvm::appendToGlobalDtors;
785  for (auto symbolAndPriority : range) {
786  llvm::Function *f = lookupFunction(
787  cast<FlatSymbolRefAttr>(std::get<0>(symbolAndPriority)).getValue());
788  appendGlobalFn(*llvmModule, f,
789  cast<IntegerAttr>(std::get<1>(symbolAndPriority)).getInt(),
790  /*Data=*/nullptr);
791  }
792  }
793 
794  for (auto op : getModuleBody(mlirModule).getOps<LLVM::GlobalOp>())
795  if (failed(convertDialectAttributes(op)))
796  return failure();
797 
798  return success();
799 }
800 
801 /// Attempts to add an attribute identified by `key`, optionally with the given
802 /// `value` to LLVM function `llvmFunc`. Reports errors at `loc` if any. If the
803 /// attribute has a kind known to LLVM IR, create the attribute of this kind,
804 /// otherwise keep it as a string attribute. Performs additional checks for
805 /// attributes known to have or not have a value in order to avoid assertions
806 /// inside LLVM upon construction.
808  llvm::Function *llvmFunc,
809  StringRef key,
810  StringRef value = StringRef()) {
811  auto kind = llvm::Attribute::getAttrKindFromName(key);
812  if (kind == llvm::Attribute::None) {
813  llvmFunc->addFnAttr(key, value);
814  return success();
815  }
816 
817  if (llvm::Attribute::isIntAttrKind(kind)) {
818  if (value.empty())
819  return emitError(loc) << "LLVM attribute '" << key << "' expects a value";
820 
821  int64_t result;
822  if (!value.getAsInteger(/*Radix=*/0, result))
823  llvmFunc->addFnAttr(
824  llvm::Attribute::get(llvmFunc->getContext(), kind, result));
825  else
826  llvmFunc->addFnAttr(key, value);
827  return success();
828  }
829 
830  if (!value.empty())
831  return emitError(loc) << "LLVM attribute '" << key
832  << "' does not expect a value, found '" << value
833  << "'";
834 
835  llvmFunc->addFnAttr(kind);
836  return success();
837 }
838 
839 /// Attaches the attributes listed in the given array attribute to `llvmFunc`.
840 /// Reports error to `loc` if any and returns immediately. Expects `attributes`
841 /// to be an array attribute containing either string attributes, treated as
842 /// value-less LLVM attributes, or array attributes containing two string
843 /// attributes, with the first string being the name of the corresponding LLVM
844 /// attribute and the second string beings its value. Note that even integer
845 /// attributes are expected to have their values expressed as strings.
846 static LogicalResult
847 forwardPassthroughAttributes(Location loc, std::optional<ArrayAttr> attributes,
848  llvm::Function *llvmFunc) {
849  if (!attributes)
850  return success();
851 
852  for (Attribute attr : *attributes) {
853  if (auto stringAttr = dyn_cast<StringAttr>(attr)) {
854  if (failed(
855  checkedAddLLVMFnAttribute(loc, llvmFunc, stringAttr.getValue())))
856  return failure();
857  continue;
858  }
859 
860  auto arrayAttr = dyn_cast<ArrayAttr>(attr);
861  if (!arrayAttr || arrayAttr.size() != 2)
862  return emitError(loc)
863  << "expected 'passthrough' to contain string or array attributes";
864 
865  auto keyAttr = dyn_cast<StringAttr>(arrayAttr[0]);
866  auto valueAttr = dyn_cast<StringAttr>(arrayAttr[1]);
867  if (!keyAttr || !valueAttr)
868  return emitError(loc)
869  << "expected arrays within 'passthrough' to contain two strings";
870 
871  if (failed(checkedAddLLVMFnAttribute(loc, llvmFunc, keyAttr.getValue(),
872  valueAttr.getValue())))
873  return failure();
874  }
875  return success();
876 }
877 
878 LogicalResult ModuleTranslation::convertOneFunction(LLVMFuncOp func) {
879  // Clear the block, branch value mappings, they are only relevant within one
880  // function.
881  blockMapping.clear();
882  valueMapping.clear();
883  branchMapping.clear();
884  llvm::Function *llvmFunc = lookupFunction(func.getName());
885 
886  // Translate the debug information for this function.
887  debugTranslation->translate(func, *llvmFunc);
888 
889  // Add function arguments to the value remapping table.
890  for (auto [mlirArg, llvmArg] :
891  llvm::zip(func.getArguments(), llvmFunc->args()))
892  mapValue(mlirArg, &llvmArg);
893 
894  // Check the personality and set it.
895  if (func.getPersonality()) {
896  llvm::Type *ty = llvm::Type::getInt8PtrTy(llvmFunc->getContext());
897  if (llvm::Constant *pfunc = getLLVMConstant(ty, func.getPersonalityAttr(),
898  func.getLoc(), *this))
899  llvmFunc->setPersonalityFn(pfunc);
900  }
901 
902  if (std::optional<StringRef> section = func.getSection())
903  llvmFunc->setSection(*section);
904 
905  if (func.getArmStreaming())
906  llvmFunc->addFnAttr("aarch64_pstate_sm_enabled");
907  else if (func.getArmLocallyStreaming())
908  llvmFunc->addFnAttr("aarch64_pstate_sm_body");
909 
910  if (auto attr = func.getVscaleRange())
911  llvmFunc->addFnAttr(llvm::Attribute::getWithVScaleRangeArgs(
912  getLLVMContext(), attr->getMinRange().getInt(),
913  attr->getMaxRange().getInt()));
914 
915  // First, create all blocks so we can jump to them.
916  llvm::LLVMContext &llvmContext = llvmFunc->getContext();
917  for (auto &bb : func) {
918  auto *llvmBB = llvm::BasicBlock::Create(llvmContext);
919  llvmBB->insertInto(llvmFunc);
920  mapBlock(&bb, llvmBB);
921  }
922 
923  // Then, convert blocks one by one in topological order to ensure defs are
924  // converted before uses.
925  auto blocks = detail::getTopologicallySortedBlocks(func.getBody());
926  for (Block *bb : blocks) {
927  llvm::IRBuilder<> builder(llvmContext);
928  if (failed(convertBlock(*bb, bb->isEntryBlock(), builder)))
929  return failure();
930  }
931 
932  // After all blocks have been traversed and values mapped, connect the PHI
933  // nodes to the results of preceding blocks.
934  detail::connectPHINodes(func.getBody(), *this);
935 
936  // Finally, convert dialect attributes attached to the function.
937  return convertDialectAttributes(func);
938 }
939 
940 LogicalResult ModuleTranslation::convertDialectAttributes(Operation *op) {
941  for (NamedAttribute attribute : op->getDialectAttrs())
942  if (failed(iface.amendOperation(op, attribute, *this)))
943  return failure();
944  return success();
945 }
946 
947 /// Converts the function attributes from LLVMFuncOp and attaches them to the
948 /// llvm::Function.
949 static void convertFunctionAttributes(LLVMFuncOp func,
950  llvm::Function *llvmFunc) {
951  if (!func.getMemory())
952  return;
953 
954  MemoryEffectsAttr memEffects = func.getMemoryAttr();
955 
956  // Add memory effects incrementally.
957  llvm::MemoryEffects newMemEffects =
958  llvm::MemoryEffects(llvm::MemoryEffects::Location::ArgMem,
959  convertModRefInfoToLLVM(memEffects.getArgMem()));
960  newMemEffects |= llvm::MemoryEffects(
961  llvm::MemoryEffects::Location::InaccessibleMem,
962  convertModRefInfoToLLVM(memEffects.getInaccessibleMem()));
963  newMemEffects |=
964  llvm::MemoryEffects(llvm::MemoryEffects::Location::Other,
965  convertModRefInfoToLLVM(memEffects.getOther()));
966  llvmFunc->setMemoryEffects(newMemEffects);
967 }
968 
969 llvm::AttrBuilder
970 ModuleTranslation::convertParameterAttrs(DictionaryAttr paramAttrs) {
971  llvm::AttrBuilder attrBuilder(llvmModule->getContext());
972 
973  for (auto [llvmKind, mlirName] : getAttrKindToNameMapping()) {
974  Attribute attr = paramAttrs.get(mlirName);
975  // Skip attributes that are not present.
976  if (!attr)
977  continue;
978 
979  // NOTE: C++17 does not support capturing structured bindings.
980  llvm::Attribute::AttrKind llvmKindCap = llvmKind;
981 
983  .Case<TypeAttr>([&](auto typeAttr) {
984  attrBuilder.addTypeAttr(llvmKindCap,
985  convertType(typeAttr.getValue()));
986  })
987  .Case<IntegerAttr>([&](auto intAttr) {
988  attrBuilder.addRawIntAttr(llvmKindCap, intAttr.getInt());
989  })
990  .Case<UnitAttr>([&](auto) { attrBuilder.addAttribute(llvmKindCap); });
991  }
992 
993  return attrBuilder;
994 }
995 
996 LogicalResult ModuleTranslation::convertFunctionSignatures() {
997  // Declare all functions first because there may be function calls that form a
998  // call graph with cycles, or global initializers that reference functions.
999  for (auto function : getModuleBody(mlirModule).getOps<LLVMFuncOp>()) {
1000  llvm::FunctionCallee llvmFuncCst = llvmModule->getOrInsertFunction(
1001  function.getName(),
1002  cast<llvm::FunctionType>(convertType(function.getFunctionType())));
1003  llvm::Function *llvmFunc = cast<llvm::Function>(llvmFuncCst.getCallee());
1004  llvmFunc->setLinkage(convertLinkageToLLVM(function.getLinkage()));
1005  llvmFunc->setCallingConv(convertCConvToLLVM(function.getCConv()));
1006  mapFunction(function.getName(), llvmFunc);
1007  addRuntimePreemptionSpecifier(function.getDsoLocal(), llvmFunc);
1008 
1009  // Convert function attributes.
1010  convertFunctionAttributes(function, llvmFunc);
1011 
1012  // Convert function_entry_count attribute to metadata.
1013  if (std::optional<uint64_t> entryCount = function.getFunctionEntryCount())
1014  llvmFunc->setEntryCount(entryCount.value());
1015 
1016  // Convert result attributes.
1017  if (ArrayAttr allResultAttrs = function.getAllResultAttrs()) {
1018  DictionaryAttr resultAttrs = cast<DictionaryAttr>(allResultAttrs[0]);
1019  llvmFunc->addRetAttrs(convertParameterAttrs(resultAttrs));
1020  }
1021 
1022  // Convert argument attributes.
1023  for (auto [argIdx, llvmArg] : llvm::enumerate(llvmFunc->args())) {
1024  if (DictionaryAttr argAttrs = function.getArgAttrDict(argIdx)) {
1025  llvm::AttrBuilder attrBuilder = convertParameterAttrs(argAttrs);
1026  llvmArg.addAttrs(attrBuilder);
1027  }
1028  }
1029 
1030  // Forward the pass-through attributes to LLVM.
1032  function.getLoc(), function.getPassthrough(), llvmFunc)))
1033  return failure();
1034 
1035  // Convert visibility attribute.
1036  llvmFunc->setVisibility(convertVisibilityToLLVM(function.getVisibility_()));
1037 
1038  // Convert the comdat attribute.
1039  if (std::optional<mlir::SymbolRefAttr> comdat = function.getComdat()) {
1040  auto selectorOp = cast<ComdatSelectorOp>(
1041  SymbolTable::lookupNearestSymbolFrom(function, *comdat));
1042  llvmFunc->setComdat(comdatMapping.lookup(selectorOp));
1043  }
1044 
1045  if (auto gc = function.getGarbageCollector())
1046  llvmFunc->setGC(gc->str());
1047 
1048  if (auto unnamedAddr = function.getUnnamedAddr())
1049  llvmFunc->setUnnamedAddr(convertUnnamedAddrToLLVM(*unnamedAddr));
1050 
1051  if (auto alignment = function.getAlignment())
1052  llvmFunc->setAlignment(llvm::MaybeAlign(*alignment));
1053  }
1054 
1055  return success();
1056 }
1057 
1058 LogicalResult ModuleTranslation::convertFunctions() {
1059  // Convert functions.
1060  for (auto function : getModuleBody(mlirModule).getOps<LLVMFuncOp>()) {
1061  // Do not convert external functions, but do process dialect attributes
1062  // attached to them.
1063  if (function.isExternal()) {
1064  if (failed(convertDialectAttributes(function)))
1065  return failure();
1066  continue;
1067  }
1068 
1069  if (failed(convertOneFunction(function)))
1070  return failure();
1071  }
1072 
1073  return success();
1074 }
1075 
1076 LogicalResult ModuleTranslation::convertComdats() {
1077  for (auto comdatOp : getModuleBody(mlirModule).getOps<ComdatOp>()) {
1078  for (auto selectorOp : comdatOp.getOps<ComdatSelectorOp>()) {
1079  llvm::Module *module = getLLVMModule();
1080  if (module->getComdatSymbolTable().contains(selectorOp.getSymName()))
1081  return emitError(selectorOp.getLoc())
1082  << "comdat selection symbols must be unique even in different "
1083  "comdat regions";
1084  llvm::Comdat *comdat = module->getOrInsertComdat(selectorOp.getSymName());
1085  comdat->setSelectionKind(convertComdatToLLVM(selectorOp.getComdat()));
1086  comdatMapping.try_emplace(selectorOp, comdat);
1087  }
1088  }
1089  return success();
1090 }
1091 
1092 void ModuleTranslation::setAccessGroupsMetadata(AccessGroupOpInterface op,
1093  llvm::Instruction *inst) {
1094  if (llvm::MDNode *node = loopAnnotationTranslation->getAccessGroups(op))
1095  inst->setMetadata(llvm::LLVMContext::MD_access_group, node);
1096 }
1097 
1098 llvm::MDNode *
1099 ModuleTranslation::getOrCreateAliasScope(AliasScopeAttr aliasScopeAttr) {
1100  auto [scopeIt, scopeInserted] =
1101  aliasScopeMetadataMapping.try_emplace(aliasScopeAttr, nullptr);
1102  if (!scopeInserted)
1103  return scopeIt->second;
1104  llvm::LLVMContext &ctx = llvmModule->getContext();
1105  // Convert the domain metadata node if necessary.
1106  auto [domainIt, insertedDomain] = aliasDomainMetadataMapping.try_emplace(
1107  aliasScopeAttr.getDomain(), nullptr);
1108  if (insertedDomain) {
1110  // Placeholder for self-reference.
1111  operands.push_back({});
1112  if (StringAttr description = aliasScopeAttr.getDomain().getDescription())
1113  operands.push_back(llvm::MDString::get(ctx, description));
1114  domainIt->second = llvm::MDNode::get(ctx, operands);
1115  // Self-reference for uniqueness.
1116  domainIt->second->replaceOperandWith(0, domainIt->second);
1117  }
1118  // Convert the scope metadata node.
1119  assert(domainIt->second && "Scope's domain should already be valid");
1121  // Placeholder for self-reference.
1122  operands.push_back({});
1123  operands.push_back(domainIt->second);
1124  if (StringAttr description = aliasScopeAttr.getDescription())
1125  operands.push_back(llvm::MDString::get(ctx, description));
1126  scopeIt->second = llvm::MDNode::get(ctx, operands);
1127  // Self-reference for uniqueness.
1128  scopeIt->second->replaceOperandWith(0, scopeIt->second);
1129  return scopeIt->second;
1130 }
1131 
1133  ArrayRef<AliasScopeAttr> aliasScopeAttrs) {
1135  nodes.reserve(aliasScopeAttrs.size());
1136  for (AliasScopeAttr aliasScopeAttr : aliasScopeAttrs)
1137  nodes.push_back(getOrCreateAliasScope(aliasScopeAttr));
1138  return llvm::MDNode::get(getLLVMContext(), nodes);
1139 }
1140 
1141 void ModuleTranslation::setAliasScopeMetadata(AliasAnalysisOpInterface op,
1142  llvm::Instruction *inst) {
1143  auto populateScopeMetadata = [&](ArrayAttr aliasScopeAttrs, unsigned kind) {
1144  if (!aliasScopeAttrs || aliasScopeAttrs.empty())
1145  return;
1146  llvm::MDNode *node = getOrCreateAliasScopes(
1147  llvm::to_vector(aliasScopeAttrs.getAsRange<AliasScopeAttr>()));
1148  inst->setMetadata(kind, node);
1149  };
1150 
1151  populateScopeMetadata(op.getAliasScopesOrNull(),
1152  llvm::LLVMContext::MD_alias_scope);
1153  populateScopeMetadata(op.getNoAliasScopesOrNull(),
1154  llvm::LLVMContext::MD_noalias);
1155 }
1156 
1157 llvm::MDNode *ModuleTranslation::getTBAANode(TBAATagAttr tbaaAttr) const {
1158  return tbaaMetadataMapping.lookup(tbaaAttr);
1159 }
1160 
1161 void ModuleTranslation::setTBAAMetadata(AliasAnalysisOpInterface op,
1162  llvm::Instruction *inst) {
1163  ArrayAttr tagRefs = op.getTBAATagsOrNull();
1164  if (!tagRefs || tagRefs.empty())
1165  return;
1166 
1167  // LLVM IR currently does not support attaching more than one TBAA access tag
1168  // to a memory accessing instruction. It may be useful to support this in
1169  // future, but for the time being just ignore the metadata if MLIR operation
1170  // has multiple access tags.
1171  if (tagRefs.size() > 1) {
1172  op.emitWarning() << "TBAA access tags were not translated, because LLVM "
1173  "IR only supports a single tag per instruction";
1174  return;
1175  }
1176 
1177  llvm::MDNode *node = getTBAANode(cast<TBAATagAttr>(tagRefs[0]));
1178  inst->setMetadata(llvm::LLVMContext::MD_tbaa, node);
1179 }
1180 
1181 void ModuleTranslation::setBranchWeightsMetadata(BranchWeightOpInterface op) {
1182  DenseI32ArrayAttr weightsAttr = op.getBranchWeightsOrNull();
1183  if (!weightsAttr)
1184  return;
1185 
1186  llvm::Instruction *inst = isa<CallOp>(op) ? lookupCall(op) : lookupBranch(op);
1187  assert(inst && "expected the operation to have a mapping to an instruction");
1188  SmallVector<uint32_t> weights(weightsAttr.asArrayRef());
1189  inst->setMetadata(
1190  llvm::LLVMContext::MD_prof,
1191  llvm::MDBuilder(getLLVMContext()).createBranchWeights(weights));
1192 }
1193 
1194 LogicalResult ModuleTranslation::createTBAAMetadata() {
1195  llvm::LLVMContext &ctx = llvmModule->getContext();
1196  llvm::IntegerType *offsetTy = llvm::IntegerType::get(ctx, 64);
1197 
1198  // Walk the entire module and create all metadata nodes for the TBAA
1199  // attributes. The code below relies on two invariants of the
1200  // `AttrTypeWalker`:
1201  // 1. Attributes are visited in post-order: Since the attributes create a DAG,
1202  // this ensures that any lookups into `tbaaMetadataMapping` for child
1203  // attributes succeed.
1204  // 2. Attributes are only ever visited once: This way we don't leak any
1205  // LLVM metadata instances.
1206  AttrTypeWalker walker;
1207  walker.addWalk([&](TBAARootAttr root) {
1208  tbaaMetadataMapping.insert(
1209  {root, llvm::MDNode::get(ctx, llvm::MDString::get(ctx, root.getId()))});
1210  });
1211 
1212  walker.addWalk([&](TBAATypeDescriptorAttr descriptor) {
1214  operands.push_back(llvm::MDString::get(ctx, descriptor.getId()));
1215  for (TBAAMemberAttr member : descriptor.getMembers()) {
1216  operands.push_back(tbaaMetadataMapping.lookup(member.getTypeDesc()));
1217  operands.push_back(llvm::ConstantAsMetadata::get(
1218  llvm::ConstantInt::get(offsetTy, member.getOffset())));
1219  }
1220 
1221  tbaaMetadataMapping.insert({descriptor, llvm::MDNode::get(ctx, operands)});
1222  });
1223 
1224  walker.addWalk([&](TBAATagAttr tag) {
1226 
1227  operands.push_back(tbaaMetadataMapping.lookup(tag.getBaseType()));
1228  operands.push_back(tbaaMetadataMapping.lookup(tag.getAccessType()));
1229 
1230  operands.push_back(llvm::ConstantAsMetadata::get(
1231  llvm::ConstantInt::get(offsetTy, tag.getOffset())));
1232  if (tag.getConstant())
1233  operands.push_back(
1235 
1236  tbaaMetadataMapping.insert({tag, llvm::MDNode::get(ctx, operands)});
1237  });
1238 
1239  mlirModule->walk([&](AliasAnalysisOpInterface analysisOpInterface) {
1240  if (auto attr = analysisOpInterface.getTBAATagsOrNull())
1241  walker.walk(attr);
1242  });
1243 
1244  return success();
1245 }
1246 
1248  llvm::Instruction *inst) {
1249  LoopAnnotationAttr attr =
1251  .Case<LLVM::BrOp, LLVM::CondBrOp>(
1252  [](auto branchOp) { return branchOp.getLoopAnnotationAttr(); });
1253  if (!attr)
1254  return;
1255  llvm::MDNode *loopMD =
1256  loopAnnotationTranslation->translateLoopAnnotation(attr, op);
1257  inst->setMetadata(llvm::LLVMContext::MD_loop, loopMD);
1258 }
1259 
1261  return typeTranslator.translateType(type);
1262 }
1263 
1264 /// A helper to look up remapped operands in the value remapping table.
1266  SmallVector<llvm::Value *> remapped;
1267  remapped.reserve(values.size());
1268  for (Value v : values)
1269  remapped.push_back(lookupValue(v));
1270  return remapped;
1271 }
1272 
1273 llvm::OpenMPIRBuilder *ModuleTranslation::getOpenMPBuilder() {
1274  if (!ompBuilder) {
1275  ompBuilder = std::make_unique<llvm::OpenMPIRBuilder>(*llvmModule);
1276  ompBuilder->initialize();
1277 
1278  // Flags represented as top-level OpenMP dialect attributes are set in
1279  // `OpenMPDialectLLVMIRTranslationInterface::amendOperation()`. Here we set
1280  // the default configuration.
1281  ompBuilder->setConfig(llvm::OpenMPIRBuilderConfig(
1282  /* IsTargetDevice = */ false, /* IsGPU = */ false,
1283  /* OpenMPOffloadMandatory = */ false,
1284  /* HasRequiresReverseOffload = */ false,
1285  /* HasRequiresUnifiedAddress = */ false,
1286  /* HasRequiresUnifiedSharedMemory = */ false,
1287  /* HasRequiresDynamicAllocators = */ false));
1288  }
1289  return ompBuilder.get();
1290 }
1291 
1293  llvm::DILocalScope *scope) {
1294  return debugTranslation->translateLoc(loc, scope);
1295 }
1296 
1298  return debugTranslation->translate(attr);
1299 }
1300 
1301 llvm::NamedMDNode *
1303  return llvmModule->getOrInsertNamedMetadata(name);
1304 }
1305 
1306 void ModuleTranslation::StackFrame::anchor() {}
1307 
1308 static std::unique_ptr<llvm::Module>
1309 prepareLLVMModule(Operation *m, llvm::LLVMContext &llvmContext,
1310  StringRef name) {
1311  m->getContext()->getOrLoadDialect<LLVM::LLVMDialect>();
1312  auto llvmModule = std::make_unique<llvm::Module>(name, llvmContext);
1313  if (auto dataLayoutAttr =
1314  m->getDiscardableAttr(LLVM::LLVMDialect::getDataLayoutAttrName())) {
1315  llvmModule->setDataLayout(cast<StringAttr>(dataLayoutAttr).getValue());
1316  } else {
1317  FailureOr<llvm::DataLayout> llvmDataLayout(llvm::DataLayout(""));
1318  if (auto iface = dyn_cast<DataLayoutOpInterface>(m)) {
1319  if (DataLayoutSpecInterface spec = iface.getDataLayoutSpec()) {
1320  llvmDataLayout =
1321  translateDataLayout(spec, DataLayout(iface), m->getLoc());
1322  }
1323  } else if (auto mod = dyn_cast<ModuleOp>(m)) {
1324  if (DataLayoutSpecInterface spec = mod.getDataLayoutSpec()) {
1325  llvmDataLayout =
1326  translateDataLayout(spec, DataLayout(mod), m->getLoc());
1327  }
1328  }
1329  if (failed(llvmDataLayout))
1330  return nullptr;
1331  llvmModule->setDataLayout(*llvmDataLayout);
1332  }
1333  if (auto targetTripleAttr =
1334  m->getDiscardableAttr(LLVM::LLVMDialect::getTargetTripleAttrName()))
1335  llvmModule->setTargetTriple(cast<StringAttr>(targetTripleAttr).getValue());
1336 
1337  // Inject declarations for `malloc` and `free` functions that can be used in
1338  // memref allocation/deallocation coming from standard ops lowering.
1339  llvm::IRBuilder<> builder(llvmContext);
1340  llvmModule->getOrInsertFunction("malloc", builder.getInt8PtrTy(),
1341  builder.getInt64Ty());
1342  llvmModule->getOrInsertFunction("free", builder.getVoidTy(),
1343  builder.getInt8PtrTy());
1344 
1345  return llvmModule;
1346 }
1347 
1348 std::unique_ptr<llvm::Module>
1349 mlir::translateModuleToLLVMIR(Operation *module, llvm::LLVMContext &llvmContext,
1350  StringRef name) {
1351  if (!satisfiesLLVMModule(module)) {
1352  module->emitOpError("can not be translated to an LLVMIR module");
1353  return nullptr;
1354  }
1355 
1356  std::unique_ptr<llvm::Module> llvmModule =
1357  prepareLLVMModule(module, llvmContext, name);
1358  if (!llvmModule)
1359  return nullptr;
1360 
1362 
1363  ModuleTranslation translator(module, std::move(llvmModule));
1364  llvm::IRBuilder<> llvmBuilder(llvmContext);
1365 
1366  // Convert module before functions and operations inside, so dialect
1367  // attributes can be used to change dialect-specific global configurations via
1368  // `amendOperation()`. These configurations can then influence the translation
1369  // of operations afterwards.
1370  if (failed(translator.convertOperation(*module, llvmBuilder)))
1371  return nullptr;
1372 
1373  if (failed(translator.convertComdats()))
1374  return nullptr;
1375  if (failed(translator.convertFunctionSignatures()))
1376  return nullptr;
1377  if (failed(translator.convertGlobals()))
1378  return nullptr;
1379  if (failed(translator.createTBAAMetadata()))
1380  return nullptr;
1381 
1382  // Convert other top-level operations if possible.
1383  for (Operation &o : getModuleBody(module).getOperations()) {
1384  if (!isa<LLVM::LLVMFuncOp, LLVM::GlobalOp, LLVM::GlobalCtorsOp,
1385  LLVM::GlobalDtorsOp, LLVM::ComdatOp>(&o) &&
1386  !o.hasTrait<OpTrait::IsTerminator>() &&
1387  failed(translator.convertOperation(o, llvmBuilder))) {
1388  return nullptr;
1389  }
1390  }
1391 
1392  // Operations in function bodies with symbolic references must be converted
1393  // after the top-level operations they refer to are declared, so we do it
1394  // last.
1395  if (failed(translator.convertFunctions()))
1396  return nullptr;
1397 
1398  if (llvm::verifyModule(*translator.llvmModule, &llvm::errs()))
1399  return nullptr;
1400 
1401  return std::move(translator.llvmModule);
1402 }
static MLIRContext * getContext(OpFoldResult val)
@ None
static Value getPHISourceValue(Block *current, Block *pred, unsigned numArguments, unsigned index)
Get the SSA value passed to the current block from the terminator operation of its predecessor.
static llvm::Constant * convertDenseElementsAttr(Location loc, DenseElementsAttr denseElementsAttr, llvm::Type *llvmType, const ModuleTranslation &moduleTranslation)
Convert a dense elements attribute to an LLVM IR constant using its raw data storage if possible.
static Block & getModuleBody(Operation *module)
A helper method to get the single Block in an operation honoring LLVM's module requirements.
static void addRuntimePreemptionSpecifier(bool dsoLocalRequested, llvm::GlobalValue *gv)
Sets the runtime preemption specifier of gv to dso_local if dsoLocalRequested is true,...
static LogicalResult checkedAddLLVMFnAttribute(Location loc, llvm::Function *llvmFunc, StringRef key, StringRef value=StringRef())
Attempts to add an attribute identified by key, optionally with the given value to LLVM function llvm...
static void convertFunctionAttributes(LLVMFuncOp func, llvm::Function *llvmFunc)
Converts the function attributes from LLVMFuncOp and attaches them to the llvm::Function.
static bool shouldDropGlobalInitializer(llvm::GlobalValue::LinkageTypes linkage, llvm::Constant *cst)
A helper method to decide if a constant must not be set as a global variable initializer.
static llvm::Type * getInnermostElementType(llvm::Type *type)
Returns the first non-sequential type nested in sequential types.
static std::unique_ptr< llvm::Module > prepareLLVMModule(Operation *m, llvm::LLVMContext &llvmContext, StringRef name)
static LogicalResult forwardPassthroughAttributes(Location loc, std::optional< ArrayAttr > attributes, llvm::Function *llvmFunc)
Attaches the attributes listed in the given array attribute to llvmFunc.
static llvm::Constant * buildSequentialConstant(ArrayRef< llvm::Constant * > &constants, ArrayRef< int64_t > shape, llvm::Type *type, Location loc)
Builds a constant of a sequential LLVM type type, potentially containing other sequential types recur...
void addWalk(WalkFn< Attribute > &&fn)
Register a walk function for a given attribute or type.
WalkResult walk(T element)
Walk the given attribute/type, and recursively walk any sub elements.
Attributes are known-constant values of operations.
Definition: Attributes.h:25
Block represents an ordered list of Operations.
Definition: Block.h:30
Operation * getTerminator()
Get the terminator operation of this block.
Definition: Block.cpp:238
iterator_range< pred_iterator > getPredecessors()
Definition: Block.h:230
BlockArgListType getArguments()
Definition: Block.h:80
Operation & front()
Definition: Block.h:146
The main mechanism for performing data layout queries.
unsigned getTypeABIAlignment(Type t) const
Returns the required alignment of the given type in the current scope.
unsigned getTypeSizeInBits(Type t) const
Returns the size in bits of the given type in the current scope.
unsigned getTypePreferredAlignment(Type t) const
Returns the preferred of the given type in the current scope.
An attribute that represents a reference to a dense vector or tensor object.
std::enable_if_t<!std::is_base_of< Attribute, T >::value||std::is_same< Attribute, T >::value, T > getSplatValue() const
Return the splat value for this attribute.
int64_t getNumElements() const
Returns the number of elements held by this attribute.
bool isSplat() const
Returns true if this attribute corresponds to a splat, i.e.
ArrayRef< char > getRawData() const
Return the raw storage data held by this attribute.
ShapedType getType() const
Return the type of this ElementsAttr, guaranteed to be a vector or tensor with static shape.
const InterfaceType * getInterfaceFor(Object *obj) const
Get the interface for a given object, or null if one is not registered.
This class provides support for representing a failure result, or a valid value of type T.
Definition: LogicalResult.h:78
Base class for dialect interfaces providing translation to LLVM IR.
virtual LogicalResult convertOperation(Operation *op, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation) const
Hook for derived dialect interface to provide translation of the operations to LLVM IR.
virtual LogicalResult amendOperation(Operation *op, NamedAttribute attribute, LLVM::ModuleTranslation &moduleTranslation) const
Acts on the given operation using the interface implemented by the dialect of one of the operation's ...
This class represents the base attribute for all debug info attributes.
Definition: LLVMAttrs.h:27
Implementation class for module translation.
LogicalResult convertBlock(Block &bb, bool ignoreArguments, llvm::IRBuilderBase &builder)
Translates the contents of the given block to LLVM IR using this translator.
llvm::Value * lookupValue(Value value) const
Finds an LLVM IR value corresponding to the given MLIR value.
llvm::NamedMDNode * getOrInsertNamedModuleMetadata(StringRef name)
Gets the named metadata in the LLVM IR module being constructed, creating it if it does not exist.
llvm::Instruction * lookupBranch(Operation *op) const
Finds an LLVM IR instruction that corresponds to the given MLIR operation with successors.
SmallVector< llvm::Value * > lookupValues(ValueRange values)
Looks up remapped a list of remapped values.
void mapFunction(StringRef name, llvm::Function *func)
Stores the mapping between a function name and its LLVM IR representation.
llvm::DILocation * translateLoc(Location loc, llvm::DILocalScope *scope)
Translates the given location.
llvm::BasicBlock * lookupBlock(Block *block) const
Finds an LLVM IR basic block that corresponds to the given MLIR block.
void setBranchWeightsMetadata(BranchWeightOpInterface op)
Sets LLVM profiling metadata for operations that have branch weights.
llvm::Type * convertType(Type type)
Converts the type from MLIR LLVM dialect to LLVM.
void setTBAAMetadata(AliasAnalysisOpInterface op, llvm::Instruction *inst)
Sets LLVM TBAA metadata for memory operations that have TBAA attributes.
llvm::OpenMPIRBuilder * getOpenMPBuilder()
Returns the OpenMP IR builder associated with the LLVM IR module being constructed.
llvm::CallInst * lookupCall(Operation *op) const
Finds an LLVM call instruction that corresponds to the given MLIR call operation.
llvm::Metadata * translateDebugInfo(LLVM::DINodeAttr attr)
Translates the given LLVM debug info metadata.
llvm::LLVMContext & getLLVMContext() const
Returns the LLVM context in which the IR is being constructed.
llvm::GlobalValue * lookupGlobal(Operation *op)
Finds an LLVM IR global value that corresponds to the given MLIR operation defining a global value.
llvm::Module * getLLVMModule()
Returns the LLVM module in which the IR is being constructed.
llvm::Function * lookupFunction(StringRef name) const
Finds an LLVM IR function by its name.
llvm::MDNode * getOrCreateAliasScopes(ArrayRef< AliasScopeAttr > aliasScopeAttrs)
Returns the LLVM metadata corresponding to an array of mlir LLVM dialect alias scope attributes.
void mapBlock(Block *mlir, llvm::BasicBlock *llvm)
Stores the mapping between an MLIR block and LLVM IR basic block.
llvm::MDNode * getOrCreateAliasScope(AliasScopeAttr aliasScopeAttr)
Returns the LLVM metadata corresponding to a mlir LLVM dialect alias scope attribute.
void forgetMapping(Region &region)
Removes the mapping for blocks contained in the region and values defined in these blocks.
void setAliasScopeMetadata(AliasAnalysisOpInterface op, llvm::Instruction *inst)
void setAccessGroupsMetadata(AccessGroupOpInterface op, llvm::Instruction *inst)
void mapValue(Value mlir, llvm::Value *llvm)
Stores the mapping between an MLIR value and its LLVM IR counterpart.
void setLoopMetadata(Operation *op, llvm::Instruction *inst)
Sets LLVM loop metadata for branch operations that have a loop annotation attribute.
llvm::Type * translateType(Type type)
Translates the given MLIR LLVM dialect type to LLVM IR.
Definition: TypeToLLVM.cpp:192
A helper class that converts LoopAnnotationAttrs and AccessGroupAttrs into corresponding llvm::MDNode...
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition: Location.h:63
T * getOrLoadDialect()
Get (or create) a dialect for the given derived dialect type.
Definition: MLIRContext.h:97
NamedAttribute represents a combination of a name and an Attribute value.
Definition: Attributes.h:198
This class provides the API for ops that are known to be terminators.
Definition: OpDefinition.h:757
Operation is the basic unit of execution within MLIR.
Definition: Operation.h:88
Attribute getDiscardableAttr(StringRef name)
Access a discardable attribute by name, returns an null Attribute if the discardable attribute does n...
Definition: Operation.h:448
Value getOperand(unsigned idx)
Definition: Operation.h:345
Block * getSuccessor(unsigned index)
Definition: Operation.h:687
unsigned getNumSuccessors()
Definition: Operation.h:685
InFlightDiagnostic emitWarning(const Twine &message={})
Emit a warning about this operation, reporting up to any diagnostic handlers that may be listening.
Definition: Operation.cpp:279
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Definition: Operation.h:402
std::enable_if_t< llvm::function_traits< std::decay_t< FnT > >::num_args==1, RetT > walk(FnT &&callback)
Walk the operation by calling the callback for each nested operation (including this one),...
Definition: Operation.h:776
MLIRContext * getContext()
Return the context this operation is associated with.
Definition: Operation.h:216
Location getLoc()
The source location the operation was defined or derived from.
Definition: Operation.h:223
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
Definition: Operation.cpp:267
Region & getRegion(unsigned index)
Returns the region held by this operation at position 'index'.
Definition: Operation.h:665
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
Definition: Operation.h:655
OperationName getName()
The name of an operation is the key identifier for it.
Definition: Operation.h:119
dialect_attr_range getDialectAttrs()
Return a range corresponding to the dialect attributes for this operation.
Definition: Operation.h:615
bool hasSuccessors()
Definition: Operation.h:684
result_range getResults()
Definition: Operation.h:410
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
Definition: Operation.cpp:640
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition: Region.h:26
BlockListType & getBlocks()
Definition: Region.h:45
Block & front()
Definition: Region.h:65
This class models how operands are forwarded to block arguments in control flow.
bool empty() const
Returns true if there are no successor operands.
static Operation * lookupNearestSymbolFrom(Operation *from, StringAttr symbol)
Returns the operation registered with the given symbol name within the closest parent operation of,...
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition: Types.h:74
This class provides an abstraction over the different types of ranges over Values.
Definition: ValueRange.h:372
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:93
Include the generated interface declarations.
Definition: CallGraph.h:229
static llvm::ArrayRef< std::pair< llvm::Attribute::AttrKind, llvm::StringRef > > getAttrKindToNameMapping()
Returns a list of pairs that each hold a mapping from LLVM attribute kinds to their corresponding str...
void connectPHINodes(Region &region, const ModuleTranslation &state)
For all blocks in the region that were converted to LLVM IR using the given ModuleTranslation,...
llvm::CallInst * createIntrinsicCall(llvm::IRBuilderBase &builder, llvm::Intrinsic::ID intrinsic, ArrayRef< llvm::Value * > args={}, ArrayRef< llvm::Type * > tys={})
Creates a call to an LLVM IR intrinsic function with the given arguments.
SetVector< Block * > getTopologicallySortedBlocks(Region &region)
Get a topologically sorted list of blocks of the given region.
llvm::Constant * getLLVMConstant(llvm::Type *llvmType, Attribute attr, Location loc, const ModuleTranslation &moduleTranslation)
Create an LLVM IR constant of llvmType from the MLIR attribute attr.
std::optional< unsigned > extractPointerSpecValue(Attribute attr, PtrDLEntryPos pos)
Returns the value that corresponds to named position pos from the data layout entry attr assuming it'...
Definition: LLVMTypes.cpp:321
bool satisfiesLLVMModule(Operation *op)
LLVM requires some operations to be inside of a Module operation.
bool isCompatibleType(Type type)
Returns true if the given type is compatible with the LLVM dialect.
Definition: LLVMTypes.cpp:913
void ensureDistinctSuccessors(Operation *op)
Make argument-taking successors of each block distinct.
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
Definition: Matchers.h:285
DictionaryAttr getArgAttrDict(FunctionOpInterface op, unsigned index)
Returns the dictionary attribute corresponding to the argument at 'index'.
This header declares functions that assist transformations in the MemRef dialect.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:62
DataLayoutSpecInterface translateDataLayout(const llvm::DataLayout &dataLayout, MLIRContext *context)
Translate the given LLVM data layout into an MLIR equivalent using the DLTI dialect.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:56
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
std::unique_ptr< llvm::Module > translateModuleToLLVMIR(Operation *module, llvm::LLVMContext &llvmContext, llvm::StringRef name="LLVMDialectModule")
Translate operation that satisfies LLVM dialect module requirements into an LLVM IR module living in ...
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value.
Definition: LogicalResult.h:72
int64_t mod(int64_t lhs, int64_t rhs)
Returns MLIR's mod operation on constants.
Definition: MathExtras.h:45
This class represents an efficient way to signal success or failure.
Definition: LogicalResult.h:26