MLIR  18.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"
16 #include "mlir/Support/LLVM.h"
18 
19 #include "llvm/IR/IRBuilder.h"
20 #include "llvm/IR/InlineAsm.h"
21 #include "llvm/IR/MDBuilder.h"
22 #include "llvm/IR/MatrixBuilder.h"
23 #include "llvm/IR/Operator.h"
24 
25 using namespace mlir;
26 using namespace mlir::LLVM;
29 
30 #include "mlir/Dialect/LLVMIR/LLVMConversionEnumsToLLVM.inc"
31 
32 static llvm::FastMathFlags getFastmathFlags(FastmathFlagsInterface &op) {
33  using llvmFMF = llvm::FastMathFlags;
34  using FuncT = void (llvmFMF::*)(bool);
35  const std::pair<FastmathFlags, FuncT> handlers[] = {
36  // clang-format off
37  {FastmathFlags::nnan, &llvmFMF::setNoNaNs},
38  {FastmathFlags::ninf, &llvmFMF::setNoInfs},
39  {FastmathFlags::nsz, &llvmFMF::setNoSignedZeros},
40  {FastmathFlags::arcp, &llvmFMF::setAllowReciprocal},
41  {FastmathFlags::contract, &llvmFMF::setAllowContract},
42  {FastmathFlags::afn, &llvmFMF::setApproxFunc},
43  {FastmathFlags::reassoc, &llvmFMF::setAllowReassoc},
44  // clang-format on
45  };
46  llvm::FastMathFlags ret;
47  ::mlir::LLVM::FastmathFlags fmfMlir = op.getFastmathAttr().getValue();
48  for (auto it : handlers)
49  if (bitEnumContainsAll(fmfMlir, it.first))
50  (ret.*(it.second))(true);
51  return ret;
52 }
53 
54 /// Convert the value of a DenseI64ArrayAttr to a vector of unsigned indices.
56  SmallVector<unsigned> position;
57  llvm::append_range(position, indices);
58  return position;
59 }
60 
61 /// Convert an LLVM type to a string for printing in diagnostics.
62 static std::string diagStr(const llvm::Type *type) {
63  std::string str;
64  llvm::raw_string_ostream os(str);
65  type->print(os);
66  return os.str();
67 }
68 
69 /// Get the declaration of an overloaded llvm intrinsic. First we get the
70 /// overloaded argument types and/or result type from the CallIntrinsicOp, and
71 /// then use those to get the correct declaration of the overloaded intrinsic.
74  llvm::Module *module,
75  LLVM::ModuleTranslation &moduleTranslation) {
77  for (Type type : op->getOperandTypes())
78  allArgTys.push_back(moduleTranslation.convertType(type));
79 
80  llvm::Type *resTy;
81  if (op.getNumResults() == 0)
82  resTy = llvm::Type::getVoidTy(module->getContext());
83  else
84  resTy = moduleTranslation.convertType(op.getResult(0).getType());
85 
86  // ATM we do not support variadic intrinsics.
87  llvm::FunctionType *ft = llvm::FunctionType::get(resTy, allArgTys, false);
88 
90  getIntrinsicInfoTableEntries(id, table);
92 
93  SmallVector<llvm::Type *, 8> overloadedArgTys;
94  if (llvm::Intrinsic::matchIntrinsicSignature(ft, tableRef,
95  overloadedArgTys) !=
96  llvm::Intrinsic::MatchIntrinsicTypesResult::MatchIntrinsicTypes_Match) {
97  return mlir::emitError(op.getLoc(), "call intrinsic signature ")
98  << diagStr(ft) << " to overloaded intrinsic " << op.getIntrinAttr()
99  << " does not match any of the overloads";
100  }
101 
102  ArrayRef<llvm::Type *> overloadedArgTysRef = overloadedArgTys;
103  return llvm::Intrinsic::getDeclaration(module, id, overloadedArgTysRef);
104 }
105 
106 /// Builder for LLVM_CallIntrinsicOp
107 static LogicalResult
108 convertCallLLVMIntrinsicOp(CallIntrinsicOp op, llvm::IRBuilderBase &builder,
109  LLVM::ModuleTranslation &moduleTranslation) {
110  llvm::Module *module = builder.GetInsertBlock()->getModule();
112  llvm::Function::lookupIntrinsicID(op.getIntrinAttr());
113  if (!id)
114  return mlir::emitError(op.getLoc(), "could not find LLVM intrinsic: ")
115  << op.getIntrinAttr();
116 
117  llvm::Function *fn = nullptr;
118  if (llvm::Intrinsic::isOverloaded(id)) {
119  auto fnOrFailure =
120  getOverloadedDeclaration(op, id, module, moduleTranslation);
121  if (failed(fnOrFailure))
122  return failure();
123  fn = *fnOrFailure;
124  } else {
125  fn = llvm::Intrinsic::getDeclaration(module, id, {});
126  }
127 
128  // Check the result type of the call.
129  const llvm::Type *intrinType =
130  op.getNumResults() == 0
131  ? llvm::Type::getVoidTy(module->getContext())
132  : moduleTranslation.convertType(op.getResultTypes().front());
133  if (intrinType != fn->getReturnType()) {
134  return mlir::emitError(op.getLoc(), "intrinsic call returns ")
135  << diagStr(intrinType) << " but " << op.getIntrinAttr()
136  << " actually returns " << diagStr(fn->getReturnType());
137  }
138 
139  // Check the argument types of the call. If the function is variadic, check
140  // the subrange of required arguments.
141  if (!fn->getFunctionType()->isVarArg() &&
142  op.getNumOperands() != fn->arg_size()) {
143  return mlir::emitError(op.getLoc(), "intrinsic call has ")
144  << op.getNumOperands() << " operands but " << op.getIntrinAttr()
145  << " expects " << fn->arg_size();
146  }
147  if (fn->getFunctionType()->isVarArg() &&
148  op.getNumOperands() < fn->arg_size()) {
149  return mlir::emitError(op.getLoc(), "intrinsic call has ")
150  << op.getNumOperands() << " operands but variadic "
151  << op.getIntrinAttr() << " expects at least " << fn->arg_size();
152  }
153  // Check the arguments up to the number the function requires.
154  for (unsigned i = 0, e = fn->arg_size(); i != e; ++i) {
155  const llvm::Type *expected = fn->getArg(i)->getType();
156  const llvm::Type *actual =
157  moduleTranslation.convertType(op.getOperandTypes()[i]);
158  if (actual != expected) {
159  return mlir::emitError(op.getLoc(), "intrinsic call operand #")
160  << i << " has type " << diagStr(actual) << " but "
161  << op.getIntrinAttr() << " expects " << diagStr(expected);
162  }
163  }
164 
165  FastmathFlagsInterface itf = op;
166  builder.setFastMathFlags(getFastmathFlags(itf));
167 
168  auto *inst =
169  builder.CreateCall(fn, moduleTranslation.lookupValues(op.getOperands()));
170  if (op.getNumResults() == 1)
171  moduleTranslation.mapValue(op->getResults().front()) = inst;
172  return success();
173 }
174 
175 static LogicalResult
176 convertOperationImpl(Operation &opInst, llvm::IRBuilderBase &builder,
177  LLVM::ModuleTranslation &moduleTranslation) {
178 
179  llvm::IRBuilder<>::FastMathFlagGuard fmfGuard(builder);
180  if (auto fmf = dyn_cast<FastmathFlagsInterface>(opInst))
181  builder.setFastMathFlags(getFastmathFlags(fmf));
182 
183 #include "mlir/Dialect/LLVMIR/LLVMConversions.inc"
184 #include "mlir/Dialect/LLVMIR/LLVMIntrinsicConversions.inc"
185 
186  // Helper function to reconstruct the function type for an indirect call given
187  // the result and argument types. The function cannot reconstruct the type of
188  // variadic functions since the call operation does not carry enough
189  // information to distinguish normal and variadic arguments. Supporting
190  // indirect variadic calls requires an additional type attribute on the call
191  // operation that stores the LLVM function type of the callee.
192  // TODO: Support indirect calls to variadic function pointers.
193  auto getCalleeFunctionType = [&](TypeRange resultTypes, ValueRange args) {
194  Type resultType = resultTypes.empty()
195  ? LLVMVoidType::get(opInst.getContext())
196  : resultTypes.front();
197  return llvm::cast<llvm::FunctionType>(moduleTranslation.convertType(
198  LLVMFunctionType::get(opInst.getContext(), resultType,
199  llvm::to_vector(args.getTypes()), false)));
200  };
201 
202  // Emit function calls. If the "callee" attribute is present, this is a
203  // direct function call and we also need to look up the remapped function
204  // itself. Otherwise, this is an indirect call and the callee is the first
205  // operand, look it up as a normal value.
206  if (auto callOp = dyn_cast<LLVM::CallOp>(opInst)) {
207  auto operands = moduleTranslation.lookupValues(callOp.getOperands());
208  ArrayRef<llvm::Value *> operandsRef(operands);
209  llvm::CallInst *call;
210  if (auto attr = callOp.getCalleeAttr()) {
211  call = builder.CreateCall(
212  moduleTranslation.lookupFunction(attr.getValue()), operandsRef);
213  } else {
214  call = builder.CreateCall(getCalleeFunctionType(callOp.getResultTypes(),
215  callOp.getArgOperands()),
216  operandsRef.front(), operandsRef.drop_front());
217  }
218  moduleTranslation.setAccessGroupsMetadata(callOp, call);
219  moduleTranslation.setAliasScopeMetadata(callOp, call);
220  moduleTranslation.setTBAAMetadata(callOp, call);
221  // If the called function has a result, remap the corresponding value. Note
222  // that LLVM IR dialect CallOp has either 0 or 1 result.
223  if (opInst.getNumResults() != 0)
224  moduleTranslation.mapValue(opInst.getResult(0), call);
225  // Check that LLVM call returns void for 0-result functions.
226  else if (!call->getType()->isVoidTy())
227  return failure();
228  moduleTranslation.mapCall(callOp, call);
229  return success();
230  }
231 
232  if (auto inlineAsmOp = dyn_cast<LLVM::InlineAsmOp>(opInst)) {
233  // TODO: refactor function type creation which usually occurs in std-LLVM
234  // conversion.
235  SmallVector<Type, 8> operandTypes;
236  llvm::append_range(operandTypes, inlineAsmOp.getOperands().getTypes());
237 
238  Type resultType;
239  if (inlineAsmOp.getNumResults() == 0) {
240  resultType = LLVM::LLVMVoidType::get(&moduleTranslation.getContext());
241  } else {
242  assert(inlineAsmOp.getNumResults() == 1);
243  resultType = inlineAsmOp.getResultTypes()[0];
244  }
245  auto ft = LLVM::LLVMFunctionType::get(resultType, operandTypes);
246  llvm::InlineAsm *inlineAsmInst =
247  inlineAsmOp.getAsmDialect()
249  static_cast<llvm::FunctionType *>(
250  moduleTranslation.convertType(ft)),
251  inlineAsmOp.getAsmString(), inlineAsmOp.getConstraints(),
252  inlineAsmOp.getHasSideEffects(),
253  inlineAsmOp.getIsAlignStack(),
254  convertAsmDialectToLLVM(*inlineAsmOp.getAsmDialect()))
255  : llvm::InlineAsm::get(static_cast<llvm::FunctionType *>(
256  moduleTranslation.convertType(ft)),
257  inlineAsmOp.getAsmString(),
258  inlineAsmOp.getConstraints(),
259  inlineAsmOp.getHasSideEffects(),
260  inlineAsmOp.getIsAlignStack());
261  llvm::CallInst *inst = builder.CreateCall(
262  inlineAsmInst,
263  moduleTranslation.lookupValues(inlineAsmOp.getOperands()));
264  if (auto maybeOperandAttrs = inlineAsmOp.getOperandAttrs()) {
265  llvm::AttributeList attrList;
266  for (const auto &it : llvm::enumerate(*maybeOperandAttrs)) {
267  Attribute attr = it.value();
268  if (!attr)
269  continue;
270  DictionaryAttr dAttr = cast<DictionaryAttr>(attr);
271  TypeAttr tAttr =
272  cast<TypeAttr>(dAttr.get(InlineAsmOp::getElementTypeAttrName()));
273  llvm::AttrBuilder b(moduleTranslation.getLLVMContext());
274  llvm::Type *ty = moduleTranslation.convertType(tAttr.getValue());
275  b.addTypeAttr(llvm::Attribute::ElementType, ty);
276  // shift to account for the returned value (this is always 1 aggregate
277  // value in LLVM).
278  int shift = (opInst.getNumResults() > 0) ? 1 : 0;
279  attrList = attrList.addAttributesAtIndex(
280  moduleTranslation.getLLVMContext(), it.index() + shift, b);
281  }
282  inst->setAttributes(attrList);
283  }
284 
285  if (opInst.getNumResults() != 0)
286  moduleTranslation.mapValue(opInst.getResult(0), inst);
287  return success();
288  }
289 
290  if (auto invOp = dyn_cast<LLVM::InvokeOp>(opInst)) {
291  auto operands = moduleTranslation.lookupValues(invOp.getCalleeOperands());
292  ArrayRef<llvm::Value *> operandsRef(operands);
293  llvm::Instruction *result;
294  if (auto attr = opInst.getAttrOfType<FlatSymbolRefAttr>("callee")) {
295  result = builder.CreateInvoke(
296  moduleTranslation.lookupFunction(attr.getValue()),
297  moduleTranslation.lookupBlock(invOp.getSuccessor(0)),
298  moduleTranslation.lookupBlock(invOp.getSuccessor(1)), operandsRef);
299  } else {
300  result = builder.CreateInvoke(
301  getCalleeFunctionType(invOp.getResultTypes(), invOp.getArgOperands()),
302  operandsRef.front(),
303  moduleTranslation.lookupBlock(invOp.getSuccessor(0)),
304  moduleTranslation.lookupBlock(invOp.getSuccessor(1)),
305  operandsRef.drop_front());
306  }
307  moduleTranslation.mapBranch(invOp, result);
308  // InvokeOp can only have 0 or 1 result
309  if (invOp->getNumResults() != 0) {
310  moduleTranslation.mapValue(opInst.getResult(0), result);
311  return success();
312  }
313  return success(result->getType()->isVoidTy());
314  }
315 
316  if (auto lpOp = dyn_cast<LLVM::LandingpadOp>(opInst)) {
317  llvm::Type *ty = moduleTranslation.convertType(lpOp.getType());
318  llvm::LandingPadInst *lpi =
319  builder.CreateLandingPad(ty, lpOp.getNumOperands());
320  lpi->setCleanup(lpOp.getCleanup());
321 
322  // Add clauses
323  for (llvm::Value *operand :
324  moduleTranslation.lookupValues(lpOp.getOperands())) {
325  // All operands should be constant - checked by verifier
326  if (auto *constOperand = dyn_cast<llvm::Constant>(operand))
327  lpi->addClause(constOperand);
328  }
329  moduleTranslation.mapValue(lpOp.getResult(), lpi);
330  return success();
331  }
332 
333  // Emit branches. We need to look up the remapped blocks and ignore the
334  // block arguments that were transformed into PHI nodes.
335  if (auto brOp = dyn_cast<LLVM::BrOp>(opInst)) {
336  llvm::BranchInst *branch =
337  builder.CreateBr(moduleTranslation.lookupBlock(brOp.getSuccessor()));
338  moduleTranslation.mapBranch(&opInst, branch);
339  moduleTranslation.setLoopMetadata(&opInst, branch);
340  return success();
341  }
342  if (auto condbrOp = dyn_cast<LLVM::CondBrOp>(opInst)) {
343  llvm::BranchInst *branch = builder.CreateCondBr(
344  moduleTranslation.lookupValue(condbrOp.getOperand(0)),
345  moduleTranslation.lookupBlock(condbrOp.getSuccessor(0)),
346  moduleTranslation.lookupBlock(condbrOp.getSuccessor(1)));
347  moduleTranslation.mapBranch(&opInst, branch);
348  moduleTranslation.setLoopMetadata(&opInst, branch);
349  return success();
350  }
351  if (auto switchOp = dyn_cast<LLVM::SwitchOp>(opInst)) {
352  llvm::SwitchInst *switchInst = builder.CreateSwitch(
353  moduleTranslation.lookupValue(switchOp.getValue()),
354  moduleTranslation.lookupBlock(switchOp.getDefaultDestination()),
355  switchOp.getCaseDestinations().size());
356 
357  // Handle switch with zero cases.
358  if (!switchOp.getCaseValues())
359  return success();
360 
361  auto *ty = llvm::cast<llvm::IntegerType>(
362  moduleTranslation.convertType(switchOp.getValue().getType()));
363  for (auto i :
364  llvm::zip(llvm::cast<DenseIntElementsAttr>(*switchOp.getCaseValues()),
365  switchOp.getCaseDestinations()))
366  switchInst->addCase(
367  llvm::ConstantInt::get(ty, std::get<0>(i).getLimitedValue()),
368  moduleTranslation.lookupBlock(std::get<1>(i)));
369 
370  moduleTranslation.mapBranch(&opInst, switchInst);
371  return success();
372  }
373 
374  // Emit addressof. We need to look up the global value referenced by the
375  // operation and store it in the MLIR-to-LLVM value mapping. This does not
376  // emit any LLVM instruction.
377  if (auto addressOfOp = dyn_cast<LLVM::AddressOfOp>(opInst)) {
378  LLVM::GlobalOp global =
379  addressOfOp.getGlobal(moduleTranslation.symbolTable());
380  LLVM::LLVMFuncOp function =
381  addressOfOp.getFunction(moduleTranslation.symbolTable());
382 
383  // The verifier should not have allowed this.
384  assert((global || function) &&
385  "referencing an undefined global or function");
386 
387  moduleTranslation.mapValue(
388  addressOfOp.getResult(),
389  global ? moduleTranslation.lookupGlobal(global)
390  : moduleTranslation.lookupFunction(function.getName()));
391  return success();
392  }
393 
394  return failure();
395 }
396 
397 namespace {
398 /// Implementation of the dialect interface that converts operations belonging
399 /// to the LLVM dialect to LLVM IR.
400 class LLVMDialectLLVMIRTranslationInterface
402 public:
404 
405  /// Translates the given operation to LLVM IR using the provided IR builder
406  /// and saving the state in `moduleTranslation`.
408  convertOperation(Operation *op, llvm::IRBuilderBase &builder,
409  LLVM::ModuleTranslation &moduleTranslation) const final {
410  return convertOperationImpl(*op, builder, moduleTranslation);
411  }
412 };
413 } // namespace
414 
416  registry.insert<LLVM::LLVMDialect>();
417  registry.addExtension(+[](MLIRContext *ctx, LLVM::LLVMDialect *dialect) {
418  dialect->addInterfaces<LLVMDialectLLVMIRTranslationInterface>();
419  });
420 }
421 
423  DialectRegistry registry;
425  context.appendDialectRegistry(registry);
426 }
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 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 LogicalResult convertCallLLVMIntrinsicOp(CallIntrinsicOp op, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
Builder for LLVM_CallIntrinsicOp.
static llvm::FastMathFlags getFastmathFlags(FastmathFlagsInterface &op)
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.
Attributes are known-constant values of operations.
Definition: Attributes.h:25
The DialectRegistry maps a dialect namespace to a constructor for the matching dialect.
void addExtension(std::unique_ptr< DialectExtensionBase > extension)
Add the given extension to the registry.
This class provides support for representing a failure result, or a valid value of type T.
Definition: LogicalResult.h:78
A symbol reference with a reference path containing a single element.
Base class for dialect interfaces providing translation to LLVM IR.
Implementation class for module translation.
llvm::Value * lookupValue(Value value) const
Finds an LLVM IR value corresponding to the given MLIR value.
void mapCall(Operation *mlir, llvm::CallInst *llvm)
Stores a mapping between an MLIR call operation and a corresponding LLVM call instruction.
void mapBranch(Operation *mlir, llvm::Instruction *llvm)
Stores the mapping between an MLIR operation with successors and a corresponding LLVM IR instruction.
SmallVector< llvm::Value * > lookupValues(ValueRange values)
Looks up remapped a list of remapped values.
llvm::BasicBlock * lookupBlock(Block *block) const
Finds an LLVM IR basic block that corresponds to the given MLIR block.
SymbolTableCollection & symbolTable()
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::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::Function * lookupFunction(StringRef name) const
Finds an LLVM IR function by its name.
void setAliasScopeMetadata(AliasAnalysisOpInterface op, llvm::Instruction *inst)
void setAccessGroupsMetadata(AccessGroupOpInterface op, llvm::Instruction *inst)
MLIRContext & getContext()
Returns the MLIR context of the module being translated.
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.
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:60
void appendDialectRegistry(const DialectRegistry &registry)
Append the contents of the given dialect registry to the registry associated with this context.
Operation is the basic unit of execution within MLIR.
Definition: Operation.h:88
AttrClass getAttrOfType(StringAttr name)
Definition: Operation.h:528
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Definition: Operation.h:402
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
unsigned getNumOperands()
Definition: Operation.h:341
operand_type_range getOperandTypes()
Definition: Operation.h:392
result_type_range getResultTypes()
Definition: Operation.h:423
operand_range getOperands()
Returns an iterator on the underlying Value's.
Definition: Operation.h:373
result_range getResults()
Definition: Operation.h:410
unsigned getNumResults()
Return the number of results held by this operation.
Definition: Operation.h:399
This class provides an abstraction over the various different ranges of value types.
Definition: TypeRange.h:36
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
Type front()
Return first type in the range.
Definition: TypeRange.h:148
Type getType() const
Return the type of this value.
Definition: Value.h:122
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.
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.
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
Definition: Matchers.h:285
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
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
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...
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value.
Definition: LogicalResult.h:72
This class represents an efficient way to signal success or failure.
Definition: LogicalResult.h:26