MLIR  22.0.0git
LLVMToLLVMIRTranslation.cpp
Go to the documentation of this file.
1 //===- LLVMToLLVMIRTranslation.cpp - Translate LLVM dialect to LLVM IR ----===//
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 a translation between the MLIR LLVM dialect and LLVM IR.
10 //
11 //===----------------------------------------------------------------------===//
12 
15 #include "mlir/IR/Operation.h"
17 #include "mlir/Support/LLVM.h"
19 
20 #include "llvm/ADT/TypeSwitch.h"
21 #include "llvm/IR/DIBuilder.h"
22 #include "llvm/IR/IRBuilder.h"
23 #include "llvm/IR/InlineAsm.h"
24 #include "llvm/IR/Instructions.h"
25 #include "llvm/IR/MDBuilder.h"
26 #include "llvm/IR/MatrixBuilder.h"
27 
28 using namespace mlir;
29 using namespace mlir::LLVM;
31 
32 #include "mlir/Dialect/LLVMIR/LLVMConversionEnumsToLLVM.inc"
33 
34 static llvm::FastMathFlags getFastmathFlags(FastmathFlagsInterface &op) {
35  using llvmFMF = llvm::FastMathFlags;
36  using FuncT = void (llvmFMF::*)(bool);
37  const std::pair<FastmathFlags, FuncT> handlers[] = {
38  // clang-format off
39  {FastmathFlags::nnan, &llvmFMF::setNoNaNs},
40  {FastmathFlags::ninf, &llvmFMF::setNoInfs},
41  {FastmathFlags::nsz, &llvmFMF::setNoSignedZeros},
42  {FastmathFlags::arcp, &llvmFMF::setAllowReciprocal},
43  {FastmathFlags::contract, &llvmFMF::setAllowContract},
44  {FastmathFlags::afn, &llvmFMF::setApproxFunc},
45  {FastmathFlags::reassoc, &llvmFMF::setAllowReassoc},
46  // clang-format on
47  };
48  llvm::FastMathFlags ret;
49  ::mlir::LLVM::FastmathFlags fmfMlir = op.getFastmathAttr().getValue();
50  for (auto it : handlers)
51  if (bitEnumContainsAll(fmfMlir, it.first))
52  (ret.*(it.second))(true);
53  return ret;
54 }
55 
56 /// Convert the value of a DenseI64ArrayAttr to a vector of unsigned indices.
58  SmallVector<unsigned> position;
59  llvm::append_range(position, indices);
60  return position;
61 }
62 
63 /// Convert an LLVM type to a string for printing in diagnostics.
64 static std::string diagStr(const llvm::Type *type) {
65  std::string str;
66  llvm::raw_string_ostream os(str);
67  type->print(os);
68  return str;
69 }
70 
71 /// Get the declaration of an overloaded llvm intrinsic. First we get the
72 /// overloaded argument types and/or result type from the CallIntrinsicOp, and
73 /// then use those to get the correct declaration of the overloaded intrinsic.
74 static FailureOr<llvm::Function *>
76  llvm::Module *module,
77  LLVM::ModuleTranslation &moduleTranslation) {
79  for (Type type : op->getOperandTypes())
80  allArgTys.push_back(moduleTranslation.convertType(type));
81 
82  llvm::Type *resTy;
83  if (op.getNumResults() == 0)
84  resTy = llvm::Type::getVoidTy(module->getContext());
85  else
86  resTy = moduleTranslation.convertType(op.getResult(0).getType());
87 
88  // ATM we do not support variadic intrinsics.
89  llvm::FunctionType *ft = llvm::FunctionType::get(resTy, allArgTys, false);
90 
92  getIntrinsicInfoTableEntries(id, table);
94 
95  SmallVector<llvm::Type *, 8> overloadedArgTys;
96  if (llvm::Intrinsic::matchIntrinsicSignature(ft, tableRef,
97  overloadedArgTys) !=
98  llvm::Intrinsic::MatchIntrinsicTypesResult::MatchIntrinsicTypes_Match) {
99  return mlir::emitError(op.getLoc(), "call intrinsic signature ")
100  << diagStr(ft) << " to overloaded intrinsic " << op.getIntrinAttr()
101  << " does not match any of the overloads";
102  }
103 
104  ArrayRef<llvm::Type *> overloadedArgTysRef = overloadedArgTys;
105  return llvm::Intrinsic::getOrInsertDeclaration(module, id,
106  overloadedArgTysRef);
107 }
108 
109 static llvm::OperandBundleDef
110 convertOperandBundle(OperandRange bundleOperands, StringRef bundleTag,
111  LLVM::ModuleTranslation &moduleTranslation) {
112  std::vector<llvm::Value *> operands;
113  operands.reserve(bundleOperands.size());
114  for (Value bundleArg : bundleOperands)
115  operands.push_back(moduleTranslation.lookupValue(bundleArg));
116  return llvm::OperandBundleDef(bundleTag.str(), std::move(operands));
117 }
118 
120 convertOperandBundles(OperandRangeRange bundleOperands, ArrayAttr bundleTags,
121  LLVM::ModuleTranslation &moduleTranslation) {
123  bundles.reserve(bundleOperands.size());
124 
125  for (auto [operands, tagAttr] : llvm::zip_equal(bundleOperands, bundleTags)) {
126  StringRef tag = cast<StringAttr>(tagAttr).getValue();
127  bundles.push_back(convertOperandBundle(operands, tag, moduleTranslation));
128  }
129  return bundles;
130 }
131 
134  std::optional<ArrayAttr> bundleTags,
135  LLVM::ModuleTranslation &moduleTranslation) {
136  if (!bundleTags)
137  return {};
138  return convertOperandBundles(bundleOperands, *bundleTags, moduleTranslation);
139 }
140 
141 /// Builder for LLVM_CallIntrinsicOp
142 static LogicalResult
143 convertCallLLVMIntrinsicOp(CallIntrinsicOp op, llvm::IRBuilderBase &builder,
144  LLVM::ModuleTranslation &moduleTranslation) {
145  llvm::Module *module = builder.GetInsertBlock()->getModule();
147  llvm::Intrinsic::lookupIntrinsicID(op.getIntrinAttr());
148  if (!id)
149  return mlir::emitError(op.getLoc(), "could not find LLVM intrinsic: ")
150  << op.getIntrinAttr();
151 
152  llvm::Function *fn = nullptr;
153  if (llvm::Intrinsic::isOverloaded(id)) {
154  auto fnOrFailure =
155  getOverloadedDeclaration(op, id, module, moduleTranslation);
156  if (failed(fnOrFailure))
157  return failure();
158  fn = *fnOrFailure;
159  } else {
160  fn = llvm::Intrinsic::getOrInsertDeclaration(module, id, {});
161  }
162 
163  // Check the result type of the call.
164  const llvm::Type *intrinType =
165  op.getNumResults() == 0
166  ? llvm::Type::getVoidTy(module->getContext())
167  : moduleTranslation.convertType(op.getResultTypes().front());
168  if (intrinType != fn->getReturnType()) {
169  return mlir::emitError(op.getLoc(), "intrinsic call returns ")
170  << diagStr(intrinType) << " but " << op.getIntrinAttr()
171  << " actually returns " << diagStr(fn->getReturnType());
172  }
173 
174  // Check the argument types of the call. If the function is variadic, check
175  // the subrange of required arguments.
176  if (!fn->getFunctionType()->isVarArg() &&
177  op.getArgs().size() != fn->arg_size()) {
178  return mlir::emitError(op.getLoc(), "intrinsic call has ")
179  << op.getArgs().size() << " operands but " << op.getIntrinAttr()
180  << " expects " << fn->arg_size();
181  }
182  if (fn->getFunctionType()->isVarArg() &&
183  op.getArgs().size() < fn->arg_size()) {
184  return mlir::emitError(op.getLoc(), "intrinsic call has ")
185  << op.getArgs().size() << " operands but variadic "
186  << op.getIntrinAttr() << " expects at least " << fn->arg_size();
187  }
188  // Check the arguments up to the number the function requires.
189  for (unsigned i = 0, e = fn->arg_size(); i != e; ++i) {
190  const llvm::Type *expected = fn->getArg(i)->getType();
191  const llvm::Type *actual =
192  moduleTranslation.convertType(op.getOperandTypes()[i]);
193  if (actual != expected) {
194  return mlir::emitError(op.getLoc(), "intrinsic call operand #")
195  << i << " has type " << diagStr(actual) << " but "
196  << op.getIntrinAttr() << " expects " << diagStr(expected);
197  }
198  }
199 
200  FastmathFlagsInterface itf = op;
201  builder.setFastMathFlags(getFastmathFlags(itf));
202 
203  auto *inst = builder.CreateCall(
204  fn, moduleTranslation.lookupValues(op.getArgs()),
205  convertOperandBundles(op.getOpBundleOperands(), op.getOpBundleTags(),
206  moduleTranslation));
207 
208  if (failed(moduleTranslation.convertArgAndResultAttrs(op, inst)))
209  return failure();
210 
211  if (op.getNumResults() == 1)
212  moduleTranslation.mapValue(op->getResults().front()) = inst;
213  return success();
214 }
215 
216 static void convertLinkerOptionsOp(ArrayAttr options,
217  llvm::IRBuilderBase &builder,
218  LLVM::ModuleTranslation &moduleTranslation) {
219  llvm::Module *llvmModule = moduleTranslation.getLLVMModule();
220  llvm::LLVMContext &context = llvmModule->getContext();
221  llvm::NamedMDNode *linkerMDNode =
222  llvmModule->getOrInsertNamedMetadata("llvm.linker.options");
224  MDNodes.reserve(options.size());
225  for (auto s : options.getAsRange<StringAttr>()) {
226  auto *MDNode = llvm::MDString::get(context, s.getValue());
227  MDNodes.push_back(MDNode);
228  }
229 
230  auto *listMDNode = llvm::MDTuple::get(context, MDNodes);
231  linkerMDNode->addOperand(listMDNode);
232 }
233 
234 static llvm::Metadata *
235 convertModuleFlagValue(StringRef key, ArrayAttr arrayAttr,
236  llvm::IRBuilderBase &builder,
237  LLVM::ModuleTranslation &moduleTranslation) {
238  llvm::LLVMContext &context = builder.getContext();
239  llvm::MDBuilder mdb(context);
241 
242  if (key == LLVMDialect::getModuleFlagKeyCGProfileName()) {
243  for (auto entry : arrayAttr.getAsRange<ModuleFlagCGProfileEntryAttr>()) {
244  llvm::Metadata *fromMetadata =
245  entry.getFrom()
246  ? llvm::ValueAsMetadata::get(moduleTranslation.lookupFunction(
247  entry.getFrom().getValue()))
248  : nullptr;
249  llvm::Metadata *toMetadata =
250  entry.getTo()
252  moduleTranslation.lookupFunction(entry.getTo().getValue()))
253  : nullptr;
254 
255  llvm::Metadata *vals[] = {
256  fromMetadata, toMetadata,
257  mdb.createConstant(llvm::ConstantInt::get(
258  llvm::Type::getInt64Ty(context), entry.getCount()))};
259  nodes.push_back(llvm::MDNode::get(context, vals));
260  }
261  return llvm::MDTuple::getDistinct(context, nodes);
262  }
263  return nullptr;
264 }
265 
266 static llvm::Metadata *convertModuleFlagProfileSummaryAttr(
267  StringRef key, ModuleFlagProfileSummaryAttr summaryAttr,
268  llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation) {
269  llvm::LLVMContext &context = builder.getContext();
270  llvm::MDBuilder mdb(context);
271 
272  auto getIntTuple = [&](StringRef key, uint64_t val) -> llvm::MDTuple * {
274  mdb.createString(key), mdb.createConstant(llvm::ConstantInt::get(
275  llvm::Type::getInt64Ty(context), val))};
276  return llvm::MDTuple::get(context, tupleNodes);
277  };
278 
280  mdb.createString("ProfileFormat"),
281  mdb.createString(
282  stringifyProfileSummaryFormatKind(summaryAttr.getFormat()))};
283 
285  llvm::MDTuple::get(context, fmtNode),
286  getIntTuple("TotalCount", summaryAttr.getTotalCount()),
287  getIntTuple("MaxCount", summaryAttr.getMaxCount()),
288  getIntTuple("MaxInternalCount", summaryAttr.getMaxInternalCount()),
289  getIntTuple("MaxFunctionCount", summaryAttr.getMaxFunctionCount()),
290  getIntTuple("NumCounts", summaryAttr.getNumCounts()),
291  getIntTuple("NumFunctions", summaryAttr.getNumFunctions()),
292  };
293 
294  if (summaryAttr.getIsPartialProfile())
295  vals.push_back(
296  getIntTuple("IsPartialProfile", *summaryAttr.getIsPartialProfile()));
297 
298  if (summaryAttr.getPartialProfileRatio()) {
300  mdb.createString("PartialProfileRatio"),
301  mdb.createConstant(llvm::ConstantFP::get(
302  llvm::Type::getDoubleTy(context),
303  summaryAttr.getPartialProfileRatio().getValue()))};
304  vals.push_back(llvm::MDTuple::get(context, tupleNodes));
305  }
306 
307  SmallVector<llvm::Metadata *> detailedEntries;
308  llvm::Type *llvmInt64Type = llvm::Type::getInt64Ty(context);
309  for (ModuleFlagProfileSummaryDetailedAttr detailedEntry :
310  summaryAttr.getDetailedSummary()) {
312  mdb.createConstant(
313  llvm::ConstantInt::get(llvmInt64Type, detailedEntry.getCutOff())),
314  mdb.createConstant(
315  llvm::ConstantInt::get(llvmInt64Type, detailedEntry.getMinCount())),
316  mdb.createConstant(llvm::ConstantInt::get(
317  llvmInt64Type, detailedEntry.getNumCounts()))};
318  detailedEntries.push_back(llvm::MDTuple::get(context, tupleNodes));
319  }
320  SmallVector<llvm::Metadata *> detailedSummary{
321  mdb.createString("DetailedSummary"),
322  llvm::MDTuple::get(context, detailedEntries)};
323  vals.push_back(llvm::MDTuple::get(context, detailedSummary));
324 
325  return llvm::MDNode::get(context, vals);
326 }
327 
328 static void convertModuleFlagsOp(ArrayAttr flags, llvm::IRBuilderBase &builder,
329  LLVM::ModuleTranslation &moduleTranslation) {
330  llvm::Module *llvmModule = moduleTranslation.getLLVMModule();
331  for (auto flagAttr : flags.getAsRange<ModuleFlagAttr>()) {
332  llvm::Metadata *valueMetadata =
334  .Case<StringAttr>([&](auto strAttr) {
335  return llvm::MDString::get(builder.getContext(),
336  strAttr.getValue());
337  })
338  .Case<IntegerAttr>([&](auto intAttr) {
340  llvm::Type::getInt32Ty(builder.getContext()),
341  intAttr.getInt()));
342  })
343  .Case<ArrayAttr>([&](auto arrayAttr) {
344  return convertModuleFlagValue(flagAttr.getKey().getValue(),
345  arrayAttr, builder,
346  moduleTranslation);
347  })
348  .Case([&](ModuleFlagProfileSummaryAttr summaryAttr) {
350  flagAttr.getKey().getValue(), summaryAttr, builder,
351  moduleTranslation);
352  })
353  .Default([](auto) { return nullptr; });
354 
355  assert(valueMetadata && "expected valid metadata");
356  llvmModule->addModuleFlag(
357  convertModFlagBehaviorToLLVM(flagAttr.getBehavior()),
358  flagAttr.getKey().getValue(), valueMetadata);
359  }
360 }
361 
362 static llvm::DILocalScope *
363 getLocalScopeFromLoc(llvm::IRBuilderBase &builder, Location loc,
364  LLVM::ModuleTranslation &moduleTranslation) {
365  if (auto scopeLoc =
367  if (auto *localScope = llvm::dyn_cast<llvm::DILocalScope>(
368  moduleTranslation.translateDebugInfo(scopeLoc.getMetadata())))
369  return localScope;
370  return builder.GetInsertBlock()->getParent()->getSubprogram();
371 }
372 
373 static LogicalResult
374 convertOperationImpl(Operation &opInst, llvm::IRBuilderBase &builder,
375  LLVM::ModuleTranslation &moduleTranslation) {
376 
377  llvm::IRBuilder<>::FastMathFlagGuard fmfGuard(builder);
378  if (auto fmf = dyn_cast<FastmathFlagsInterface>(opInst))
379  builder.setFastMathFlags(getFastmathFlags(fmf));
380 
381 #include "mlir/Dialect/LLVMIR/LLVMConversions.inc"
382 #include "mlir/Dialect/LLVMIR/LLVMIntrinsicConversions.inc"
383 
384  // Emit function calls. If the "callee" attribute is present, this is a
385  // direct function call and we also need to look up the remapped function
386  // itself. Otherwise, this is an indirect call and the callee is the first
387  // operand, look it up as a normal value.
388  if (auto callOp = dyn_cast<LLVM::CallOp>(opInst)) {
389  auto operands = moduleTranslation.lookupValues(callOp.getCalleeOperands());
391  convertOperandBundles(callOp.getOpBundleOperands(),
392  callOp.getOpBundleTags(), moduleTranslation);
393  ArrayRef<llvm::Value *> operandsRef(operands);
394  llvm::CallInst *call;
395  if (auto attr = callOp.getCalleeAttr()) {
396  if (llvm::Function *function =
397  moduleTranslation.lookupFunction(attr.getValue())) {
398  call = builder.CreateCall(function, operandsRef, opBundles);
399  } else {
400  Operation *moduleOp = parentLLVMModule(&opInst);
401  Operation *ifuncOp =
402  moduleTranslation.symbolTable().lookupSymbolIn(moduleOp, attr);
403  llvm::GlobalValue *ifunc = moduleTranslation.lookupIFunc(ifuncOp);
404  llvm::FunctionType *calleeType = llvm::cast<llvm::FunctionType>(
405  moduleTranslation.convertType(callOp.getCalleeFunctionType()));
406  call = builder.CreateCall(calleeType, ifunc, operandsRef, opBundles);
407  }
408  } else {
409  llvm::FunctionType *calleeType = llvm::cast<llvm::FunctionType>(
410  moduleTranslation.convertType(callOp.getCalleeFunctionType()));
411  call = builder.CreateCall(calleeType, operandsRef.front(),
412  operandsRef.drop_front(), opBundles);
413  }
414  call->setCallingConv(convertCConvToLLVM(callOp.getCConv()));
415  call->setTailCallKind(convertTailCallKindToLLVM(callOp.getTailCallKind()));
416  if (callOp.getConvergentAttr())
417  call->addFnAttr(llvm::Attribute::Convergent);
418  if (callOp.getNoUnwindAttr())
419  call->addFnAttr(llvm::Attribute::NoUnwind);
420  if (callOp.getWillReturnAttr())
421  call->addFnAttr(llvm::Attribute::WillReturn);
422  if (callOp.getNoInlineAttr())
423  call->addFnAttr(llvm::Attribute::NoInline);
424  if (callOp.getAlwaysInlineAttr())
425  call->addFnAttr(llvm::Attribute::AlwaysInline);
426  if (callOp.getInlineHintAttr())
427  call->addFnAttr(llvm::Attribute::InlineHint);
428 
429  if (failed(moduleTranslation.convertArgAndResultAttrs(callOp, call)))
430  return failure();
431 
432  if (MemoryEffectsAttr memAttr = callOp.getMemoryEffectsAttr()) {
433  llvm::MemoryEffects memEffects =
434  llvm::MemoryEffects(llvm::MemoryEffects::Location::ArgMem,
435  convertModRefInfoToLLVM(memAttr.getArgMem())) |
436  llvm::MemoryEffects(
437  llvm::MemoryEffects::Location::InaccessibleMem,
438  convertModRefInfoToLLVM(memAttr.getInaccessibleMem())) |
439  llvm::MemoryEffects(llvm::MemoryEffects::Location::Other,
440  convertModRefInfoToLLVM(memAttr.getOther()));
441  call->setMemoryEffects(memEffects);
442  }
443 
444  moduleTranslation.setAccessGroupsMetadata(callOp, call);
445  moduleTranslation.setAliasScopeMetadata(callOp, call);
446  moduleTranslation.setTBAAMetadata(callOp, call);
447  // If the called function has a result, remap the corresponding value. Note
448  // that LLVM IR dialect CallOp has either 0 or 1 result.
449  if (opInst.getNumResults() != 0)
450  moduleTranslation.mapValue(opInst.getResult(0), call);
451  // Check that LLVM call returns void for 0-result functions.
452  else if (!call->getType()->isVoidTy())
453  return failure();
454  moduleTranslation.mapCall(callOp, call);
455  return success();
456  }
457 
458  if (auto inlineAsmOp = dyn_cast<LLVM::InlineAsmOp>(opInst)) {
459  // TODO: refactor function type creation which usually occurs in std-LLVM
460  // conversion.
461  SmallVector<Type, 8> operandTypes;
462  llvm::append_range(operandTypes, inlineAsmOp.getOperands().getTypes());
463 
464  Type resultType;
465  if (inlineAsmOp.getNumResults() == 0) {
466  resultType = LLVM::LLVMVoidType::get(&moduleTranslation.getContext());
467  } else {
468  assert(inlineAsmOp.getNumResults() == 1);
469  resultType = inlineAsmOp.getResultTypes()[0];
470  }
471  auto ft = LLVM::LLVMFunctionType::get(resultType, operandTypes);
472  llvm::InlineAsm *inlineAsmInst =
473  inlineAsmOp.getAsmDialect()
475  static_cast<llvm::FunctionType *>(
476  moduleTranslation.convertType(ft)),
477  inlineAsmOp.getAsmString(), inlineAsmOp.getConstraints(),
478  inlineAsmOp.getHasSideEffects(),
479  inlineAsmOp.getIsAlignStack(),
480  convertAsmDialectToLLVM(*inlineAsmOp.getAsmDialect()))
481  : llvm::InlineAsm::get(static_cast<llvm::FunctionType *>(
482  moduleTranslation.convertType(ft)),
483  inlineAsmOp.getAsmString(),
484  inlineAsmOp.getConstraints(),
485  inlineAsmOp.getHasSideEffects(),
486  inlineAsmOp.getIsAlignStack());
487  llvm::CallInst *inst = builder.CreateCall(
488  inlineAsmInst,
489  moduleTranslation.lookupValues(inlineAsmOp.getOperands()));
490  inst->setTailCallKind(convertTailCallKindToLLVM(
491  inlineAsmOp.getTailCallKindAttr().getTailCallKind()));
492  if (auto maybeOperandAttrs = inlineAsmOp.getOperandAttrs()) {
493  llvm::AttributeList attrList;
494  for (const auto &it : llvm::enumerate(*maybeOperandAttrs)) {
495  Attribute attr = it.value();
496  if (!attr)
497  continue;
498  DictionaryAttr dAttr = cast<DictionaryAttr>(attr);
499  if (dAttr.empty())
500  continue;
501  TypeAttr tAttr =
502  cast<TypeAttr>(dAttr.get(InlineAsmOp::getElementTypeAttrName()));
503  llvm::AttrBuilder b(moduleTranslation.getLLVMContext());
504  llvm::Type *ty = moduleTranslation.convertType(tAttr.getValue());
505  b.addTypeAttr(llvm::Attribute::ElementType, ty);
506  // shift to account for the returned value (this is always 1 aggregate
507  // value in LLVM).
508  int shift = (opInst.getNumResults() > 0) ? 1 : 0;
509  attrList = attrList.addAttributesAtIndex(
510  moduleTranslation.getLLVMContext(), it.index() + shift, b);
511  }
512  inst->setAttributes(attrList);
513  }
514 
515  if (opInst.getNumResults() != 0)
516  moduleTranslation.mapValue(opInst.getResult(0), inst);
517  return success();
518  }
519 
520  if (auto invOp = dyn_cast<LLVM::InvokeOp>(opInst)) {
521  auto operands = moduleTranslation.lookupValues(invOp.getCalleeOperands());
523  convertOperandBundles(invOp.getOpBundleOperands(),
524  invOp.getOpBundleTags(), moduleTranslation);
525  ArrayRef<llvm::Value *> operandsRef(operands);
526  llvm::InvokeInst *result;
527  if (auto attr = opInst.getAttrOfType<FlatSymbolRefAttr>("callee")) {
528  result = builder.CreateInvoke(
529  moduleTranslation.lookupFunction(attr.getValue()),
530  moduleTranslation.lookupBlock(invOp.getSuccessor(0)),
531  moduleTranslation.lookupBlock(invOp.getSuccessor(1)), operandsRef,
532  opBundles);
533  } else {
534  llvm::FunctionType *calleeType = llvm::cast<llvm::FunctionType>(
535  moduleTranslation.convertType(invOp.getCalleeFunctionType()));
536  result = builder.CreateInvoke(
537  calleeType, operandsRef.front(),
538  moduleTranslation.lookupBlock(invOp.getSuccessor(0)),
539  moduleTranslation.lookupBlock(invOp.getSuccessor(1)),
540  operandsRef.drop_front(), opBundles);
541  }
542  result->setCallingConv(convertCConvToLLVM(invOp.getCConv()));
543  if (failed(moduleTranslation.convertArgAndResultAttrs(invOp, result)))
544  return failure();
545  moduleTranslation.mapBranch(invOp, result);
546  // InvokeOp can only have 0 or 1 result
547  if (invOp->getNumResults() != 0) {
548  moduleTranslation.mapValue(opInst.getResult(0), result);
549  return success();
550  }
551  return success(result->getType()->isVoidTy());
552  }
553 
554  if (auto lpOp = dyn_cast<LLVM::LandingpadOp>(opInst)) {
555  llvm::Type *ty = moduleTranslation.convertType(lpOp.getType());
556  llvm::LandingPadInst *lpi =
557  builder.CreateLandingPad(ty, lpOp.getNumOperands());
558  lpi->setCleanup(lpOp.getCleanup());
559 
560  // Add clauses
561  for (llvm::Value *operand :
562  moduleTranslation.lookupValues(lpOp.getOperands())) {
563  // All operands should be constant - checked by verifier
564  if (auto *constOperand = dyn_cast<llvm::Constant>(operand))
565  lpi->addClause(constOperand);
566  }
567  moduleTranslation.mapValue(lpOp.getResult(), lpi);
568  return success();
569  }
570 
571  // Emit branches. We need to look up the remapped blocks and ignore the
572  // block arguments that were transformed into PHI nodes.
573  if (auto brOp = dyn_cast<LLVM::BrOp>(opInst)) {
574  llvm::BranchInst *branch =
575  builder.CreateBr(moduleTranslation.lookupBlock(brOp.getSuccessor()));
576  moduleTranslation.mapBranch(&opInst, branch);
577  moduleTranslation.setLoopMetadata(&opInst, branch);
578  return success();
579  }
580  if (auto condbrOp = dyn_cast<LLVM::CondBrOp>(opInst)) {
581  llvm::BranchInst *branch = builder.CreateCondBr(
582  moduleTranslation.lookupValue(condbrOp.getOperand(0)),
583  moduleTranslation.lookupBlock(condbrOp.getSuccessor(0)),
584  moduleTranslation.lookupBlock(condbrOp.getSuccessor(1)));
585  moduleTranslation.mapBranch(&opInst, branch);
586  moduleTranslation.setLoopMetadata(&opInst, branch);
587  return success();
588  }
589  if (auto switchOp = dyn_cast<LLVM::SwitchOp>(opInst)) {
590  llvm::SwitchInst *switchInst = builder.CreateSwitch(
591  moduleTranslation.lookupValue(switchOp.getValue()),
592  moduleTranslation.lookupBlock(switchOp.getDefaultDestination()),
593  switchOp.getCaseDestinations().size());
594 
595  // Handle switch with zero cases.
596  if (!switchOp.getCaseValues())
597  return success();
598 
599  auto *ty = llvm::cast<llvm::IntegerType>(
600  moduleTranslation.convertType(switchOp.getValue().getType()));
601  for (auto i :
602  llvm::zip(llvm::cast<DenseIntElementsAttr>(*switchOp.getCaseValues()),
603  switchOp.getCaseDestinations()))
604  switchInst->addCase(
605  llvm::ConstantInt::get(ty, std::get<0>(i).getLimitedValue()),
606  moduleTranslation.lookupBlock(std::get<1>(i)));
607 
608  moduleTranslation.mapBranch(&opInst, switchInst);
609  return success();
610  }
611  if (auto indBrOp = dyn_cast<LLVM::IndirectBrOp>(opInst)) {
612  llvm::IndirectBrInst *indBr = builder.CreateIndirectBr(
613  moduleTranslation.lookupValue(indBrOp.getAddr()),
614  indBrOp->getNumSuccessors());
615  for (auto *succ : indBrOp.getSuccessors())
616  indBr->addDestination(moduleTranslation.lookupBlock(succ));
617  moduleTranslation.mapBranch(&opInst, indBr);
618  return success();
619  }
620 
621  // Emit addressof. We need to look up the global value referenced by the
622  // operation and store it in the MLIR-to-LLVM value mapping. This does not
623  // emit any LLVM instruction.
624  if (auto addressOfOp = dyn_cast<LLVM::AddressOfOp>(opInst)) {
625  LLVM::GlobalOp global =
626  addressOfOp.getGlobal(moduleTranslation.symbolTable());
627  LLVM::LLVMFuncOp function =
628  addressOfOp.getFunction(moduleTranslation.symbolTable());
629  LLVM::AliasOp alias = addressOfOp.getAlias(moduleTranslation.symbolTable());
630  LLVM::IFuncOp ifunc = addressOfOp.getIFunc(moduleTranslation.symbolTable());
631 
632  // The verifier should not have allowed this.
633  assert((global || function || alias || ifunc) &&
634  "referencing an undefined global, function, alias, or ifunc");
635 
636  llvm::Value *llvmValue = nullptr;
637  if (global)
638  llvmValue = moduleTranslation.lookupGlobal(global);
639  else if (alias)
640  llvmValue = moduleTranslation.lookupAlias(alias);
641  else if (function)
642  llvmValue = moduleTranslation.lookupFunction(function.getName());
643  else
644  llvmValue = moduleTranslation.lookupIFunc(ifunc);
645 
646  moduleTranslation.mapValue(addressOfOp.getResult(), llvmValue);
647  return success();
648  }
649 
650  // Emit dso_local_equivalent. We need to look up the global value referenced
651  // by the operation and store it in the MLIR-to-LLVM value mapping.
652  if (auto dsoLocalEquivalentOp =
653  dyn_cast<LLVM::DSOLocalEquivalentOp>(opInst)) {
654  LLVM::LLVMFuncOp function =
655  dsoLocalEquivalentOp.getFunction(moduleTranslation.symbolTable());
656  LLVM::AliasOp alias =
657  dsoLocalEquivalentOp.getAlias(moduleTranslation.symbolTable());
658 
659  // The verifier should not have allowed this.
660  assert((function || alias) &&
661  "referencing an undefined function, or alias");
662 
663  llvm::Value *llvmValue = nullptr;
664  if (alias)
665  llvmValue = moduleTranslation.lookupAlias(alias);
666  else
667  llvmValue = moduleTranslation.lookupFunction(function.getName());
668 
669  moduleTranslation.mapValue(
670  dsoLocalEquivalentOp.getResult(),
671  llvm::DSOLocalEquivalent::get(cast<llvm::GlobalValue>(llvmValue)));
672  return success();
673  }
674 
675  // Emit blockaddress. We first need to find the LLVM block referenced by this
676  // operation and then create a LLVM block address for it.
677  if (auto blockAddressOp = dyn_cast<LLVM::BlockAddressOp>(opInst)) {
678  BlockAddressAttr blockAddressAttr = blockAddressOp.getBlockAddr();
679  llvm::BasicBlock *llvmBlock =
680  moduleTranslation.lookupBlockAddress(blockAddressAttr);
681 
682  llvm::Value *llvmValue = nullptr;
683  StringRef fnName = blockAddressAttr.getFunction().getValue();
684  if (llvmBlock) {
685  llvm::Function *llvmFn = moduleTranslation.lookupFunction(fnName);
686  llvmValue = llvm::BlockAddress::get(llvmFn, llvmBlock);
687  } else {
688  // The matching LLVM block is not yet emitted, a placeholder is created
689  // in its place. When the LLVM block is emitted later in translation,
690  // the llvmValue is replaced with the actual llvm::BlockAddress.
691  // A GlobalVariable is chosen as placeholder because in general LLVM
692  // constants are uniqued and are not proper for RAUW, since that could
693  // harm unrelated uses of the constant.
694  llvmValue = new llvm::GlobalVariable(
695  *moduleTranslation.getLLVMModule(),
696  llvm::PointerType::getUnqual(moduleTranslation.getLLVMContext()),
697  /*isConstant=*/true, llvm::GlobalValue::LinkageTypes::ExternalLinkage,
698  /*Initializer=*/nullptr,
699  Twine("__mlir_block_address_")
700  .concat(Twine(fnName))
701  .concat(Twine((uint64_t)blockAddressOp.getOperation())));
702  moduleTranslation.mapUnresolvedBlockAddress(blockAddressOp, llvmValue);
703  }
704 
705  moduleTranslation.mapValue(blockAddressOp.getResult(), llvmValue);
706  return success();
707  }
708 
709  // Emit block label. If this label is seen before BlockAddressOp is
710  // translated, go ahead and already map it.
711  if (auto blockTagOp = dyn_cast<LLVM::BlockTagOp>(opInst)) {
712  auto funcOp = blockTagOp->getParentOfType<LLVMFuncOp>();
713  BlockAddressAttr blockAddressAttr = BlockAddressAttr::get(
714  &moduleTranslation.getContext(),
715  FlatSymbolRefAttr::get(&moduleTranslation.getContext(),
716  funcOp.getName()),
717  blockTagOp.getTag());
718  moduleTranslation.mapBlockAddress(blockAddressAttr,
719  builder.GetInsertBlock());
720  return success();
721  }
722 
723  return failure();
724 }
725 
726 namespace {
727 /// Implementation of the dialect interface that converts operations belonging
728 /// to the LLVM dialect to LLVM IR.
729 class LLVMDialectLLVMIRTranslationInterface
731 public:
733 
734  /// Translates the given operation to LLVM IR using the provided IR builder
735  /// and saving the state in `moduleTranslation`.
736  LogicalResult
737  convertOperation(Operation *op, llvm::IRBuilderBase &builder,
738  LLVM::ModuleTranslation &moduleTranslation) const final {
739  return convertOperationImpl(*op, builder, moduleTranslation);
740  }
741 };
742 } // namespace
743 
745  registry.insert<LLVM::LLVMDialect>();
746  registry.addExtension(+[](MLIRContext *ctx, LLVM::LLVMDialect *dialect) {
747  dialect->addInterfaces<LLVMDialectLLVMIRTranslationInterface>();
748  });
749 }
750 
752  DialectRegistry registry;
754  context.appendDialectRegistry(registry);
755 }
static SmallVector< unsigned > extractPosition(ArrayRef< int64_t > indices)
Convert the value of a DenseI64ArrayAttr to a vector of unsigned indices.
static std::string diagStr(const llvm::Type *type)
Convert an LLVM type to a string for printing in diagnostics.
static llvm::Metadata * convertModuleFlagProfileSummaryAttr(StringRef key, ModuleFlagProfileSummaryAttr summaryAttr, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
static llvm::DILocalScope * getLocalScopeFromLoc(llvm::IRBuilderBase &builder, Location loc, LLVM::ModuleTranslation &moduleTranslation)
static void convertModuleFlagsOp(ArrayAttr flags, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
static FailureOr< llvm::Function * > getOverloadedDeclaration(CallIntrinsicOp op, llvm::Intrinsic::ID id, llvm::Module *module, LLVM::ModuleTranslation &moduleTranslation)
Get the declaration of an overloaded llvm intrinsic.
static LogicalResult convertOperationImpl(Operation &opInst, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
static SmallVector< llvm::OperandBundleDef > convertOperandBundles(OperandRangeRange bundleOperands, ArrayAttr bundleTags, LLVM::ModuleTranslation &moduleTranslation)
static LogicalResult convertCallLLVMIntrinsicOp(CallIntrinsicOp op, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
Builder for LLVM_CallIntrinsicOp.
static llvm::FastMathFlags getFastmathFlags(FastmathFlagsInterface &op)
static llvm::OperandBundleDef convertOperandBundle(OperandRange bundleOperands, StringRef bundleTag, LLVM::ModuleTranslation &moduleTranslation)
static llvm::Metadata * convertModuleFlagValue(StringRef key, ArrayAttr arrayAttr, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
static void convertLinkerOptionsOp(ArrayAttr options, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
static llvm::ManagedStatic< PassManagerOptions > options
static void contract(RootOrderingGraph &graph, ArrayRef< Value > cycle, const DenseMap< Value, unsigned > &parentDepths, DenseMap< Value, Value > &actualSource, DenseMap< Value, Value > &actualTarget)
Contracts the specified cycle in the given graph in-place.
const float * table
Attributes are known-constant values of operations.
Definition: Attributes.h:25
The DialectRegistry maps a dialect namespace to a constructor for the matching dialect.
bool addExtension(TypeID extensionID, std::unique_ptr< DialectExtensionBase > extension)
Add the given extension to the registry.
A symbol reference with a reference path containing a single element.
static FlatSymbolRefAttr get(StringAttr value)
Construct a symbol reference for the given value name.
This class represents a fused location whose metadata is known to be an instance of the given type.
Definition: Location.h:149
Base class for dialect interfaces providing translation to LLVM IR.
T findInstanceOf()
Return an instance of the given location type if one is nested under the current location.
Definition: Location.h:45
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition: Location.h:76
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:63
void appendDialectRegistry(const DialectRegistry &registry)
Append the contents of the given dialect registry to the registry associated with this context.
This class represents a contiguous range of operand ranges, e.g.
Definition: ValueRange.h:84
This class implements the operand iterators for the Operation class.
Definition: ValueRange.h:43
Operation is the basic unit of execution within MLIR.
Definition: Operation.h:88
AttrClass getAttrOfType(StringAttr name)
Definition: Operation.h:550
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Definition: Operation.h:407
unsigned getNumResults()
Return the number of results held by this operation.
Definition: Operation.h:404
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition: Types.h:74
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:96
llvm::Constant * getLLVMConstant(llvm::Type *llvmType, Attribute attr, Location loc, const ModuleTranslation &moduleTranslation)
Create an LLVM IR constant of llvmType from the MLIR attribute attr.
Operation * parentLLVMModule(Operation *op)
Lookup parent Module satisfying LLVM conditions on the Module Operation.
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
Definition: Matchers.h:344
SmallVector< AffineExpr, 4 > concat(ArrayRef< AffineExpr > a, ArrayRef< AffineExpr > b)
Return the vector that is the concatenation of a and b.
Definition: LinalgOps.cpp:2465
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition: Remarks.h:491
Include the generated interface declarations.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
void registerLLVMDialectTranslation(DialectRegistry &registry)
Register the LLVM dialect and the translation from it to the LLVM IR in the given registry;.
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...