MLIR  14.0.0git
StandardToLLVM.cpp
Go to the documentation of this file.
1 //===- StandardToLLVM.cpp - Standard 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 standard and builtin dialects
10 // into the LLVM IR dialect.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "../PassDetail.h"
26 #include "mlir/IR/Attributes.h"
28 #include "mlir/IR/Builders.h"
29 #include "mlir/IR/BuiltinOps.h"
30 #include "mlir/IR/PatternMatch.h"
31 #include "mlir/IR/TypeUtilities.h"
35 #include "mlir/Transforms/Passes.h"
36 #include "mlir/Transforms/Utils.h"
37 #include "llvm/ADT/TypeSwitch.h"
38 #include "llvm/IR/DerivedTypes.h"
39 #include "llvm/IR/IRBuilder.h"
40 #include "llvm/IR/Type.h"
41 #include "llvm/Support/CommandLine.h"
42 #include "llvm/Support/FormatVariadic.h"
43 #include <functional>
44 
45 using namespace mlir;
46 
47 #define PASS_NAME "convert-std-to-llvm"
48 
49 /// Only retain those attributes that are not constructed by
50 /// `LLVMFuncOp::build`. If `filterArgAttrs` is set, also filter out argument
51 /// attributes.
53  bool filterArgAttrs,
55  for (const auto &attr : attrs) {
56  if (attr.getName() == SymbolTable::getSymbolAttrName() ||
57  attr.getName() == FunctionOpInterface::getTypeAttrName() ||
58  attr.getName() == "std.varargs" ||
59  (filterArgAttrs &&
60  attr.getName() == FunctionOpInterface::getArgDictAttrName()))
61  continue;
62  result.push_back(attr);
63  }
64 }
65 
66 /// Creates an auxiliary function with pointer-to-memref-descriptor-struct
67 /// arguments instead of unpacked arguments. This function can be called from C
68 /// by passing a pointer to a C struct corresponding to a memref descriptor.
69 /// Similarly, returned memrefs are passed via pointers to a C struct that is
70 /// passed as additional argument.
71 /// Internally, the auxiliary function unpacks the descriptor into individual
72 /// components and forwards them to `newFuncOp` and forwards the results to
73 /// the extra arguments.
74 static void wrapForExternalCallers(OpBuilder &rewriter, Location loc,
75  LLVMTypeConverter &typeConverter,
76  FuncOp funcOp, LLVM::LLVMFuncOp newFuncOp) {
77  auto type = funcOp.getType();
79  filterFuncAttributes(funcOp->getAttrs(), /*filterArgAttrs=*/false,
80  attributes);
81  Type wrapperFuncType;
82  bool resultIsNowArg;
83  std::tie(wrapperFuncType, resultIsNowArg) =
84  typeConverter.convertFunctionTypeCWrapper(type);
85  auto wrapperFuncOp = rewriter.create<LLVM::LLVMFuncOp>(
86  loc, llvm::formatv("_mlir_ciface_{0}", funcOp.getName()).str(),
87  wrapperFuncType, LLVM::Linkage::External, /*dsoLocal*/ false, attributes);
88 
89  OpBuilder::InsertionGuard guard(rewriter);
90  rewriter.setInsertionPointToStart(wrapperFuncOp.addEntryBlock());
91 
93  size_t argOffset = resultIsNowArg ? 1 : 0;
94  for (auto &en : llvm::enumerate(type.getInputs())) {
95  Value arg = wrapperFuncOp.getArgument(en.index() + argOffset);
96  if (auto memrefType = en.value().dyn_cast<MemRefType>()) {
97  Value loaded = rewriter.create<LLVM::LoadOp>(loc, arg);
98  MemRefDescriptor::unpack(rewriter, loc, loaded, memrefType, args);
99  continue;
100  }
101  if (en.value().isa<UnrankedMemRefType>()) {
102  Value loaded = rewriter.create<LLVM::LoadOp>(loc, arg);
103  UnrankedMemRefDescriptor::unpack(rewriter, loc, loaded, args);
104  continue;
105  }
106 
107  args.push_back(arg);
108  }
109 
110  auto call = rewriter.create<LLVM::CallOp>(loc, newFuncOp, args);
111 
112  if (resultIsNowArg) {
113  rewriter.create<LLVM::StoreOp>(loc, call.getResult(0),
114  wrapperFuncOp.getArgument(0));
115  rewriter.create<LLVM::ReturnOp>(loc, ValueRange{});
116  } else {
117  rewriter.create<LLVM::ReturnOp>(loc, call.getResults());
118  }
119 }
120 
121 /// Creates an auxiliary function with pointer-to-memref-descriptor-struct
122 /// arguments instead of unpacked arguments. Creates a body for the (external)
123 /// `newFuncOp` that allocates a memref descriptor on stack, packs the
124 /// individual arguments into this descriptor and passes a pointer to it into
125 /// the auxiliary function. If the result of the function cannot be directly
126 /// returned, we write it to a special first argument that provides a pointer
127 /// to a corresponding struct. This auxiliary external function is now
128 /// compatible with functions defined in C using pointers to C structs
129 /// corresponding to a memref descriptor.
130 static void wrapExternalFunction(OpBuilder &builder, Location loc,
131  LLVMTypeConverter &typeConverter,
132  FuncOp funcOp, LLVM::LLVMFuncOp newFuncOp) {
133  OpBuilder::InsertionGuard guard(builder);
134 
135  Type wrapperType;
136  bool resultIsNowArg;
137  std::tie(wrapperType, resultIsNowArg) =
138  typeConverter.convertFunctionTypeCWrapper(funcOp.getType());
139  // This conversion can only fail if it could not convert one of the argument
140  // types. But since it has been applied to a non-wrapper function before, it
141  // should have failed earlier and not reach this point at all.
142  assert(wrapperType && "unexpected type conversion failure");
143 
145  filterFuncAttributes(funcOp->getAttrs(), /*filterArgAttrs=*/false,
146  attributes);
147 
148  // Create the auxiliary function.
149  auto wrapperFunc = builder.create<LLVM::LLVMFuncOp>(
150  loc, llvm::formatv("_mlir_ciface_{0}", funcOp.getName()).str(),
151  wrapperType, LLVM::Linkage::External, /*dsoLocal*/ false, attributes);
152 
153  builder.setInsertionPointToStart(newFuncOp.addEntryBlock());
154 
155  // Get a ValueRange containing arguments.
156  FunctionType type = funcOp.getType();
158  args.reserve(type.getNumInputs());
159  ValueRange wrapperArgsRange(newFuncOp.getArguments());
160 
161  if (resultIsNowArg) {
162  // Allocate the struct on the stack and pass the pointer.
163  Type resultType =
164  wrapperType.cast<LLVM::LLVMFunctionType>().getParamType(0);
165  Value one = builder.create<LLVM::ConstantOp>(
166  loc, typeConverter.convertType(builder.getIndexType()),
167  builder.getIntegerAttr(builder.getIndexType(), 1));
168  Value result = builder.create<LLVM::AllocaOp>(loc, resultType, one);
169  args.push_back(result);
170  }
171 
172  // Iterate over the inputs of the original function and pack values into
173  // memref descriptors if the original type is a memref.
174  for (auto &en : llvm::enumerate(type.getInputs())) {
175  Value arg;
176  int numToDrop = 1;
177  auto memRefType = en.value().dyn_cast<MemRefType>();
178  auto unrankedMemRefType = en.value().dyn_cast<UnrankedMemRefType>();
179  if (memRefType || unrankedMemRefType) {
180  numToDrop = memRefType
183  Value packed =
184  memRefType
185  ? MemRefDescriptor::pack(builder, loc, typeConverter, memRefType,
186  wrapperArgsRange.take_front(numToDrop))
188  builder, loc, typeConverter, unrankedMemRefType,
189  wrapperArgsRange.take_front(numToDrop));
190 
191  auto ptrTy = LLVM::LLVMPointerType::get(packed.getType());
192  Value one = builder.create<LLVM::ConstantOp>(
193  loc, typeConverter.convertType(builder.getIndexType()),
194  builder.getIntegerAttr(builder.getIndexType(), 1));
195  Value allocated =
196  builder.create<LLVM::AllocaOp>(loc, ptrTy, one, /*alignment=*/0);
197  builder.create<LLVM::StoreOp>(loc, packed, allocated);
198  arg = allocated;
199  } else {
200  arg = wrapperArgsRange[0];
201  }
202 
203  args.push_back(arg);
204  wrapperArgsRange = wrapperArgsRange.drop_front(numToDrop);
205  }
206  assert(wrapperArgsRange.empty() && "did not map some of the arguments");
207 
208  auto call = builder.create<LLVM::CallOp>(loc, wrapperFunc, args);
209 
210  if (resultIsNowArg) {
211  Value result = builder.create<LLVM::LoadOp>(loc, args.front());
212  builder.create<LLVM::ReturnOp>(loc, ValueRange{result});
213  } else {
214  builder.create<LLVM::ReturnOp>(loc, call.getResults());
215  }
216 }
217 
218 namespace {
219 
220 struct FuncOpConversionBase : public ConvertOpToLLVMPattern<FuncOp> {
221 protected:
223 
224  // Convert input FuncOp to LLVMFuncOp by using the LLVMTypeConverter provided
225  // to this legalization pattern.
226  LLVM::LLVMFuncOp
227  convertFuncOpToLLVMFuncOp(FuncOp funcOp,
228  ConversionPatternRewriter &rewriter) const {
229  // Convert the original function arguments. They are converted using the
230  // LLVMTypeConverter provided to this legalization pattern.
231  auto varargsAttr = funcOp->getAttrOfType<BoolAttr>("std.varargs");
232  TypeConverter::SignatureConversion result(funcOp.getNumArguments());
233  auto llvmType = getTypeConverter()->convertFunctionSignature(
234  funcOp.getType(), varargsAttr && varargsAttr.getValue(), result);
235  if (!llvmType)
236  return nullptr;
237 
238  // Propagate argument attributes to all converted arguments obtained after
239  // converting a given original argument.
241  filterFuncAttributes(funcOp->getAttrs(), /*filterArgAttrs=*/true,
242  attributes);
243  if (ArrayAttr argAttrDicts = funcOp.getAllArgAttrs()) {
244  SmallVector<Attribute, 4> newArgAttrs(
245  llvmType.cast<LLVM::LLVMFunctionType>().getNumParams());
246  for (unsigned i = 0, e = funcOp.getNumArguments(); i < e; ++i) {
247  auto mapping = result.getInputMapping(i);
248  assert(mapping.hasValue() &&
249  "unexpected deletion of function argument");
250  for (size_t j = 0; j < mapping->size; ++j)
251  newArgAttrs[mapping->inputNo + j] = argAttrDicts[i];
252  }
253  attributes.push_back(
255  rewriter.getArrayAttr(newArgAttrs)));
256  }
257  for (const auto &pair : llvm::enumerate(attributes)) {
258  if (pair.value().getName() == "llvm.linkage") {
259  attributes.erase(attributes.begin() + pair.index());
260  break;
261  }
262  }
263 
264  // Create an LLVM function, use external linkage by default until MLIR
265  // functions have linkage.
266  LLVM::Linkage linkage = LLVM::Linkage::External;
267  if (funcOp->hasAttr("llvm.linkage")) {
268  auto attr =
269  funcOp->getAttr("llvm.linkage").dyn_cast<mlir::LLVM::LinkageAttr>();
270  if (!attr) {
271  funcOp->emitError()
272  << "Contains llvm.linkage attribute not of type LLVM::LinkageAttr";
273  return nullptr;
274  }
275  linkage = attr.getLinkage();
276  }
277  auto newFuncOp = rewriter.create<LLVM::LLVMFuncOp>(
278  funcOp.getLoc(), funcOp.getName(), llvmType, linkage,
279  /*dsoLocal*/ false, attributes);
280  rewriter.inlineRegionBefore(funcOp.getBody(), newFuncOp.getBody(),
281  newFuncOp.end());
282  if (failed(rewriter.convertRegionTypes(&newFuncOp.getBody(), *typeConverter,
283  &result)))
284  return nullptr;
285 
286  return newFuncOp;
287  }
288 };
289 
290 /// FuncOp legalization pattern that converts MemRef arguments to pointers to
291 /// MemRef descriptors (LLVM struct data types) containing all the MemRef type
292 /// information.
293 static constexpr StringRef kEmitIfaceAttrName = "llvm.emit_c_interface";
294 struct FuncOpConversion : public FuncOpConversionBase {
295  FuncOpConversion(LLVMTypeConverter &converter)
296  : FuncOpConversionBase(converter) {}
297 
299  matchAndRewrite(FuncOp funcOp, OpAdaptor adaptor,
300  ConversionPatternRewriter &rewriter) const override {
301  auto newFuncOp = convertFuncOpToLLVMFuncOp(funcOp, rewriter);
302  if (!newFuncOp)
303  return failure();
304 
305  if (getTypeConverter()->getOptions().emitCWrappers ||
306  funcOp->getAttrOfType<UnitAttr>(kEmitIfaceAttrName)) {
307  if (newFuncOp.isExternal())
308  wrapExternalFunction(rewriter, funcOp.getLoc(), *getTypeConverter(),
309  funcOp, newFuncOp);
310  else
311  wrapForExternalCallers(rewriter, funcOp.getLoc(), *getTypeConverter(),
312  funcOp, newFuncOp);
313  }
314 
315  rewriter.eraseOp(funcOp);
316  return success();
317  }
318 };
319 
320 /// FuncOp legalization pattern that converts MemRef arguments to bare pointers
321 /// to the MemRef element type. This will impact the calling convention and ABI.
322 struct BarePtrFuncOpConversion : public FuncOpConversionBase {
323  using FuncOpConversionBase::FuncOpConversionBase;
324 
326  matchAndRewrite(FuncOp funcOp, OpAdaptor adaptor,
327  ConversionPatternRewriter &rewriter) const override {
328 
329  // TODO: bare ptr conversion could be handled by argument materialization
330  // and most of the code below would go away. But to do this, we would need a
331  // way to distinguish between FuncOp and other regions in the
332  // addArgumentMaterialization hook.
333 
334  // Store the type of memref-typed arguments before the conversion so that we
335  // can promote them to MemRef descriptor at the beginning of the function.
336  SmallVector<Type, 8> oldArgTypes =
337  llvm::to_vector<8>(funcOp.getType().getInputs());
338 
339  auto newFuncOp = convertFuncOpToLLVMFuncOp(funcOp, rewriter);
340  if (!newFuncOp)
341  return failure();
342  if (newFuncOp.getBody().empty()) {
343  rewriter.eraseOp(funcOp);
344  return success();
345  }
346 
347  // Promote bare pointers from memref arguments to memref descriptors at the
348  // beginning of the function so that all the memrefs in the function have a
349  // uniform representation.
350  Block *entryBlock = &newFuncOp.getBody().front();
351  auto blockArgs = entryBlock->getArguments();
352  assert(blockArgs.size() == oldArgTypes.size() &&
353  "The number of arguments and types doesn't match");
354 
355  OpBuilder::InsertionGuard guard(rewriter);
356  rewriter.setInsertionPointToStart(entryBlock);
357  for (auto it : llvm::zip(blockArgs, oldArgTypes)) {
358  BlockArgument arg = std::get<0>(it);
359  Type argTy = std::get<1>(it);
360 
361  // Unranked memrefs are not supported in the bare pointer calling
362  // convention. We should have bailed out before in the presence of
363  // unranked memrefs.
364  assert(!argTy.isa<UnrankedMemRefType>() &&
365  "Unranked memref is not supported");
366  auto memrefTy = argTy.dyn_cast<MemRefType>();
367  if (!memrefTy)
368  continue;
369 
370  // Replace barePtr with a placeholder (undef), promote barePtr to a ranked
371  // or unranked memref descriptor and replace placeholder with the last
372  // instruction of the memref descriptor.
373  // TODO: The placeholder is needed to avoid replacing barePtr uses in the
374  // MemRef descriptor instructions. We may want to have a utility in the
375  // rewriter to properly handle this use case.
376  Location loc = funcOp.getLoc();
377  auto placeholder = rewriter.create<LLVM::UndefOp>(
378  loc, getTypeConverter()->convertType(memrefTy));
379  rewriter.replaceUsesOfBlockArgument(arg, placeholder);
380 
382  rewriter, loc, *getTypeConverter(), memrefTy, arg);
383  rewriter.replaceOp(placeholder, {desc});
384  }
385 
386  rewriter.eraseOp(funcOp);
387  return success();
388  }
389 };
390 
391 // Straightforward lowerings.
393 
394 /// Lower `std.assert`. The default lowering calls the `abort` function if the
395 /// assertion is violated and has no effect otherwise. The failure message is
396 /// ignored by the default lowering but should be propagated by any custom
397 /// lowering.
398 struct AssertOpLowering : public ConvertOpToLLVMPattern<AssertOp> {
400 
402  matchAndRewrite(AssertOp op, OpAdaptor adaptor,
403  ConversionPatternRewriter &rewriter) const override {
404  auto loc = op.getLoc();
405 
406  // Insert the `abort` declaration if necessary.
407  auto module = op->getParentOfType<ModuleOp>();
408  auto abortFunc = module.lookupSymbol<LLVM::LLVMFuncOp>("abort");
409  if (!abortFunc) {
410  OpBuilder::InsertionGuard guard(rewriter);
411  rewriter.setInsertionPointToStart(module.getBody());
412  auto abortFuncTy = LLVM::LLVMFunctionType::get(getVoidType(), {});
413  abortFunc = rewriter.create<LLVM::LLVMFuncOp>(rewriter.getUnknownLoc(),
414  "abort", abortFuncTy);
415  }
416 
417  // Split block at `assert` operation.
418  Block *opBlock = rewriter.getInsertionBlock();
419  auto opPosition = rewriter.getInsertionPoint();
420  Block *continuationBlock = rewriter.splitBlock(opBlock, opPosition);
421 
422  // Generate IR to call `abort`.
423  Block *failureBlock = rewriter.createBlock(opBlock->getParent());
424  rewriter.create<LLVM::CallOp>(loc, abortFunc, llvm::None);
425  rewriter.create<LLVM::UnreachableOp>(loc);
426 
427  // Generate assertion test.
428  rewriter.setInsertionPointToEnd(opBlock);
429  rewriter.replaceOpWithNewOp<LLVM::CondBrOp>(
430  op, adaptor.getArg(), continuationBlock, failureBlock);
431 
432  return success();
433  }
434 };
435 
436 struct ConstantOpLowering : public ConvertOpToLLVMPattern<ConstantOp> {
438 
440  matchAndRewrite(ConstantOp op, OpAdaptor adaptor,
441  ConversionPatternRewriter &rewriter) const override {
442  // If constant refers to a function, convert it to "addressof".
443  if (auto symbolRef = op.getValue().dyn_cast<FlatSymbolRefAttr>()) {
444  auto type = typeConverter->convertType(op.getResult().getType());
445  if (!type || !LLVM::isCompatibleType(type))
446  return rewriter.notifyMatchFailure(op, "failed to convert result type");
447 
448  auto newOp = rewriter.create<LLVM::AddressOfOp>(op.getLoc(), type,
449  symbolRef.getValue());
450  for (const NamedAttribute &attr : op->getAttrs()) {
451  if (attr.getName().strref() == "value")
452  continue;
453  newOp->setAttr(attr.getName(), attr.getValue());
454  }
455  rewriter.replaceOp(op, newOp->getResults());
456  return success();
457  }
458 
459  // Calling into other scopes (non-flat reference) is not supported in LLVM.
460  if (op.getValue().isa<SymbolRefAttr>())
461  return rewriter.notifyMatchFailure(
462  op, "referring to a symbol outside of the current module");
463 
465  op, LLVM::ConstantOp::getOperationName(), adaptor.getOperands(),
466  *getTypeConverter(), rewriter);
467  }
468 };
469 
470 // A CallOp automatically promotes MemRefType to a sequence of alloca/store and
471 // passes the pointer to the MemRef across function boundaries.
472 template <typename CallOpType>
473 struct CallOpInterfaceLowering : public ConvertOpToLLVMPattern<CallOpType> {
475  using Super = CallOpInterfaceLowering<CallOpType>;
477 
479  matchAndRewrite(CallOpType callOp, typename CallOpType::Adaptor adaptor,
480  ConversionPatternRewriter &rewriter) const override {
481  // Pack the result types into a struct.
482  Type packedResult = nullptr;
483  unsigned numResults = callOp.getNumResults();
484  auto resultTypes = llvm::to_vector<4>(callOp.getResultTypes());
485 
486  if (numResults != 0) {
487  if (!(packedResult =
488  this->getTypeConverter()->packFunctionResults(resultTypes)))
489  return failure();
490  }
491 
492  auto promoted = this->getTypeConverter()->promoteOperands(
493  callOp.getLoc(), /*opOperands=*/callOp->getOperands(),
494  adaptor.getOperands(), rewriter);
495  auto newOp = rewriter.create<LLVM::CallOp>(
496  callOp.getLoc(), packedResult ? TypeRange(packedResult) : TypeRange(),
497  promoted, callOp->getAttrs());
498 
499  SmallVector<Value, 4> results;
500  if (numResults < 2) {
501  // If < 2 results, packing did not do anything and we can just return.
502  results.append(newOp.result_begin(), newOp.result_end());
503  } else {
504  // Otherwise, it had been converted to an operation producing a structure.
505  // Extract individual results from the structure and return them as list.
506  results.reserve(numResults);
507  for (unsigned i = 0; i < numResults; ++i) {
508  auto type =
509  this->typeConverter->convertType(callOp.getResult(i).getType());
510  results.push_back(rewriter.create<LLVM::ExtractValueOp>(
511  callOp.getLoc(), type, newOp->getResult(0),
512  rewriter.getI64ArrayAttr(i)));
513  }
514  }
515 
516  if (this->getTypeConverter()->getOptions().useBarePtrCallConv) {
517  // For the bare-ptr calling convention, promote memref results to
518  // descriptors.
519  assert(results.size() == resultTypes.size() &&
520  "The number of arguments and types doesn't match");
521  this->getTypeConverter()->promoteBarePtrsToDescriptors(
522  rewriter, callOp.getLoc(), resultTypes, results);
523  } else if (failed(this->copyUnrankedDescriptors(rewriter, callOp.getLoc(),
524  resultTypes, results,
525  /*toDynamic=*/false))) {
526  return failure();
527  }
528 
529  rewriter.replaceOp(callOp, results);
530  return success();
531  }
532 };
533 
534 struct CallOpLowering : public CallOpInterfaceLowering<CallOp> {
535  using Super::Super;
536 };
537 
538 struct CallIndirectOpLowering : public CallOpInterfaceLowering<CallIndirectOp> {
539  using Super::Super;
540 };
541 
542 struct UnrealizedConversionCastOpLowering
543  : public ConvertOpToLLVMPattern<UnrealizedConversionCastOp> {
545  UnrealizedConversionCastOp>::ConvertOpToLLVMPattern;
546 
548  matchAndRewrite(UnrealizedConversionCastOp op, OpAdaptor adaptor,
549  ConversionPatternRewriter &rewriter) const override {
550  SmallVector<Type> convertedTypes;
551  if (succeeded(typeConverter->convertTypes(op.outputs().getTypes(),
552  convertedTypes)) &&
553  convertedTypes == adaptor.inputs().getTypes()) {
554  rewriter.replaceOp(op, adaptor.inputs());
555  return success();
556  }
557 
558  convertedTypes.clear();
559  if (succeeded(typeConverter->convertTypes(adaptor.inputs().getTypes(),
560  convertedTypes)) &&
561  convertedTypes == op.outputs().getType()) {
562  rewriter.replaceOp(op, adaptor.inputs());
563  return success();
564  }
565  return failure();
566  }
567 };
568 
569 // Common base for load and store operations on MemRefs. Restricts the match
570 // to supported MemRef types. Provides functionality to emit code accessing a
571 // specific element of the underlying data buffer.
572 template <typename Derived>
573 struct LoadStoreOpLowering : public ConvertOpToLLVMPattern<Derived> {
576  using Base = LoadStoreOpLowering<Derived>;
577 
578  LogicalResult match(Derived op) const override {
579  MemRefType type = op.getMemRefType();
580  return isConvertibleAndHasIdentityMaps(type) ? success() : failure();
581  }
582 };
583 
584 // Base class for LLVM IR lowering terminator operations with successors.
585 template <typename SourceOp, typename TargetOp>
586 struct OneToOneLLVMTerminatorLowering
587  : public ConvertOpToLLVMPattern<SourceOp> {
589  using Super = OneToOneLLVMTerminatorLowering<SourceOp, TargetOp>;
590 
592  matchAndRewrite(SourceOp op, typename SourceOp::Adaptor adaptor,
593  ConversionPatternRewriter &rewriter) const override {
594  rewriter.replaceOpWithNewOp<TargetOp>(op, adaptor.getOperands(),
595  op->getSuccessors(), op->getAttrs());
596  return success();
597  }
598 };
599 
600 // Special lowering pattern for `ReturnOps`. Unlike all other operations,
601 // `ReturnOp` interacts with the function signature and must have as many
602 // operands as the function has return values. Because in LLVM IR, functions
603 // can only return 0 or 1 value, we pack multiple values into a structure type.
604 // Emit `UndefOp` followed by `InsertValueOp`s to create such structure if
605 // necessary before returning it
606 struct ReturnOpLowering : public ConvertOpToLLVMPattern<ReturnOp> {
608 
610  matchAndRewrite(ReturnOp op, OpAdaptor adaptor,
611  ConversionPatternRewriter &rewriter) const override {
612  Location loc = op.getLoc();
613  unsigned numArguments = op.getNumOperands();
614  SmallVector<Value, 4> updatedOperands;
615 
616  if (getTypeConverter()->getOptions().useBarePtrCallConv) {
617  // For the bare-ptr calling convention, extract the aligned pointer to
618  // be returned from the memref descriptor.
619  for (auto it : llvm::zip(op->getOperands(), adaptor.getOperands())) {
620  Type oldTy = std::get<0>(it).getType();
621  Value newOperand = std::get<1>(it);
622  if (oldTy.isa<MemRefType>()) {
623  MemRefDescriptor memrefDesc(newOperand);
624  newOperand = memrefDesc.alignedPtr(rewriter, loc);
625  } else if (oldTy.isa<UnrankedMemRefType>()) {
626  // Unranked memref is not supported in the bare pointer calling
627  // convention.
628  return failure();
629  }
630  updatedOperands.push_back(newOperand);
631  }
632  } else {
633  updatedOperands = llvm::to_vector<4>(adaptor.getOperands());
634  (void)copyUnrankedDescriptors(rewriter, loc, op.getOperands().getTypes(),
635  updatedOperands,
636  /*toDynamic=*/true);
637  }
638 
639  // If ReturnOp has 0 or 1 operand, create it and return immediately.
640  if (numArguments == 0) {
641  rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(op, TypeRange(), ValueRange(),
642  op->getAttrs());
643  return success();
644  }
645  if (numArguments == 1) {
646  rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(
647  op, TypeRange(), updatedOperands, op->getAttrs());
648  return success();
649  }
650 
651  // Otherwise, we need to pack the arguments into an LLVM struct type before
652  // returning.
653  auto packedType = getTypeConverter()->packFunctionResults(
654  llvm::to_vector<4>(op.getOperandTypes()));
655 
656  Value packed = rewriter.create<LLVM::UndefOp>(loc, packedType);
657  for (unsigned i = 0; i < numArguments; ++i) {
658  packed = rewriter.create<LLVM::InsertValueOp>(
659  loc, packedType, packed, updatedOperands[i],
660  rewriter.getI64ArrayAttr(i));
661  }
662  rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(op, TypeRange(), packed,
663  op->getAttrs());
664  return success();
665  }
666 };
667 
668 // FIXME: this should be tablegen'ed as well.
669 struct BranchOpLowering
670  : public OneToOneLLVMTerminatorLowering<BranchOp, LLVM::BrOp> {
671  using Super::Super;
672 };
673 struct CondBranchOpLowering
674  : public OneToOneLLVMTerminatorLowering<CondBranchOp, LLVM::CondBrOp> {
675  using Super::Super;
676 };
677 struct SwitchOpLowering
678  : public OneToOneLLVMTerminatorLowering<SwitchOp, LLVM::SwitchOp> {
679  using Super::Super;
680 };
681 
682 // The Splat operation is lowered to an insertelement + a shufflevector
683 // operation. Splat to only 0-d and 1-d vector result types are lowered.
684 struct SplatOpLowering : public ConvertOpToLLVMPattern<SplatOp> {
686 
688  matchAndRewrite(SplatOp splatOp, OpAdaptor adaptor,
689  ConversionPatternRewriter &rewriter) const override {
690  VectorType resultType = splatOp.getType().dyn_cast<VectorType>();
691  if (!resultType || resultType.getRank() > 1)
692  return failure();
693 
694  // First insert it into an undef vector so we can shuffle it.
695  auto vectorType = typeConverter->convertType(splatOp.getType());
696  Value undef = rewriter.create<LLVM::UndefOp>(splatOp.getLoc(), vectorType);
697  auto zero = rewriter.create<LLVM::ConstantOp>(
698  splatOp.getLoc(),
699  typeConverter->convertType(rewriter.getIntegerType(32)),
700  rewriter.getZeroAttr(rewriter.getIntegerType(32)));
701 
702  // For 0-d vector, we simply do `insertelement`.
703  if (resultType.getRank() == 0) {
704  rewriter.replaceOpWithNewOp<LLVM::InsertElementOp>(
705  splatOp, vectorType, undef, adaptor.getInput(), zero);
706  return success();
707  }
708 
709  // For 1-d vector, we additionally do a `vectorshuffle`.
710  auto v = rewriter.create<LLVM::InsertElementOp>(
711  splatOp.getLoc(), vectorType, undef, adaptor.getInput(), zero);
712 
713  int64_t width = splatOp.getType().cast<VectorType>().getDimSize(0);
714  SmallVector<int32_t, 4> zeroValues(width, 0);
715 
716  // Shuffle the value across the desired number of elements.
717  ArrayAttr zeroAttrs = rewriter.getI32ArrayAttr(zeroValues);
718  rewriter.replaceOpWithNewOp<LLVM::ShuffleVectorOp>(splatOp, v, undef,
719  zeroAttrs);
720  return success();
721  }
722 };
723 
724 // The Splat operation is lowered to an insertelement + a shufflevector
725 // operation. Splat to only 2+-d vector result types are lowered by the
726 // SplatNdOpLowering, the 1-d case is handled by SplatOpLowering.
727 struct SplatNdOpLowering : public ConvertOpToLLVMPattern<SplatOp> {
729 
731  matchAndRewrite(SplatOp splatOp, OpAdaptor adaptor,
732  ConversionPatternRewriter &rewriter) const override {
733  VectorType resultType = splatOp.getType().dyn_cast<VectorType>();
734  if (!resultType || resultType.getRank() <= 1)
735  return failure();
736 
737  // First insert it into an undef vector so we can shuffle it.
738  auto loc = splatOp.getLoc();
739  auto vectorTypeInfo =
740  LLVM::detail::extractNDVectorTypeInfo(resultType, *getTypeConverter());
741  auto llvmNDVectorTy = vectorTypeInfo.llvmNDVectorTy;
742  auto llvm1DVectorTy = vectorTypeInfo.llvm1DVectorTy;
743  if (!llvmNDVectorTy || !llvm1DVectorTy)
744  return failure();
745 
746  // Construct returned value.
747  Value desc = rewriter.create<LLVM::UndefOp>(loc, llvmNDVectorTy);
748 
749  // Construct a 1-D vector with the splatted value that we insert in all the
750  // places within the returned descriptor.
751  Value vdesc = rewriter.create<LLVM::UndefOp>(loc, llvm1DVectorTy);
752  auto zero = rewriter.create<LLVM::ConstantOp>(
753  loc, typeConverter->convertType(rewriter.getIntegerType(32)),
754  rewriter.getZeroAttr(rewriter.getIntegerType(32)));
755  Value v = rewriter.create<LLVM::InsertElementOp>(loc, llvm1DVectorTy, vdesc,
756  adaptor.getInput(), zero);
757 
758  // Shuffle the value across the desired number of elements.
759  int64_t width = resultType.getDimSize(resultType.getRank() - 1);
760  SmallVector<int32_t, 4> zeroValues(width, 0);
761  ArrayAttr zeroAttrs = rewriter.getI32ArrayAttr(zeroValues);
762  v = rewriter.create<LLVM::ShuffleVectorOp>(loc, v, v, zeroAttrs);
763 
764  // Iterate of linear index, convert to coords space and insert splatted 1-D
765  // vector in each position.
766  nDVectorIterate(vectorTypeInfo, rewriter, [&](ArrayAttr position) {
767  desc = rewriter.create<LLVM::InsertValueOp>(loc, llvmNDVectorTy, desc, v,
768  position);
769  });
770  rewriter.replaceOp(splatOp, desc);
771  return success();
772  }
773 };
774 
775 /// Wrap a llvm.cmpxchg operation in a while loop so that the operation can be
776 /// retried until it succeeds in atomically storing a new value into memory.
777 ///
778 /// +---------------------------------+
779 /// | <code before the AtomicRMWOp> |
780 /// | <compute initial %loaded> |
781 /// | br loop(%loaded) |
782 /// +---------------------------------+
783 /// |
784 /// -------| |
785 /// | v v
786 /// | +--------------------------------+
787 /// | | loop(%loaded): |
788 /// | | <body contents> |
789 /// | | %pair = cmpxchg |
790 /// | | %ok = %pair[0] |
791 /// | | %new = %pair[1] |
792 /// | | cond_br %ok, end, loop(%new) |
793 /// | +--------------------------------+
794 /// | | |
795 /// |----------- |
796 /// v
797 /// +--------------------------------+
798 /// | end: |
799 /// | <code after the AtomicRMWOp> |
800 /// +--------------------------------+
801 ///
802 struct GenericAtomicRMWOpLowering
803  : public LoadStoreOpLowering<GenericAtomicRMWOp> {
804  using Base::Base;
805 
807  matchAndRewrite(GenericAtomicRMWOp atomicOp, OpAdaptor adaptor,
808  ConversionPatternRewriter &rewriter) const override {
809 
810  auto loc = atomicOp.getLoc();
811  Type valueType = typeConverter->convertType(atomicOp.getResult().getType());
812 
813  // Split the block into initial, loop, and ending parts.
814  auto *initBlock = rewriter.getInsertionBlock();
815  auto *loopBlock = rewriter.createBlock(
816  initBlock->getParent(), std::next(Region::iterator(initBlock)),
817  valueType, loc);
818  auto *endBlock = rewriter.createBlock(
819  loopBlock->getParent(), std::next(Region::iterator(loopBlock)));
820 
821  // Operations range to be moved to `endBlock`.
822  auto opsToMoveStart = atomicOp->getIterator();
823  auto opsToMoveEnd = initBlock->back().getIterator();
824 
825  // Compute the loaded value and branch to the loop block.
826  rewriter.setInsertionPointToEnd(initBlock);
827  auto memRefType = atomicOp.getMemref().getType().cast<MemRefType>();
828  auto dataPtr = getStridedElementPtr(loc, memRefType, adaptor.getMemref(),
829  adaptor.getIndices(), rewriter);
830  Value init = rewriter.create<LLVM::LoadOp>(loc, dataPtr);
831  rewriter.create<LLVM::BrOp>(loc, init, loopBlock);
832 
833  // Prepare the body of the loop block.
834  rewriter.setInsertionPointToStart(loopBlock);
835 
836  // Clone the GenericAtomicRMWOp region and extract the result.
837  auto loopArgument = loopBlock->getArgument(0);
838  BlockAndValueMapping mapping;
839  mapping.map(atomicOp.getCurrentValue(), loopArgument);
840  Block &entryBlock = atomicOp.body().front();
841  for (auto &nestedOp : entryBlock.without_terminator()) {
842  Operation *clone = rewriter.clone(nestedOp, mapping);
843  mapping.map(nestedOp.getResults(), clone->getResults());
844  }
845  Value result = mapping.lookup(entryBlock.getTerminator()->getOperand(0));
846 
847  // Prepare the epilog of the loop block.
848  // Append the cmpxchg op to the end of the loop block.
849  auto successOrdering = LLVM::AtomicOrdering::acq_rel;
850  auto failureOrdering = LLVM::AtomicOrdering::monotonic;
851  auto boolType = IntegerType::get(rewriter.getContext(), 1);
852  auto pairType = LLVM::LLVMStructType::getLiteral(rewriter.getContext(),
853  {valueType, boolType});
854  auto cmpxchg = rewriter.create<LLVM::AtomicCmpXchgOp>(
855  loc, pairType, dataPtr, loopArgument, result, successOrdering,
856  failureOrdering);
857  // Extract the %new_loaded and %ok values from the pair.
858  Value newLoaded = rewriter.create<LLVM::ExtractValueOp>(
859  loc, valueType, cmpxchg, rewriter.getI64ArrayAttr({0}));
860  Value ok = rewriter.create<LLVM::ExtractValueOp>(
861  loc, boolType, cmpxchg, rewriter.getI64ArrayAttr({1}));
862 
863  // Conditionally branch to the end or back to the loop depending on %ok.
864  rewriter.create<LLVM::CondBrOp>(loc, ok, endBlock, ArrayRef<Value>(),
865  loopBlock, newLoaded);
866 
867  rewriter.setInsertionPointToEnd(endBlock);
868  moveOpsRange(atomicOp.getResult(), newLoaded, std::next(opsToMoveStart),
869  std::next(opsToMoveEnd), rewriter);
870 
871  // The 'result' of the atomic_rmw op is the newly loaded value.
872  rewriter.replaceOp(atomicOp, {newLoaded});
873 
874  return success();
875  }
876 
877 private:
878  // Clones a segment of ops [start, end) and erases the original.
879  void moveOpsRange(ValueRange oldResult, ValueRange newResult,
880  Block::iterator start, Block::iterator end,
881  ConversionPatternRewriter &rewriter) const {
882  BlockAndValueMapping mapping;
883  mapping.map(oldResult, newResult);
884  SmallVector<Operation *, 2> opsToErase;
885  for (auto it = start; it != end; ++it) {
886  rewriter.clone(*it, mapping);
887  opsToErase.push_back(&*it);
888  }
889  for (auto *it : opsToErase)
890  rewriter.eraseOp(it);
891  }
892 };
893 
894 } // namespace
895 
897  LLVMTypeConverter &converter, RewritePatternSet &patterns) {
898  if (converter.getOptions().useBarePtrCallConv)
899  patterns.add<BarePtrFuncOpConversion>(converter);
900  else
901  patterns.add<FuncOpConversion>(converter);
902 }
903 
905  RewritePatternSet &patterns) {
906  populateStdToLLVMFuncOpConversionPattern(converter, patterns);
907  // clang-format off
908  patterns.add<
910  BranchOpLowering,
911  CallIndirectOpLowering,
912  CallOpLowering,
913  CondBranchOpLowering,
914  ConstantOpLowering,
915  GenericAtomicRMWOpLowering,
916  ReturnOpLowering,
917  SelectOpLowering,
918  SplatOpLowering,
919  SplatNdOpLowering,
920  SwitchOpLowering>(converter);
921  // clang-format on
922 }
923 
924 namespace {
925 /// A pass converting MLIR operations into the LLVM IR dialect.
926 struct LLVMLoweringPass : public ConvertStandardToLLVMBase<LLVMLoweringPass> {
927  LLVMLoweringPass() = default;
928  LLVMLoweringPass(bool useBarePtrCallConv, bool emitCWrappers,
929  unsigned indexBitwidth, bool useAlignedAlloc,
930  const llvm::DataLayout &dataLayout) {
931  this->useBarePtrCallConv = useBarePtrCallConv;
932  this->emitCWrappers = emitCWrappers;
933  this->indexBitwidth = indexBitwidth;
934  this->dataLayout = dataLayout.getStringRepresentation();
935  }
936 
937  /// Run the dialect converter on the module.
938  void runOnOperation() override {
939  if (useBarePtrCallConv && emitCWrappers) {
940  getOperation().emitError()
941  << "incompatible conversion options: bare-pointer calling convention "
942  "and C wrapper emission";
943  signalPassFailure();
944  return;
945  }
946  if (failed(LLVM::LLVMDialect::verifyDataLayoutString(
947  this->dataLayout, [this](const Twine &message) {
948  getOperation().emitError() << message.str();
949  }))) {
950  signalPassFailure();
951  return;
952  }
953 
954  ModuleOp m = getOperation();
955  const auto &dataLayoutAnalysis = getAnalysis<DataLayoutAnalysis>();
956 
957  LowerToLLVMOptions options(&getContext(),
958  dataLayoutAnalysis.getAtOrAbove(m));
959  options.useBarePtrCallConv = useBarePtrCallConv;
960  options.emitCWrappers = emitCWrappers;
961  if (indexBitwidth != kDeriveIndexBitwidthFromDataLayout)
962  options.overrideIndexBitwidth(indexBitwidth);
963  options.dataLayout = llvm::DataLayout(this->dataLayout);
964 
965  LLVMTypeConverter typeConverter(&getContext(), options,
966  &dataLayoutAnalysis);
967 
968  RewritePatternSet patterns(&getContext());
969  populateStdToLLVMConversionPatterns(typeConverter, patterns);
970  arith::populateArithmeticToLLVMConversionPatterns(typeConverter, patterns);
971 
972  LLVMConversionTarget target(getContext());
973  if (failed(applyPartialConversion(m, target, std::move(patterns))))
974  signalPassFailure();
975 
976  m->setAttr(LLVM::LLVMDialect::getDataLayoutAttrName(),
977  StringAttr::get(m.getContext(), this->dataLayout));
978  }
979 };
980 } // namespace
981 
982 std::unique_ptr<OperationPass<ModuleOp>> mlir::createLowerToLLVMPass() {
983  return std::make_unique<LLVMLoweringPass>();
984 }
985 
986 std::unique_ptr<OperationPass<ModuleOp>>
988  auto allocLowering = options.allocLowering;
989  // There is no way to provide additional patterns for pass, so
990  // AllocLowering::None will always fail.
991  assert(allocLowering != LowerToLLVMOptions::AllocLowering::None &&
992  "LLVMLoweringPass doesn't support AllocLowering::None");
993  bool useAlignedAlloc =
995  return std::make_unique<LLVMLoweringPass>(
996  options.useBarePtrCallConv, options.emitCWrappers,
997  options.getIndexBitwidth(), useAlignedAlloc, options.dataLayout);
998 }
Location getUnknownLoc()
Definition: Builders.cpp:26
Include the generated interface declarations.
Utility class for operation conversions targeting the LLVM dialect that match exactly one source oper...
Definition: Pattern.h:132
Do not lower heap allocations.
OpTy create(Location location, Args &&...args)
Create an operation of specific op type at the current insertion point.
Definition: Builders.h:430
NDVectorTypeInfo extractNDVectorTypeInfo(VectorType vectorType, LLVMTypeConverter &converter)
static StringRef getSymbolAttrName()
Return the name of the attribute used for symbol names.
Definition: SymbolTable.h:55
MLIRContext * getContext() const
Definition: Builders.h:54
const LowerToLLVMOptions & getOptions() const
Definition: TypeConverter.h:81
Block * getInsertionBlock() const
Return the block the current insertion point belongs to.
Definition: Builders.h:373
Operation is a basic unit of execution within MLIR.
Definition: Operation.h:28
LogicalResult applyPartialConversion(ArrayRef< Operation *> ops, ConversionTarget &target, const FrozenRewritePatternSet &patterns, DenseSet< Operation *> *unconvertedOps=nullptr)
Below we define several entry points for operation conversion.
Operation & back()
Definition: Block.h:143
StringRef getArgDictAttrName()
Return the name of the attribute used for function argument attributes.
Attribute getZeroAttr(Type type)
Definition: Builders.cpp:264
static LLVMStructType getLiteral(MLIRContext *context, ArrayRef< Type > types, bool isPacked=false)
Gets or creates a literal struct with the given body in the provided context.
Definition: LLVMTypes.cpp:371
Basic lowering implementation to rewrite Ops with just one result to the LLVM Dialect.
Definition: VectorPattern.h:67
LogicalResult convertType(Type t, SmallVectorImpl< Type > &results)
Convert the given type.
Block represents an ordered list of Operations.
Definition: Block.h:29
A symbol reference with a reference path containing a single element.
void replaceUsesOfBlockArgument(BlockArgument from, Value to)
Replace all the uses of the block argument from with value to.
Operation * clone(Operation &op, BlockAndValueMapping &mapper)
Creates a deep copy of the specified operation, remapping any operands that use values outside of the...
Definition: Builders.cpp:457
Value getOperand(unsigned idx)
Definition: Operation.h:219
static unsigned getNumUnpackedValues(MemRefType type)
Returns the number of non-aggregate values that would be produced by unpack.
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value...
Definition: LogicalResult.h:72
LLVM dialect function type.
Definition: LLVMTypes.h:123
BlockListType::iterator iterator
Definition: Region.h:52
Derived class that automatically populates legalization information for different LLVM ops...
static Value pack(OpBuilder &builder, Location loc, LLVMTypeConverter &converter, MemRefType type, ValueRange values)
Builds IR populating a MemRef descriptor structure from a list of individual values composing that de...
void populateArithmeticToLLVMConversionPatterns(LLVMTypeConverter &converter, RewritePatternSet &patterns)
llvm::DataLayout dataLayout
The data layout of the module to produce.
bool succeeded(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a success value...
Definition: LogicalResult.h:68
StringRef getTypeAttrName()
Return the name of the attribute used for function types.
LogicalResult notifyMatchFailure(Operation *op, function_ref< void(Diagnostic &)> reasonCallback) override
PatternRewriter hook for notifying match failure reasons.
Operation & front()
Definition: Block.h:144
T lookup(T from) const
Lookup a mapped value within the map.
NamedAttribute getNamedAttr(StringRef name, Attribute val)
Definition: Builders.cpp:81
iterator_range< iterator > without_terminator()
Return an iterator range over the operation within this block excluding the terminator operation at t...
Definition: Block.h:200
ArrayAttr getI64ArrayAttr(ArrayRef< int64_t > values)
Definition: Builders.cpp:220
static LLVMPointerType get(Type pointee, unsigned addressSpace=0)
Gets or creates an instance of LLVM dialect pointer type pointing to an object of pointee type in the...
Definition: LLVMTypes.cpp:165
static LLVMFunctionType get(Type result, ArrayRef< Type > arguments, bool isVarArg=false)
Gets or creates an instance of LLVM dialect function in the same context as the result type...
Definition: LLVMTypes.cpp:101
unsigned getIndexBitwidth() const
Get the index bitwidth.
void replaceOp(Operation *op, ValueRange newValues) override
PatternRewriter hook for replacing the results of an operation.
void populateStdToLLVMFuncOpConversionPattern(LLVMTypeConverter &converter, RewritePatternSet &patterns)
Collect the default pattern to convert a FuncOp to the LLVM dialect.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition: Location.h:48
NamedAttribute represents a combination of a name and an Attribute value.
Definition: Attributes.h:137
void map(Block *from, Block *to)
Inserts a new mapping for &#39;from&#39; to &#39;to&#39;.
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:56
This class represents an efficient way to signal success or failure.
Definition: LogicalResult.h:26
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:62
This class provides all of the information necessary to convert a type signature. ...
bool isCompatibleType(Type type)
Returns true if the given type is compatible with the LLVM dialect.
Definition: LLVMTypes.cpp:752
OpListType::iterator iterator
Definition: Block.h:131
IntegerAttr getIntegerAttr(Type type, int64_t value)
Definition: Builders.cpp:170
Helper class to produce LLVM dialect operations extracting or inserting elements of a MemRef descript...
Definition: MemRefBuilder.h:33
Special case of IntegerAttr to represent boolean integers, i.e., signless i1 integers.
U dyn_cast() const
Definition: Value.h:99
std::pair< Type, bool > convertFunctionTypeCWrapper(FunctionType type)
Converts the function type to a C-compatible format, in particular using pointers to memref descripto...
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
Definition: Matchers.h:206
static MemRefDescriptor fromStaticShape(OpBuilder &builder, Location loc, LLVMTypeConverter &typeConverter, MemRefType type, Value memory)
Builds IR creating a MemRef descriptor that represents type and populates it with static shape and st...
IntegerType getIntegerType(unsigned width)
Definition: Builders.cpp:58
Use aligned_alloc for heap allocations.
unsigned getNumParams()
Returns the number of arguments to the function.
Definition: LLVMTypes.cpp:127
This class provides an abstraction over the various different ranges of value types.
Definition: TypeRange.h:38
ArrayAttr getI32ArrayAttr(ArrayRef< int32_t > values)
Definition: Builders.cpp:215
BlockArgListType getArguments()
Definition: Block.h:76
This class represents an argument of a Block.
Definition: Value.h:298
Eliminates identifier at the specified position using Fourier-Motzkin variable elimination.
static void filterFuncAttributes(ArrayRef< NamedAttribute > attrs, bool filterArgAttrs, SmallVectorImpl< NamedAttribute > &result)
Only retain those attributes that are not constructed by LLVMFuncOp::build.
void inlineRegionBefore(Region &region, Region &parent, Region::iterator before) override
PatternRewriter hook for moving blocks out of a region.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition: Types.h:72
static unsigned getNumUnpackedValues()
Returns the number of non-aggregate values that would be produced by unpack.
static constexpr unsigned kDeriveIndexBitwidthFromDataLayout
Value to pass as bitwidth for the index type when the converter is expected to derive the bitwidth fr...
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:84
static llvm::ManagedStatic< PassManagerOptions > options
Operation * getTerminator()
Get the terminator operation of this block.
Definition: Block.cpp:230
static void wrapForExternalCallers(OpBuilder &rewriter, Location loc, LLVMTypeConverter &typeConverter, FuncOp funcOp, LLVM::LLVMFuncOp newFuncOp)
Creates an auxiliary function with pointer-to-memref-descriptor-struct arguments instead of unpacked ...
void setInsertionPointToStart(Block *block)
Sets the insertion point to the start of the specified block.
Definition: Builders.h:362
RAII guard to reset the insertion point of the builder when destroyed.
Definition: Builders.h:279
OpTy replaceOpWithNewOp(Operation *op, Args &&... args)
Replaces the result op with a new op that is created without verification.
Definition: PatternMatch.h:741
Value alignedPtr(OpBuilder &builder, Location loc)
Builds IR extracting the aligned pointer from the descriptor.
Type getType() const
Return the type of this value.
Definition: Value.h:117
RewritePatternSet & add(ConstructorArg &&arg, ConstructorArgs &&... args)
Add an instance of each of the pattern types &#39;Ts&#39; to the pattern list with the given arguments...
Definition: PatternMatch.h:930
IndexType getIndexType()
Definition: Builders.cpp:48
static VectorType vectorType(CodeGen &codegen, Type etp)
Constructs vector type.
Conversion from types in the Standard dialect to the LLVM IR dialect.
Definition: TypeConverter.h:30
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...
Block * splitBlock(Block *block, Block::iterator before) override
PatternRewriter hook for splitting a block into two parts.
void nDVectorIterate(const NDVectorTypeInfo &info, OpBuilder &builder, function_ref< void(ArrayAttr)> fun)
Options to control the Standard dialect to LLVM lowering.
This class implements a pattern rewriter for use with ConversionPatterns.
static void wrapExternalFunction(OpBuilder &builder, Location loc, LLVMTypeConverter &typeConverter, FuncOp funcOp, LLVM::LLVMFuncOp newFuncOp)
Creates an auxiliary function with pointer-to-memref-descriptor-struct arguments instead of unpacked ...
void setInsertionPointToEnd(Block *block)
Sets the insertion point to the end of the specified block.
Definition: Builders.h:367
void eraseOp(Operation *op) override
PatternRewriter hook for erasing a dead operation.
LogicalResult oneToOneRewrite(Operation *op, StringRef targetOp, ValueRange operands, LLVMTypeConverter &typeConverter, ConversionPatternRewriter &rewriter)
Replaces the given operation "op" with a new operation of type "targetOp" and given operands...
Definition: Pattern.cpp:309
Block * createBlock(Region *parent, Region::iterator insertPt={}, TypeRange argTypes=llvm::None, ArrayRef< Location > locs=llvm::None)
Add new block with &#39;argTypes&#39; arguments and set the insertion point to the end of it...
Definition: Builders.cpp:353
Block::iterator getInsertionPoint() const
Returns the current insertion point of the builder.
Definition: Builders.h:376
static Value pack(OpBuilder &builder, Location loc, LLVMTypeConverter &converter, UnrankedMemRefType type, ValueRange values)
Builds IR populating an unranked MemRef descriptor structure from a list of individual constituent va...
bool isa() const
Definition: Types.h:234
result_range getResults()
Definition: Operation.h:284
This class helps build Operations.
Definition: Builders.h:177
std::unique_ptr< OperationPass< ModuleOp > > createLowerToLLVMPass()
Creates a pass to convert the Standard dialect into the LLVMIR dialect.
ArrayAttr getArrayAttr(ArrayRef< Attribute > value)
Definition: Builders.cpp:205
This class provides an abstraction over the different types of ranges over Values.
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 ...
void populateStdToLLVMConversionPatterns(LLVMTypeConverter &converter, RewritePatternSet &patterns)
Collect the patterns to convert from the Standard dialect to LLVM.
FailureOr< Block * > convertRegionTypes(Region *region, TypeConverter &converter, TypeConverter::SignatureConversion *entryConversion=nullptr)
Convert the types of block arguments within the given region.
U cast() const
Definition: Types.h:250