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