//===- InlinerInterfaceImpl.cpp - Inlining for LLVM the dialect -----------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // Logic for inlining LLVM functions and the definition of the // LLVMInliningInterface. // //===----------------------------------------------------------------------===// #include "mlir/Dialect/LLVMIR/Transforms/InlinerInterfaceImpl.h" #include "mlir/Analysis/SliceWalk.h" #include "mlir/Dialect/LLVMIR/LLVMDialect.h" #include "mlir/IR/Matchers.h" #include "mlir/Interfaces/DataLayoutInterfaces.h" #include "mlir/Interfaces/ViewLikeInterface.h" #include "mlir/Transforms/InliningUtils.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/Support/Debug.h" #define DEBUG_TYPE … usingnamespacemlir; /// Check whether the given alloca is an input to a lifetime intrinsic, /// optionally passing through one or more casts on the way. This is not /// transitive through block arguments. static bool hasLifetimeMarkers(LLVM::AllocaOp allocaOp) { … } /// Handles alloca operations in the inlined blocks: /// - Moves all alloca operations with a constant size in the former entry block /// of the callee into the entry block of the caller, so they become part of /// the function prologue/epilogue during code generation. /// - Inserts lifetime intrinsics that limit the scope of inlined static allocas /// to the inlined blocks. /// - Inserts StackSave and StackRestore operations if dynamic allocas were /// inlined. static void handleInlinedAllocas(Operation *call, iterator_range<Region::iterator> inlinedBlocks) { … } /// Maps all alias scopes in the inlined operations to deep clones of the scopes /// and domain. This is required for code such as `foo(a, b); foo(a2, b2);` to /// not incorrectly return `noalias` for e.g. operations on `a` and `a2`. static void deepCloneAliasScopes(iterator_range<Region::iterator> inlinedBlocks) { … } /// Creates a new ArrayAttr by concatenating `lhs` with `rhs`. /// Returns null if both parameters are null. If only one attribute is null, /// return the other. static ArrayAttr concatArrayAttr(ArrayAttr lhs, ArrayAttr rhs) { … } /// Attempts to return the set of all underlying pointer values that /// `pointerValue` is based on. This function traverses through select /// operations and block arguments. static FailureOr<SmallVector<Value>> getUnderlyingObjectSet(Value pointerValue) { … } /// Creates a new AliasScopeAttr for every noalias parameter and attaches it to /// the appropriate inlined memory operations in an attempt to preserve the /// original semantics of the parameter attribute. static void createNewAliasScopesFromNoAliasParameter( Operation *call, iterator_range<Region::iterator> inlinedBlocks) { … } /// Appends any alias scopes of the call operation to any inlined memory /// operation. static void appendCallOpAliasScopes(Operation *call, iterator_range<Region::iterator> inlinedBlocks) { … } /// Handles all interactions with alias scopes during inlining. static void handleAliasScopes(Operation *call, iterator_range<Region::iterator> inlinedBlocks) { … } /// Appends any access groups of the call operation to any inlined memory /// operation. static void handleAccessGroups(Operation *call, iterator_range<Region::iterator> inlinedBlocks) { … } /// Updates locations inside loop annotations to reflect that they were inlined. static void handleLoopAnnotations(Operation *call, iterator_range<Region::iterator> inlinedBlocks) { … } /// If `requestedAlignment` is higher than the alignment specified on `alloca`, /// realigns `alloca` if this does not exceed the natural stack alignment. /// Returns the post-alignment of `alloca`, whether it was realigned or not. static uint64_t tryToEnforceAllocaAlignment(LLVM::AllocaOp alloca, uint64_t requestedAlignment, DataLayout const &dataLayout) { … } /// Tries to find and return the alignment of the pointer `value` by looking for /// an alignment attribute on the defining allocation op or function argument. /// If the found alignment is lower than `requestedAlignment`, tries to realign /// the pointer, then returns the resulting post-alignment, regardless of /// whether it was realigned or not. If no existing alignment attribute is /// found, returns 1 (i.e., assume that no alignment is guaranteed). static uint64_t tryToEnforceAlignment(Value value, uint64_t requestedAlignment, DataLayout const &dataLayout) { … } /// Introduces a new alloca and copies the memory pointed to by `argument` to /// the address of the new alloca, then returns the value of the new alloca. static Value handleByValArgumentInit(OpBuilder &builder, Location loc, Value argument, Type elementType, uint64_t elementTypeSize, uint64_t targetAlignment) { … } /// Handles a function argument marked with the byval attribute by introducing a /// memcpy or realigning the defining operation, if required either due to the /// pointee being writeable in the callee, and/or due to an alignment mismatch. /// `requestedAlignment` specifies the alignment set in the "align" argument /// attribute (or 1 if no align attribute was set). static Value handleByValArgument(OpBuilder &builder, Operation *callable, Value argument, Type elementType, uint64_t requestedAlignment) { … } namespace { struct LLVMInlinerInterface : public DialectInlinerInterface { … }; } // end anonymous namespace void mlir::LLVM::registerInlinerInterface(DialectRegistry ®istry) { … }