MLIR  22.0.0git
FuncToLLVM.cpp
Go to the documentation of this file.
1 //===- FuncToLLVM.cpp - Func to LLVM dialect 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 a pass to convert MLIR Func and builtin dialects
10 // into the LLVM IR dialect.
11 //
12 //===----------------------------------------------------------------------===//
13 
15 
27 #include "mlir/IR/Attributes.h"
28 #include "mlir/IR/Builders.h"
30 #include "mlir/IR/BuiltinOps.h"
31 #include "mlir/IR/PatternMatch.h"
32 #include "mlir/IR/SymbolTable.h"
33 #include "mlir/IR/TypeUtilities.h"
35 #include "mlir/Transforms/Passes.h"
36 #include "llvm/ADT/SmallVector.h"
37 #include "llvm/IR/Type.h"
38 #include "llvm/Support/FormatVariadic.h"
39 #include <optional>
40 
41 namespace mlir {
42 #define GEN_PASS_DEF_CONVERTFUNCTOLLVMPASS
43 #define GEN_PASS_DEF_SETLLVMMODULEDATALAYOUTPASS
44 #include "mlir/Conversion/Passes.h.inc"
45 } // namespace mlir
46 
47 using namespace mlir;
48 
49 #define PASS_NAME "convert-func-to-llvm"
50 
51 static constexpr StringRef varargsAttrName = "func.varargs";
52 static constexpr StringRef linkageAttrName = "llvm.linkage";
53 static constexpr StringRef barePtrAttrName = "llvm.bareptr";
54 
55 /// Return `true` if the `op` should use bare pointer calling convention.
57  const LLVMTypeConverter *typeConverter) {
58  return (op && op->hasAttr(barePtrAttrName)) ||
59  typeConverter->getOptions().useBarePtrCallConv;
60 }
61 
62 /// Only retain those attributes that are not constructed by
63 /// `LLVMFuncOp::build`.
64 static void filterFuncAttributes(FunctionOpInterface func,
66  for (const NamedAttribute &attr : func->getDiscardableAttrs()) {
67  if (attr.getName() == linkageAttrName ||
68  attr.getName() == varargsAttrName ||
69  attr.getName() == LLVM::LLVMDialect::getReadnoneAttrName())
70  continue;
71  result.push_back(attr);
72  }
73 }
74 
75 /// Propagate argument/results attributes.
76 static void propagateArgResAttrs(OpBuilder &builder, bool resultStructType,
77  FunctionOpInterface funcOp,
78  LLVM::LLVMFuncOp wrapperFuncOp) {
79  auto argAttrs = funcOp.getAllArgAttrs();
80  if (!resultStructType) {
81  if (auto resAttrs = funcOp.getAllResultAttrs())
82  wrapperFuncOp.setAllResultAttrs(resAttrs);
83  if (argAttrs)
84  wrapperFuncOp.setAllArgAttrs(argAttrs);
85  } else {
86  SmallVector<Attribute> argAttributes;
87  // Only modify the argument and result attributes when the result is now
88  // an argument.
89  if (argAttrs) {
90  argAttributes.push_back(builder.getDictionaryAttr({}));
91  argAttributes.append(argAttrs.begin(), argAttrs.end());
92  wrapperFuncOp.setAllArgAttrs(argAttributes);
93  }
94  }
95  cast<FunctionOpInterface>(wrapperFuncOp.getOperation())
96  .setVisibility(funcOp.getVisibility());
97 }
98 
99 /// Creates an auxiliary function with pointer-to-memref-descriptor-struct
100 /// arguments instead of unpacked arguments. This function can be called from C
101 /// by passing a pointer to a C struct corresponding to a memref descriptor.
102 /// Similarly, returned memrefs are passed via pointers to a C struct that is
103 /// passed as additional argument.
104 /// Internally, the auxiliary function unpacks the descriptor into individual
105 /// components and forwards them to `newFuncOp` and forwards the results to
106 /// the extra arguments.
107 static void wrapForExternalCallers(OpBuilder &rewriter, Location loc,
108  const LLVMTypeConverter &typeConverter,
109  FunctionOpInterface funcOp,
110  LLVM::LLVMFuncOp newFuncOp) {
111  auto type = cast<FunctionType>(funcOp.getFunctionType());
112  auto [wrapperFuncType, resultStructType] =
113  typeConverter.convertFunctionTypeCWrapper(type);
114 
115  SmallVector<NamedAttribute> attributes;
116  filterFuncAttributes(funcOp, attributes);
117 
118  auto wrapperFuncOp = LLVM::LLVMFuncOp::create(
119  rewriter, loc, llvm::formatv("_mlir_ciface_{0}", funcOp.getName()).str(),
120  wrapperFuncType, LLVM::Linkage::External, /*dsoLocal=*/false,
121  /*cconv=*/LLVM::CConv::C, /*comdat=*/nullptr, attributes);
122  propagateArgResAttrs(rewriter, !!resultStructType, funcOp, wrapperFuncOp);
123 
124  OpBuilder::InsertionGuard guard(rewriter);
125  rewriter.setInsertionPointToStart(wrapperFuncOp.addEntryBlock(rewriter));
126 
128  size_t argOffset = resultStructType ? 1 : 0;
129  for (auto [index, argType] : llvm::enumerate(type.getInputs())) {
130  Value arg = wrapperFuncOp.getArgument(index + argOffset);
131  if (auto memrefType = dyn_cast<MemRefType>(argType)) {
132  Value loaded = LLVM::LoadOp::create(
133  rewriter, loc, typeConverter.convertType(memrefType), arg);
134  MemRefDescriptor::unpack(rewriter, loc, loaded, memrefType, args);
135  continue;
136  }
137  if (isa<UnrankedMemRefType>(argType)) {
138  Value loaded = LLVM::LoadOp::create(
139  rewriter, loc, typeConverter.convertType(argType), arg);
140  UnrankedMemRefDescriptor::unpack(rewriter, loc, loaded, args);
141  continue;
142  }
143 
144  args.push_back(arg);
145  }
146 
147  auto call = LLVM::CallOp::create(rewriter, loc, newFuncOp, args);
148 
149  if (resultStructType) {
150  LLVM::StoreOp::create(rewriter, loc, call.getResult(),
151  wrapperFuncOp.getArgument(0));
152  LLVM::ReturnOp::create(rewriter, loc, ValueRange{});
153  } else {
154  LLVM::ReturnOp::create(rewriter, loc, call.getResults());
155  }
156 }
157 
158 /// Creates an auxiliary function with pointer-to-memref-descriptor-struct
159 /// arguments instead of unpacked arguments. Creates a body for the (external)
160 /// `newFuncOp` that allocates a memref descriptor on stack, packs the
161 /// individual arguments into this descriptor and passes a pointer to it into
162 /// the auxiliary function. If the result of the function cannot be directly
163 /// returned, we write it to a special first argument that provides a pointer
164 /// to a corresponding struct. This auxiliary external function is now
165 /// compatible with functions defined in C using pointers to C structs
166 /// corresponding to a memref descriptor.
167 static void wrapExternalFunction(OpBuilder &builder, Location loc,
168  const LLVMTypeConverter &typeConverter,
169  FunctionOpInterface funcOp,
170  LLVM::LLVMFuncOp newFuncOp) {
171  OpBuilder::InsertionGuard guard(builder);
172 
173  auto [wrapperType, resultStructType] =
174  typeConverter.convertFunctionTypeCWrapper(
175  cast<FunctionType>(funcOp.getFunctionType()));
176  // This conversion can only fail if it could not convert one of the argument
177  // types. But since it has been applied to a non-wrapper function before, it
178  // should have failed earlier and not reach this point at all.
179  assert(wrapperType && "unexpected type conversion failure");
180 
182  filterFuncAttributes(funcOp, attributes);
183 
184  // Create the auxiliary function.
185  auto wrapperFunc = LLVM::LLVMFuncOp::create(
186  builder, loc, llvm::formatv("_mlir_ciface_{0}", funcOp.getName()).str(),
187  wrapperType, LLVM::Linkage::External, /*dsoLocal=*/false,
188  /*cconv=*/LLVM::CConv::C, /*comdat=*/nullptr, attributes);
189  propagateArgResAttrs(builder, !!resultStructType, funcOp, wrapperFunc);
190 
191  // The wrapper that we synthetize here should only be visible in this module.
192  newFuncOp.setLinkage(LLVM::Linkage::Private);
193  builder.setInsertionPointToStart(newFuncOp.addEntryBlock(builder));
194 
195  // Get a ValueRange containing arguments.
196  FunctionType type = cast<FunctionType>(funcOp.getFunctionType());
198  args.reserve(type.getNumInputs());
199  ValueRange wrapperArgsRange(newFuncOp.getArguments());
200 
201  if (resultStructType) {
202  // Allocate the struct on the stack and pass the pointer.
203  Type resultType = cast<LLVM::LLVMFunctionType>(wrapperType).getParamType(0);
204  Value one = LLVM::ConstantOp::create(
205  builder, loc, typeConverter.convertType(builder.getIndexType()),
206  builder.getIntegerAttr(builder.getIndexType(), 1));
207  Value result =
208  LLVM::AllocaOp::create(builder, loc, resultType, resultStructType, one);
209  args.push_back(result);
210  }
211 
212  // Iterate over the inputs of the original function and pack values into
213  // memref descriptors if the original type is a memref.
214  for (Type input : type.getInputs()) {
215  Value arg;
216  int numToDrop = 1;
217  auto memRefType = dyn_cast<MemRefType>(input);
218  auto unrankedMemRefType = dyn_cast<UnrankedMemRefType>(input);
219  if (memRefType || unrankedMemRefType) {
220  numToDrop = memRefType
223  Value packed =
224  memRefType
225  ? MemRefDescriptor::pack(builder, loc, typeConverter, memRefType,
226  wrapperArgsRange.take_front(numToDrop))
228  builder, loc, typeConverter, unrankedMemRefType,
229  wrapperArgsRange.take_front(numToDrop));
230 
231  auto ptrTy = LLVM::LLVMPointerType::get(builder.getContext());
232  Value one = LLVM::ConstantOp::create(
233  builder, loc, typeConverter.convertType(builder.getIndexType()),
234  builder.getIntegerAttr(builder.getIndexType(), 1));
235  Value allocated = LLVM::AllocaOp::create(
236  builder, loc, ptrTy, packed.getType(), one, /*alignment=*/0);
237  LLVM::StoreOp::create(builder, loc, packed, allocated);
238  arg = allocated;
239  } else {
240  arg = wrapperArgsRange[0];
241  }
242 
243  args.push_back(arg);
244  wrapperArgsRange = wrapperArgsRange.drop_front(numToDrop);
245  }
246  assert(wrapperArgsRange.empty() && "did not map some of the arguments");
247 
248  auto call = LLVM::CallOp::create(builder, loc, wrapperFunc, args);
249 
250  if (resultStructType) {
251  Value result =
252  LLVM::LoadOp::create(builder, loc, resultStructType, args.front());
253  LLVM::ReturnOp::create(builder, loc, result);
254  } else {
255  LLVM::ReturnOp::create(builder, loc, call.getResults());
256  }
257 }
258 
259 /// Inserts `llvm.load` ops in the function body to restore the expected pointee
260 /// value from `llvm.byval`/`llvm.byref` function arguments that were converted
261 /// to LLVM pointer types.
263  ConversionPatternRewriter &rewriter, const LLVMTypeConverter &typeConverter,
264  ArrayRef<std::optional<NamedAttribute>> byValRefNonPtrAttrs,
265  LLVM::LLVMFuncOp funcOp) {
266  // Nothing to do for function declarations.
267  if (funcOp.isExternal())
268  return;
269 
270  ConversionPatternRewriter::InsertionGuard guard(rewriter);
271  rewriter.setInsertionPointToStart(&funcOp.getFunctionBody().front());
272 
273  for (const auto &[arg, byValRefAttr] :
274  llvm::zip(funcOp.getArguments(), byValRefNonPtrAttrs)) {
275  // Skip argument if no `llvm.byval` or `llvm.byref` attribute.
276  if (!byValRefAttr)
277  continue;
278 
279  // Insert load to retrieve the actual argument passed by value/reference.
280  assert(isa<LLVM::LLVMPointerType>(arg.getType()) &&
281  "Expected LLVM pointer type for argument with "
282  "`llvm.byval`/`llvm.byref` attribute");
283  Type resTy = typeConverter.convertType(
284  cast<TypeAttr>(byValRefAttr->getValue()).getValue());
285 
286  Value valueArg = LLVM::LoadOp::create(rewriter, arg.getLoc(), resTy, arg);
287  rewriter.replaceUsesOfBlockArgument(arg, valueArg);
288  }
289 }
290 
291 FailureOr<LLVM::LLVMFuncOp> mlir::convertFuncOpToLLVMFuncOp(
292  FunctionOpInterface funcOp, ConversionPatternRewriter &rewriter,
293  const LLVMTypeConverter &converter, SymbolTableCollection *symbolTables) {
294  // Check the funcOp has `FunctionType`.
295  auto funcTy = dyn_cast<FunctionType>(funcOp.getFunctionType());
296  if (!funcTy)
297  return rewriter.notifyMatchFailure(
298  funcOp, "Only support FunctionOpInterface with FunctionType");
299 
300  // Convert the original function arguments. They are converted using the
301  // LLVMTypeConverter provided to this legalization pattern.
302  auto varargsAttr = funcOp->getAttrOfType<BoolAttr>(varargsAttrName);
303  // Gather `llvm.byval` and `llvm.byref` arguments whose type convertion was
304  // overriden with an LLVM pointer type for later processing.
305  SmallVector<std::optional<NamedAttribute>> byValRefNonPtrAttrs;
306  TypeConverter::SignatureConversion result(funcOp.getNumArguments());
307  auto llvmType = dyn_cast_or_null<LLVM::LLVMFunctionType>(
308  converter.convertFunctionSignature(
309  funcOp, varargsAttr && varargsAttr.getValue(),
310  shouldUseBarePtrCallConv(funcOp, &converter), result,
311  byValRefNonPtrAttrs));
312  if (!llvmType)
313  return rewriter.notifyMatchFailure(funcOp, "signature conversion failed");
314 
315  // Check for unsupported variadic functions.
316  if (!shouldUseBarePtrCallConv(funcOp, &converter))
317  if (funcOp->getAttrOfType<UnitAttr>(
318  LLVM::LLVMDialect::getEmitCWrapperAttrName()))
319  if (llvmType.isVarArg())
320  return funcOp.emitError("C interface for variadic functions is not "
321  "supported yet.");
322 
323  // Create an LLVM function, use external linkage by default until MLIR
324  // functions have linkage.
325  LLVM::Linkage linkage = LLVM::Linkage::External;
326  if (funcOp->hasAttr(linkageAttrName)) {
327  auto attr =
328  dyn_cast<mlir::LLVM::LinkageAttr>(funcOp->getAttr(linkageAttrName));
329  if (!attr) {
330  funcOp->emitError() << "Contains " << linkageAttrName
331  << " attribute not of type LLVM::LinkageAttr";
332  return rewriter.notifyMatchFailure(
333  funcOp, "Contains linkage attribute not of type LLVM::LinkageAttr");
334  }
335  linkage = attr.getLinkage();
336  }
337 
338  // Check for invalid attributes.
339  StringRef readnoneAttrName = LLVM::LLVMDialect::getReadnoneAttrName();
340  if (funcOp->hasAttr(readnoneAttrName)) {
341  auto attr = funcOp->getAttrOfType<UnitAttr>(readnoneAttrName);
342  if (!attr) {
343  funcOp->emitError() << "Contains " << readnoneAttrName
344  << " attribute not of type UnitAttr";
345  return rewriter.notifyMatchFailure(
346  funcOp, "Contains readnone attribute not of type UnitAttr");
347  }
348  }
349 
351  filterFuncAttributes(funcOp, attributes);
352 
353  Operation *symbolTableOp = funcOp->getParentWithTrait<OpTrait::SymbolTable>();
354 
355  if (symbolTables && symbolTableOp) {
356  SymbolTable &symbolTable = symbolTables->getSymbolTable(symbolTableOp);
357  symbolTable.remove(funcOp);
358  }
359 
360  auto newFuncOp = LLVM::LLVMFuncOp::create(
361  rewriter, funcOp.getLoc(), funcOp.getName(), llvmType, linkage,
362  /*dsoLocal=*/false, /*cconv=*/LLVM::CConv::C, /*comdat=*/nullptr,
363  attributes);
364 
365  if (symbolTables && symbolTableOp) {
366  auto ip = rewriter.getInsertionPoint();
367  SymbolTable &symbolTable = symbolTables->getSymbolTable(symbolTableOp);
368  symbolTable.insert(newFuncOp, ip);
369  }
370 
371  cast<FunctionOpInterface>(newFuncOp.getOperation())
372  .setVisibility(funcOp.getVisibility());
373 
374  // Create a memory effect attribute corresponding to readnone.
375  if (funcOp->hasAttr(readnoneAttrName)) {
376  auto memoryAttr = LLVM::MemoryEffectsAttr::get(
377  rewriter.getContext(),
378  {LLVM::ModRefInfo::NoModRef, LLVM::ModRefInfo::NoModRef,
379  LLVM::ModRefInfo::NoModRef});
380  newFuncOp.setMemoryEffectsAttr(memoryAttr);
381  }
382 
383  // Propagate argument/result attributes to all converted arguments/result
384  // obtained after converting a given original argument/result.
385  if (ArrayAttr resAttrDicts = funcOp.getAllResultAttrs()) {
386  assert(!resAttrDicts.empty() && "expected array to be non-empty");
387  if (funcOp.getNumResults() == 1)
388  newFuncOp.setAllResultAttrs(resAttrDicts);
389  }
390  if (ArrayAttr argAttrDicts = funcOp.getAllArgAttrs()) {
391  SmallVector<Attribute> newArgAttrs(
392  cast<LLVM::LLVMFunctionType>(llvmType).getNumParams());
393  for (unsigned i = 0, e = funcOp.getNumArguments(); i < e; ++i) {
394  // Some LLVM IR attribute have a type attached to them. During FuncOp ->
395  // LLVMFuncOp conversion these types may have changed. Account for that
396  // change by converting attributes' types as well.
397  SmallVector<NamedAttribute, 4> convertedAttrs;
398  auto attrsDict = cast<DictionaryAttr>(argAttrDicts[i]);
399  convertedAttrs.reserve(attrsDict.size());
400  for (const NamedAttribute &attr : attrsDict) {
401  const auto convert = [&](const NamedAttribute &attr) {
402  return TypeAttr::get(converter.convertType(
403  cast<TypeAttr>(attr.getValue()).getValue()));
404  };
405  if (attr.getName().getValue() ==
406  LLVM::LLVMDialect::getByValAttrName()) {
407  convertedAttrs.push_back(rewriter.getNamedAttr(
408  LLVM::LLVMDialect::getByValAttrName(), convert(attr)));
409  } else if (attr.getName().getValue() ==
410  LLVM::LLVMDialect::getByRefAttrName()) {
411  convertedAttrs.push_back(rewriter.getNamedAttr(
412  LLVM::LLVMDialect::getByRefAttrName(), convert(attr)));
413  } else if (attr.getName().getValue() ==
414  LLVM::LLVMDialect::getStructRetAttrName()) {
415  convertedAttrs.push_back(rewriter.getNamedAttr(
416  LLVM::LLVMDialect::getStructRetAttrName(), convert(attr)));
417  } else if (attr.getName().getValue() ==
418  LLVM::LLVMDialect::getInAllocaAttrName()) {
419  convertedAttrs.push_back(rewriter.getNamedAttr(
420  LLVM::LLVMDialect::getInAllocaAttrName(), convert(attr)));
421  } else {
422  convertedAttrs.push_back(attr);
423  }
424  }
425  auto mapping = result.getInputMapping(i);
426  assert(mapping && "unexpected deletion of function argument");
427  // Only attach the new argument attributes if there is a one-to-one
428  // mapping from old to new types. Otherwise, attributes might be
429  // attached to types that they do not support.
430  if (mapping->size == 1) {
431  newArgAttrs[mapping->inputNo] =
432  DictionaryAttr::get(rewriter.getContext(), convertedAttrs);
433  continue;
434  }
435  // TODO: Implement custom handling for types that expand to multiple
436  // function arguments.
437  for (size_t j = 0; j < mapping->size; ++j)
438  newArgAttrs[mapping->inputNo + j] =
439  DictionaryAttr::get(rewriter.getContext(), {});
440  }
441  if (!newArgAttrs.empty())
442  newFuncOp.setAllArgAttrs(rewriter.getArrayAttr(newArgAttrs));
443  }
444 
445  rewriter.inlineRegionBefore(funcOp.getFunctionBody(), newFuncOp.getBody(),
446  newFuncOp.end());
447  // Convert just the entry block. The remaining unstructured control flow is
448  // converted by ControlFlowToLLVM.
449  if (!newFuncOp.getBody().empty())
450  rewriter.applySignatureConversion(&newFuncOp.getBody().front(), result,
451  &converter);
452 
453  // Fix the type mismatch between the materialized `llvm.ptr` and the expected
454  // pointee type in the function body when converting `llvm.byval`/`llvm.byref`
455  // function arguments.
456  restoreByValRefArgumentType(rewriter, converter, byValRefNonPtrAttrs,
457  newFuncOp);
458 
459  if (!shouldUseBarePtrCallConv(funcOp, &converter)) {
460  if (funcOp->getAttrOfType<UnitAttr>(
461  LLVM::LLVMDialect::getEmitCWrapperAttrName())) {
462  if (newFuncOp.isExternal())
463  wrapExternalFunction(rewriter, funcOp->getLoc(), converter, funcOp,
464  newFuncOp);
465  else
466  wrapForExternalCallers(rewriter, funcOp->getLoc(), converter, funcOp,
467  newFuncOp);
468  }
469  }
470 
471  return newFuncOp;
472 }
473 
474 namespace {
475 
476 /// FuncOp legalization pattern that converts MemRef arguments to pointers to
477 /// MemRef descriptors (LLVM struct data types) containing all the MemRef type
478 /// information.
479 class FuncOpConversion : public ConvertOpToLLVMPattern<func::FuncOp> {
480  SymbolTableCollection *symbolTables = nullptr;
481 
482 public:
483  explicit FuncOpConversion(const LLVMTypeConverter &converter,
484  SymbolTableCollection *symbolTables = nullptr)
485  : ConvertOpToLLVMPattern(converter), symbolTables(symbolTables) {}
486 
487  LogicalResult
488  matchAndRewrite(func::FuncOp funcOp, OpAdaptor adaptor,
489  ConversionPatternRewriter &rewriter) const override {
490  FailureOr<LLVM::LLVMFuncOp> newFuncOp = mlir::convertFuncOpToLLVMFuncOp(
491  cast<FunctionOpInterface>(funcOp.getOperation()), rewriter,
492  *getTypeConverter(), symbolTables);
493  if (failed(newFuncOp))
494  return rewriter.notifyMatchFailure(funcOp, "Could not convert funcop");
495 
496  rewriter.eraseOp(funcOp);
497  return success();
498  }
499 };
500 
501 struct ConstantOpLowering : public ConvertOpToLLVMPattern<func::ConstantOp> {
503 
504  LogicalResult
505  matchAndRewrite(func::ConstantOp op, OpAdaptor adaptor,
506  ConversionPatternRewriter &rewriter) const override {
507  auto type = typeConverter->convertType(op.getResult().getType());
508  if (!type || !LLVM::isCompatibleType(type))
509  return rewriter.notifyMatchFailure(op, "failed to convert result type");
510 
511  auto newOp =
512  LLVM::AddressOfOp::create(rewriter, op.getLoc(), type, op.getValue());
513  for (const NamedAttribute &attr : op->getAttrs()) {
514  if (attr.getName().strref() == "value")
515  continue;
516  newOp->setAttr(attr.getName(), attr.getValue());
517  }
518  rewriter.replaceOp(op, newOp->getResults());
519  return success();
520  }
521 };
522 
523 // A CallOp automatically promotes MemRefType to a sequence of alloca/store and
524 // passes the pointer to the MemRef across function boundaries.
525 template <typename CallOpType>
526 struct CallOpInterfaceLowering : public ConvertOpToLLVMPattern<CallOpType> {
528  using Super = CallOpInterfaceLowering<CallOpType>;
531 
532  LogicalResult matchAndRewriteImpl(CallOpType callOp, Adaptor adaptor,
533  ConversionPatternRewriter &rewriter,
534  bool useBarePtrCallConv = false) const {
535  // Pack the result types into a struct.
536  Type packedResult = nullptr;
537  SmallVector<SmallVector<Type>> groupedResultTypes;
538  unsigned numResults = callOp.getNumResults();
539  auto resultTypes = llvm::to_vector<4>(callOp.getResultTypes());
540  int64_t numConvertedTypes = 0;
541  if (numResults != 0) {
542  if (!(packedResult = this->getTypeConverter()->packFunctionResults(
543  resultTypes, useBarePtrCallConv, &groupedResultTypes,
544  &numConvertedTypes)))
545  return failure();
546  }
547 
548  if (useBarePtrCallConv) {
549  for (auto it : callOp->getOperands()) {
550  Type operandType = it.getType();
551  if (isa<UnrankedMemRefType>(operandType)) {
552  // Unranked memref is not supported in the bare pointer calling
553  // convention.
554  return failure();
555  }
556  }
557  }
558  auto promoted = this->getTypeConverter()->promoteOperands(
559  callOp.getLoc(), /*opOperands=*/callOp->getOperands(),
560  adaptor.getOperands(), rewriter, useBarePtrCallConv);
561  auto newOp = LLVM::CallOp::create(rewriter, callOp.getLoc(),
562  packedResult ? TypeRange(packedResult)
563  : TypeRange(),
564  promoted, callOp->getAttrs());
565 
566  newOp.getProperties().operandSegmentSizes = {
567  static_cast<int32_t>(promoted.size()), 0};
568  newOp.getProperties().op_bundle_sizes = rewriter.getDenseI32ArrayAttr({});
569 
570  // Helper function that extracts an individual result from the return value
571  // of the new call op. llvm.call ops support only 0 or 1 result. In case of
572  // 2 or more results, the results are packed into a structure.
573  //
574  // The new call op may have more than 2 results because:
575  // a. The original call op has more than 2 results.
576  // b. An original op result type-converted to more than 1 result.
577  auto getUnpackedResult = [&](unsigned i) -> Value {
578  assert(numConvertedTypes > 0 && "convert op has no results");
579  if (numConvertedTypes == 1) {
580  assert(i == 0 && "out of bounds: converted op has only one result");
581  return newOp->getResult(0);
582  }
583  // Results have been converted to a structure. Extract individual results
584  // from the structure.
585  return LLVM::ExtractValueOp::create(rewriter, callOp.getLoc(),
586  newOp->getResult(0), i);
587  };
588 
589  // Group the results into a vector of vectors, such that it is clear which
590  // original op result is replaced with which range of values. (In case of a
591  // 1:N conversion, there can be multiple replacements for a single result.)
593  results.reserve(numResults);
594  unsigned counter = 0;
595  for (unsigned i = 0; i < numResults; ++i) {
596  SmallVector<Value> &group = results.emplace_back();
597  for (unsigned j = 0, e = groupedResultTypes[i].size(); j < e; ++j)
598  group.push_back(getUnpackedResult(counter++));
599  }
600 
601  // Special handling for MemRef types.
602  for (unsigned i = 0; i < numResults; ++i) {
603  Type origType = resultTypes[i];
604  auto memrefType = dyn_cast<MemRefType>(origType);
605  auto unrankedMemrefType = dyn_cast<UnrankedMemRefType>(origType);
606  if (useBarePtrCallConv && memrefType) {
607  // For the bare-ptr calling convention, promote memref results to
608  // descriptors.
609  assert(results[i].size() == 1 && "expected one converted result");
610  results[i].front() = MemRefDescriptor::fromStaticShape(
611  rewriter, callOp.getLoc(), *this->getTypeConverter(), memrefType,
612  results[i].front());
613  }
614  if (unrankedMemrefType) {
615  assert(!useBarePtrCallConv && "unranked memref is not supported in the "
616  "bare-ptr calling convention");
617  assert(results[i].size() == 1 && "expected one converted result");
618  Value desc = this->copyUnrankedDescriptor(
619  rewriter, callOp.getLoc(), unrankedMemrefType, results[i].front(),
620  /*toDynamic=*/false);
621  if (!desc)
622  return failure();
623  results[i].front() = desc;
624  }
625  }
626 
627  rewriter.replaceOpWithMultiple(callOp, results);
628  return success();
629  }
630 };
631 
632 class CallOpLowering : public CallOpInterfaceLowering<func::CallOp> {
633 public:
634  explicit CallOpLowering(const LLVMTypeConverter &typeConverter,
635  SymbolTableCollection *symbolTables = nullptr,
636  PatternBenefit benefit = 1)
637  : CallOpInterfaceLowering<func::CallOp>(typeConverter, benefit),
638  symbolTables(symbolTables) {}
639 
640  LogicalResult
641  matchAndRewrite(func::CallOp callOp, OneToNOpAdaptor adaptor,
642  ConversionPatternRewriter &rewriter) const override {
643  bool useBarePtrCallConv = false;
644  if (getTypeConverter()->getOptions().useBarePtrCallConv) {
645  useBarePtrCallConv = true;
646  } else if (symbolTables != nullptr) {
647  // Fast lookup.
648  Operation *callee =
649  symbolTables->lookupNearestSymbolFrom(callOp, callOp.getCalleeAttr());
650  useBarePtrCallConv =
651  callee != nullptr && callee->hasAttr(barePtrAttrName);
652  } else {
653  // Warning: This is a linear lookup.
654  Operation *callee =
655  SymbolTable::lookupNearestSymbolFrom(callOp, callOp.getCalleeAttr());
656  useBarePtrCallConv =
657  callee != nullptr && callee->hasAttr(barePtrAttrName);
658  }
659  return matchAndRewriteImpl(callOp, adaptor, rewriter, useBarePtrCallConv);
660  }
661 
662 private:
663  SymbolTableCollection *symbolTables = nullptr;
664 };
665 
666 struct CallIndirectOpLowering
667  : public CallOpInterfaceLowering<func::CallIndirectOp> {
668  using Super::Super;
669 
670  LogicalResult
671  matchAndRewrite(func::CallIndirectOp callIndirectOp, OneToNOpAdaptor adaptor,
672  ConversionPatternRewriter &rewriter) const override {
673  return matchAndRewriteImpl(callIndirectOp, adaptor, rewriter);
674  }
675 };
676 
677 struct UnrealizedConversionCastOpLowering
678  : public ConvertOpToLLVMPattern<UnrealizedConversionCastOp> {
680  UnrealizedConversionCastOp>::ConvertOpToLLVMPattern;
681 
682  LogicalResult
683  matchAndRewrite(UnrealizedConversionCastOp op, OpAdaptor adaptor,
684  ConversionPatternRewriter &rewriter) const override {
685  SmallVector<Type> convertedTypes;
686  if (succeeded(typeConverter->convertTypes(op.getOutputs().getTypes(),
687  convertedTypes)) &&
688  convertedTypes == adaptor.getInputs().getTypes()) {
689  rewriter.replaceOp(op, adaptor.getInputs());
690  return success();
691  }
692 
693  convertedTypes.clear();
694  if (succeeded(typeConverter->convertTypes(adaptor.getInputs().getTypes(),
695  convertedTypes)) &&
696  convertedTypes == op.getOutputs().getType()) {
697  rewriter.replaceOp(op, adaptor.getInputs());
698  return success();
699  }
700  return failure();
701  }
702 };
703 
704 // Special lowering pattern for `ReturnOps`. Unlike all other operations,
705 // `ReturnOp` interacts with the function signature and must have as many
706 // operands as the function has return values. Because in LLVM IR, functions
707 // can only return 0 or 1 value, we pack multiple values into a structure type.
708 // Emit `PoisonOp` followed by `InsertValueOp`s to create such structure if
709 // necessary before returning it
710 struct ReturnOpLowering : public ConvertOpToLLVMPattern<func::ReturnOp> {
712 
713  LogicalResult
714  matchAndRewrite(func::ReturnOp op, OneToNOpAdaptor adaptor,
715  ConversionPatternRewriter &rewriter) const override {
716  Location loc = op.getLoc();
717  SmallVector<Value, 4> updatedOperands;
718 
719  auto funcOp = op->getParentOfType<LLVM::LLVMFuncOp>();
720  bool useBarePtrCallConv =
721  shouldUseBarePtrCallConv(funcOp, this->getTypeConverter());
722 
723  for (auto [oldOperand, newOperands] :
724  llvm::zip_equal(op->getOperands(), adaptor.getOperands())) {
725  Type oldTy = oldOperand.getType();
726  if (auto memRefType = dyn_cast<MemRefType>(oldTy)) {
727  assert(newOperands.size() == 1 && "expected one converted result");
728  if (useBarePtrCallConv &&
729  getTypeConverter()->canConvertToBarePtr(memRefType)) {
730  // For the bare-ptr calling convention, extract the aligned pointer to
731  // be returned from the memref descriptor.
732  MemRefDescriptor memrefDesc(newOperands.front());
733  updatedOperands.push_back(memrefDesc.allocatedPtr(rewriter, loc));
734  continue;
735  }
736  } else if (auto unrankedMemRefType =
737  dyn_cast<UnrankedMemRefType>(oldTy)) {
738  assert(newOperands.size() == 1 && "expected one converted result");
739  if (useBarePtrCallConv) {
740  // Unranked memref is not supported in the bare pointer calling
741  // convention.
742  return failure();
743  }
744  Value updatedDesc =
745  copyUnrankedDescriptor(rewriter, loc, unrankedMemRefType,
746  newOperands.front(), /*toDynamic=*/true);
747  if (!updatedDesc)
748  return failure();
749  updatedOperands.push_back(updatedDesc);
750  continue;
751  }
752 
753  llvm::append_range(updatedOperands, newOperands);
754  }
755 
756  // If ReturnOp has 0 or 1 operand, create it and return immediately.
757  if (updatedOperands.size() <= 1) {
758  rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(
759  op, TypeRange(), updatedOperands, op->getAttrs());
760  return success();
761  }
762 
763  // Otherwise, we need to pack the arguments into an LLVM struct type before
764  // returning.
765  auto packedType = getTypeConverter()->packFunctionResults(
766  op.getOperandTypes(), useBarePtrCallConv);
767  if (!packedType) {
768  return rewriter.notifyMatchFailure(op, "could not convert result types");
769  }
770 
771  Value packed = LLVM::PoisonOp::create(rewriter, loc, packedType);
772  for (auto [idx, operand] : llvm::enumerate(updatedOperands)) {
773  packed = LLVM::InsertValueOp::create(rewriter, loc, packed, operand, idx);
774  }
775  rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(op, TypeRange(), packed,
776  op->getAttrs());
777  return success();
778  }
779 };
780 } // namespace
781 
783  const LLVMTypeConverter &converter, RewritePatternSet &patterns,
784  SymbolTableCollection *symbolTables) {
785  patterns.add<FuncOpConversion>(converter, symbolTables);
786 }
787 
789  const LLVMTypeConverter &converter, RewritePatternSet &patterns,
790  SymbolTableCollection *symbolTables) {
791  populateFuncToLLVMFuncOpConversionPattern(converter, patterns, symbolTables);
792  patterns.add<CallIndirectOpLowering>(converter);
793  patterns.add<CallOpLowering>(converter, symbolTables);
794  patterns.add<ConstantOpLowering>(converter);
795  patterns.add<ReturnOpLowering>(converter);
796 }
797 
798 namespace {
799 /// A pass converting Func operations into the LLVM IR dialect.
800 struct ConvertFuncToLLVMPass
801  : public impl::ConvertFuncToLLVMPassBase<ConvertFuncToLLVMPass> {
802  using Base::Base;
803 
804  /// Run the dialect converter on the module.
805  void runOnOperation() override {
806  ModuleOp m = getOperation();
807  StringRef dataLayout;
808  auto dataLayoutAttr = dyn_cast_or_null<StringAttr>(
809  m->getAttr(LLVM::LLVMDialect::getDataLayoutAttrName()));
810  if (dataLayoutAttr)
811  dataLayout = dataLayoutAttr.getValue();
812 
813  if (failed(LLVM::LLVMDialect::verifyDataLayoutString(
814  dataLayout, [this](const Twine &message) {
815  getOperation().emitError() << message.str();
816  }))) {
817  signalPassFailure();
818  return;
819  }
820 
821  const auto &dataLayoutAnalysis = getAnalysis<DataLayoutAnalysis>();
822 
824  dataLayoutAnalysis.getAtOrAbove(m));
825  options.useBarePtrCallConv = useBarePtrCallConv;
826  if (indexBitwidth != kDeriveIndexBitwidthFromDataLayout)
827  options.overrideIndexBitwidth(indexBitwidth);
828  options.dataLayout = llvm::DataLayout(dataLayout);
829 
830  LLVMTypeConverter typeConverter(&getContext(), options,
831  &dataLayoutAnalysis);
832 
834  SymbolTableCollection symbolTables;
835 
837  &symbolTables);
838 
840  if (failed(applyPartialConversion(m, target, std::move(patterns))))
841  signalPassFailure();
842  }
843 };
844 
845 struct SetLLVMModuleDataLayoutPass
846  : public impl::SetLLVMModuleDataLayoutPassBase<
847  SetLLVMModuleDataLayoutPass> {
848  using Base::Base;
849 
850  /// Run the dialect converter on the module.
851  void runOnOperation() override {
852  if (failed(LLVM::LLVMDialect::verifyDataLayoutString(
853  this->dataLayout, [this](const Twine &message) {
854  getOperation().emitError() << message.str();
855  }))) {
856  signalPassFailure();
857  return;
858  }
859  ModuleOp m = getOperation();
860  m->setAttr(LLVM::LLVMDialect::getDataLayoutAttrName(),
861  StringAttr::get(m.getContext(), this->dataLayout));
862  }
863 };
864 } // namespace
865 
866 //===----------------------------------------------------------------------===//
867 // ConvertToLLVMPatternInterface implementation
868 //===----------------------------------------------------------------------===//
869 
870 namespace {
871 /// Implement the interface to convert Func to LLVM.
872 struct FuncToLLVMDialectInterface : public ConvertToLLVMPatternInterface {
874  /// Hook for derived dialect interface to provide conversion patterns
875  /// and mark dialect legal for the conversion target.
876  void populateConvertToLLVMConversionPatterns(
877  ConversionTarget &target, LLVMTypeConverter &typeConverter,
878  RewritePatternSet &patterns) const final {
880  }
881 };
882 } // namespace
883 
885  registry.addExtension(+[](MLIRContext *ctx, func::FuncDialect *dialect) {
886  dialect->addInterfaces<FuncToLLVMDialectInterface>();
887  });
888 }
static void propagateArgResAttrs(OpBuilder &builder, bool resultStructType, FunctionOpInterface funcOp, LLVM::LLVMFuncOp wrapperFuncOp)
Propagate argument/results attributes.
Definition: FuncToLLVM.cpp:76
static void restoreByValRefArgumentType(ConversionPatternRewriter &rewriter, const LLVMTypeConverter &typeConverter, ArrayRef< std::optional< NamedAttribute >> byValRefNonPtrAttrs, LLVM::LLVMFuncOp funcOp)
Inserts llvm.load ops in the function body to restore the expected pointee value from llvm....
Definition: FuncToLLVM.cpp:262
static constexpr StringRef barePtrAttrName
Definition: FuncToLLVM.cpp:53
static constexpr StringRef varargsAttrName
Definition: FuncToLLVM.cpp:51
static constexpr StringRef linkageAttrName
Definition: FuncToLLVM.cpp:52
static void filterFuncAttributes(FunctionOpInterface func, SmallVectorImpl< NamedAttribute > &result)
Only retain those attributes that are not constructed by LLVMFuncOp::build.
Definition: FuncToLLVM.cpp:64
static bool shouldUseBarePtrCallConv(Operation *op, const LLVMTypeConverter *typeConverter)
Return true if the op should use bare pointer calling convention.
Definition: FuncToLLVM.cpp:56
static void wrapExternalFunction(OpBuilder &builder, Location loc, const LLVMTypeConverter &typeConverter, FunctionOpInterface funcOp, LLVM::LLVMFuncOp newFuncOp)
Creates an auxiliary function with pointer-to-memref-descriptor-struct arguments instead of unpacked ...
Definition: FuncToLLVM.cpp:167
static void wrapForExternalCallers(OpBuilder &rewriter, Location loc, const LLVMTypeConverter &typeConverter, FunctionOpInterface funcOp, LLVM::LLVMFuncOp newFuncOp)
Creates an auxiliary function with pointer-to-memref-descriptor-struct arguments instead of unpacked ...
Definition: FuncToLLVM.cpp:107
static MLIRContext * getContext(OpFoldResult val)
static llvm::ManagedStatic< PassManagerOptions > options
Special case of IntegerAttr to represent boolean integers, i.e., signless i1 integers.
DenseI32ArrayAttr getDenseI32ArrayAttr(ArrayRef< int32_t > values)
Definition: Builders.cpp:162
IntegerAttr getIntegerAttr(Type type, int64_t value)
Definition: Builders.cpp:227
MLIRContext * getContext() const
Definition: Builders.h:56
ArrayAttr getArrayAttr(ArrayRef< Attribute > value)
Definition: Builders.cpp:265
IndexType getIndexType()
Definition: Builders.cpp:50
DictionaryAttr getDictionaryAttr(ArrayRef< NamedAttribute > value)
Definition: Builders.cpp:103
NamedAttribute getNamedAttr(StringRef name, Attribute val)
Definition: Builders.cpp:93
This class implements a pattern rewriter for use with ConversionPatterns.
void replaceOp(Operation *op, ValueRange newValues) override
Replace the given operation with the new values.
void replaceOpWithMultiple(Operation *op, SmallVector< SmallVector< Value >> &&newValues)
Replace the given operation with the new value ranges.
Block * applySignatureConversion(Block *block, TypeConverter::SignatureConversion &conversion, const TypeConverter *converter=nullptr)
Apply a signature conversion to given block.
void eraseOp(Operation *op) override
PatternRewriter hook for erasing a dead operation.
void replaceUsesOfBlockArgument(BlockArgument from, ValueRange to)
Replace all the uses of the block argument from with to.
This class describes a specific conversion target.
Utility class for operation conversions targeting the LLVM dialect that match exactly one source oper...
Definition: Pattern.h:209
typename SourceOp::template GenericAdaptor< ArrayRef< ValueRange > > OneToNOpAdaptor
Definition: Pattern.h:213
Base class for dialect interfaces providing translation to LLVM IR.
ConvertToLLVMPatternInterface(Dialect *dialect)
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.
Derived class that automatically populates legalization information for different LLVM ops.
Conversion from types to the LLVM IR dialect.
Definition: TypeConverter.h:35
const LowerToLLVMOptions & getOptions() const
Type convertFunctionSignature(FunctionType funcTy, bool isVariadic, bool useBarePtrCallConv, SignatureConversion &result) const
Convert a function type.
LogicalResult convertType(Type t, SmallVectorImpl< Type > &results) const
Convert the given type.
std::pair< LLVM::LLVMFunctionType, LLVM::LLVMStructType > convertFunctionTypeCWrapper(FunctionType type) const
Converts the function type to a C-compatible format, in particular using pointers to memref descripto...
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition: Location.h:76
Options to control the LLVM lowering.
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:63
Helper class to produce LLVM dialect operations extracting or inserting elements of a MemRef descript...
Definition: MemRefBuilder.h:33
static MemRefDescriptor fromStaticShape(OpBuilder &builder, Location loc, const LLVMTypeConverter &typeConverter, MemRefType type, Value memory)
Builds IR creating a MemRef descriptor that represents type and populates it with static shape and st...
static void unpack(OpBuilder &builder, Location loc, Value packed, MemRefType type, SmallVectorImpl< Value > &results)
Builds IR extracting individual elements of a MemRef descriptor structure and returning them as resul...
static unsigned getNumUnpackedValues(MemRefType type)
Returns the number of non-aggregate values that would be produced by unpack.
static Value pack(OpBuilder &builder, Location loc, const LLVMTypeConverter &converter, MemRefType type, ValueRange values)
Builds IR populating a MemRef descriptor structure from a list of individual values composing that de...
NamedAttribute represents a combination of a name and an Attribute value.
Definition: Attributes.h:164
RAII guard to reset the insertion point of the builder when destroyed.
Definition: Builders.h:348
This class helps build Operations.
Definition: Builders.h:207
Block::iterator getInsertionPoint() const
Returns the current insertion point of the builder.
Definition: Builders.h:445
void setInsertionPointToStart(Block *block)
Sets the insertion point to the start of the specified block.
Definition: Builders.h:431
A trait used to provide symbol table functionalities to a region operation.
Definition: SymbolTable.h:452
Operation is the basic unit of execution within MLIR.
Definition: Operation.h:88
bool hasAttr(StringAttr name)
Return true if the operation has an attribute with the provided name, false otherwise.
Definition: Operation.h:560
Operation * getParentWithTrait()
Returns the closest surrounding parent operation with trait Trait.
Definition: Operation.h:248
This class represents the benefit of a pattern match in a unitless scheme that ranges from 0 (very li...
Definition: PatternMatch.h:34
std::enable_if_t<!std::is_convertible< CallbackT, Twine >::value, LogicalResult > notifyMatchFailure(Location loc, CallbackT &&reasonCallback)
Used to notify the listener that the IR failed to be rewritten because of a match failure,...
Definition: PatternMatch.h:716
void inlineRegionBefore(Region &region, Region &parent, Region::iterator before)
Move the blocks that belong to "region" before the given position in another region "parent".
OpTy replaceOpWithNewOp(Operation *op, Args &&...args)
Replace the results of the given (original) op with a new op that is created without verification (re...
Definition: PatternMatch.h:519
This class represents a collection of SymbolTables.
Definition: SymbolTable.h:283
virtual Operation * lookupNearestSymbolFrom(Operation *from, StringAttr symbol)
Returns the operation registered with the given symbol name within the closest parent operation of,...
virtual SymbolTable & getSymbolTable(Operation *op)
Lookup, or create, a symbol table for an operation.
This class allows for representing and managing the symbol table used by operations with the 'SymbolT...
Definition: SymbolTable.h:24
static Operation * lookupNearestSymbolFrom(Operation *from, StringAttr symbol)
Returns the operation registered with the given symbol name within the closest parent operation of,...
StringAttr insert(Operation *symbol, Block::iterator insertPt={})
Insert a new symbol into the table, and rename it as necessary to avoid collisions.
void remove(Operation *op)
Remove the given symbol from the table, without deleting it.
This class provides all of the information necessary to convert a type signature.
std::optional< InputMapping > getInputMapping(unsigned input) const
Get the input mapping for the given argument.
This class provides an abstraction over the various different ranges of value types.
Definition: TypeRange.h:37
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition: Types.h:74
static Value pack(OpBuilder &builder, Location loc, const LLVMTypeConverter &converter, UnrankedMemRefType type, ValueRange values)
Builds IR populating an unranked MemRef descriptor structure from a list of individual constituent va...
static void unpack(OpBuilder &builder, Location loc, Value packed, SmallVectorImpl< Value > &results)
Builds IR extracting individual elements that compose an unranked memref descriptor and returns them ...
static unsigned getNumUnpackedValues()
Returns the number of non-aggregate values that would be produced by unpack.
This class provides an abstraction over the different types of ranges over Values.
Definition: ValueRange.h:387
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:96
Type getType() const
Return the type of this value.
Definition: Value.h:105
bool isCompatibleType(Type type)
Returns true if the given type is compatible with the LLVM dialect.
Definition: LLVMTypes.cpp:809
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
Definition: Matchers.h:344
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition: Remarks.h:491
Include the generated interface declarations.
static constexpr unsigned kDeriveIndexBitwidthFromDataLayout
Value to pass as bitwidth for the index type when the converter is expected to derive the bitwidth fr...
void registerConvertFuncToLLVMInterface(DialectRegistry &registry)
Definition: FuncToLLVM.cpp:884
void populateFuncToLLVMConversionPatterns(const LLVMTypeConverter &converter, RewritePatternSet &patterns, SymbolTableCollection *symbolTables=nullptr)
Collect the patterns to convert from the Func dialect to LLVM.
Definition: FuncToLLVM.cpp:788
void populateFuncToLLVMFuncOpConversionPattern(const LLVMTypeConverter &converter, RewritePatternSet &patterns, SymbolTableCollection *symbolTables=nullptr)
Collect the default pattern to convert a FuncOp to the LLVM dialect.
Definition: FuncToLLVM.cpp:782
const FrozenRewritePatternSet & patterns
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
FailureOr< LLVM::LLVMFuncOp > convertFuncOpToLLVMFuncOp(FunctionOpInterface funcOp, ConversionPatternRewriter &rewriter, const LLVMTypeConverter &converter, SymbolTableCollection *symbolTables=nullptr)
Convert input FunctionOpInterface operation to LLVMFuncOp by using the provided LLVMTypeConverter.
Definition: FuncToLLVM.cpp:291
LogicalResult applyPartialConversion(ArrayRef< Operation * > ops, const ConversionTarget &target, const FrozenRewritePatternSet &patterns, ConversionConfig config=ConversionConfig())
Below we define several entry points for operation conversion.
Eliminates variable at the specified position using Fourier-Motzkin variable elimination.