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