Generic dialect conversion pass exercised by LLVM IR lowering
This commit introduces a generic dialect conversion/lowering/legalization pass
and illustrates it on StandardOps->LLVMIR conversion.
It partially reuses the PatternRewriter infrastructure and adds the following
functionality:
- an actual pass;
- non-default pattern constructors;
- one-to-many rewrites;
- rewriting terminators with successors;
- not applying patterns iteratively (unlike the existing greedy rewrite driver);
- ability to change function signature;
- ability to change basic block argument types.
The latter two things required, given the existing API, to create new functions
in the same module. Eventually, this should converge with the rest of
PatternRewriter. However, we may want to keep two pass versions: "heavy" with
function/block argument conversion and "light" that only touches operations.
This pass creates new functions within a module as a means to change function
signature, then creates new blocks with converted argument types in the new
function. Then, it traverses the CFG in DFS-preorder to make sure defs are
converted before uses in the dominated blocks. The generic pass has a minimal
interface with two hooks: one to fill in the set of patterns, and another one
to convert types for functions and blocks. The patterns are defined as
separate classes that can be table-generated in the future.
The LLVM IR lowering pass partially inherits from the existing LLVM IR
translator, in particular for type conversion. It defines a conversion pattern
template, instantiated for different operations, and is a good candidate for
tablegen. The lowering does not yet support loads and stores and is not
connected to the translator as it would have broken the existing flows. Future
patches will add missing support before switching the translator in a single
patch.
PiperOrigin-RevId: 230951202
2019-01-25 12:46:53 -08:00
|
|
|
//===- DialectConversion.cpp - MLIR dialect conversion generic pass -------===//
|
|
|
|
|
//
|
|
|
|
|
// Copyright 2019 The MLIR Authors.
|
|
|
|
|
//
|
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
|
//
|
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
//
|
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
|
// limitations under the License.
|
|
|
|
|
// =============================================================================
|
|
|
|
|
|
|
|
|
|
#include "mlir/Transforms/DialectConversion.h"
|
|
|
|
|
#include "mlir/IR/BlockAndValueMapping.h"
|
|
|
|
|
#include "mlir/IR/Builders.h"
|
|
|
|
|
#include "mlir/IR/Function.h"
|
|
|
|
|
#include "mlir/IR/Module.h"
|
|
|
|
|
#include "mlir/Transforms/Utils.h"
|
2019-06-03 12:49:55 -07:00
|
|
|
#include "llvm/ADT/SetVector.h"
|
|
|
|
|
#include "llvm/ADT/SmallPtrSet.h"
|
|
|
|
|
#include "llvm/Support/Debug.h"
|
|
|
|
|
#include "llvm/Support/raw_ostream.h"
|
Generic dialect conversion pass exercised by LLVM IR lowering
This commit introduces a generic dialect conversion/lowering/legalization pass
and illustrates it on StandardOps->LLVMIR conversion.
It partially reuses the PatternRewriter infrastructure and adds the following
functionality:
- an actual pass;
- non-default pattern constructors;
- one-to-many rewrites;
- rewriting terminators with successors;
- not applying patterns iteratively (unlike the existing greedy rewrite driver);
- ability to change function signature;
- ability to change basic block argument types.
The latter two things required, given the existing API, to create new functions
in the same module. Eventually, this should converge with the rest of
PatternRewriter. However, we may want to keep two pass versions: "heavy" with
function/block argument conversion and "light" that only touches operations.
This pass creates new functions within a module as a means to change function
signature, then creates new blocks with converted argument types in the new
function. Then, it traverses the CFG in DFS-preorder to make sure defs are
converted before uses in the dominated blocks. The generic pass has a minimal
interface with two hooks: one to fill in the set of patterns, and another one
to convert types for functions and blocks. The patterns are defined as
separate classes that can be table-generated in the future.
The LLVM IR lowering pass partially inherits from the existing LLVM IR
translator, in particular for type conversion. It defines a conversion pattern
template, instantiated for different operations, and is a good candidate for
tablegen. The lowering does not yet support loads and stores and is not
connected to the translator as it would have broken the existing flows. Future
patches will add missing support before switching the translator in a single
patch.
PiperOrigin-RevId: 230951202
2019-01-25 12:46:53 -08:00
|
|
|
|
|
|
|
|
using namespace mlir;
|
2019-06-03 12:49:55 -07:00
|
|
|
|
|
|
|
|
#define DEBUG_TYPE "dialect-conversion"
|
Generic dialect conversion pass exercised by LLVM IR lowering
This commit introduces a generic dialect conversion/lowering/legalization pass
and illustrates it on StandardOps->LLVMIR conversion.
It partially reuses the PatternRewriter infrastructure and adds the following
functionality:
- an actual pass;
- non-default pattern constructors;
- one-to-many rewrites;
- rewriting terminators with successors;
- not applying patterns iteratively (unlike the existing greedy rewrite driver);
- ability to change function signature;
- ability to change basic block argument types.
The latter two things required, given the existing API, to create new functions
in the same module. Eventually, this should converge with the rest of
PatternRewriter. However, we may want to keep two pass versions: "heavy" with
function/block argument conversion and "light" that only touches operations.
This pass creates new functions within a module as a means to change function
signature, then creates new blocks with converted argument types in the new
function. Then, it traverses the CFG in DFS-preorder to make sure defs are
converted before uses in the dominated blocks. The generic pass has a minimal
interface with two hooks: one to fill in the set of patterns, and another one
to convert types for functions and blocks. The patterns are defined as
separate classes that can be table-generated in the future.
The LLVM IR lowering pass partially inherits from the existing LLVM IR
translator, in particular for type conversion. It defines a conversion pattern
template, instantiated for different operations, and is a good candidate for
tablegen. The lowering does not yet support loads and stores and is not
connected to the translator as it would have broken the existing flows. Future
patches will add missing support before switching the translator in a single
patch.
PiperOrigin-RevId: 230951202
2019-01-25 12:46:53 -08:00
|
|
|
|
2019-05-19 20:54:13 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
2019-05-22 11:49:04 -07:00
|
|
|
// ArgConverter
|
2019-05-19 20:54:13 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
2019-05-17 22:21:13 -07:00
|
|
|
namespace {
|
2019-05-22 11:49:04 -07:00
|
|
|
/// This class provides a simple interface for converting the types of block
|
|
|
|
|
/// arguments. This is done by inserting fake cast operations for the illegal
|
|
|
|
|
/// type that allow for updating the real type to return the correct type.
|
|
|
|
|
struct ArgConverter {
|
|
|
|
|
ArgConverter(MLIRContext *ctx)
|
|
|
|
|
: castOpName(kCastName, ctx), loc(UnknownLoc::get(ctx)) {}
|
|
|
|
|
|
|
|
|
|
/// Cleanup and undo any generated conversion values.
|
|
|
|
|
void discardRewrites() {
|
|
|
|
|
// On failure drop all uses of the cast operation and destroy it.
|
|
|
|
|
for (auto *op : castOps) {
|
|
|
|
|
op->getResult(0)->dropAllUses();
|
|
|
|
|
op->destroy();
|
|
|
|
|
}
|
|
|
|
|
castOps.clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Replace usages of the cast operations with the argument directly.
|
|
|
|
|
void applyRewrites() {
|
|
|
|
|
// On success, we update the type of the block argument and replace uses of
|
|
|
|
|
// the cast.
|
|
|
|
|
for (auto *op : castOps) {
|
|
|
|
|
op->getOperand(0)->setType(op->getResult(0)->getType());
|
|
|
|
|
op->getResult(0)->replaceAllUsesWith(op->getOperand(0));
|
2019-05-19 17:56:32 -07:00
|
|
|
op->destroy();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-22 11:49:04 -07:00
|
|
|
/// Generate a cast operation for 'arg' that produces the new, legal, type.
|
|
|
|
|
void castArgument(BlockArgument *arg, Type newType,
|
|
|
|
|
BlockAndValueMapping &mapping) {
|
|
|
|
|
// Otherwise, generate a new cast operation for the given value type.
|
|
|
|
|
auto *cast = Operation::create(loc, castOpName, arg, newType, llvm::None,
|
|
|
|
|
llvm::None, 0, false, arg->getContext());
|
|
|
|
|
|
|
|
|
|
// Replace the uses of the argument and record the mapping.
|
|
|
|
|
mapping.map(arg, cast->getResult(0));
|
|
|
|
|
castOps.push_back(cast);
|
2019-05-19 17:56:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// This is an operation name for a fake operation that is inserted during the
|
|
|
|
|
/// conversion process. Operations of this type are guaranteed to never escape
|
|
|
|
|
/// the converter.
|
2019-05-22 11:49:04 -07:00
|
|
|
static constexpr StringLiteral kCastName = "__mlir_conversion.cast";
|
|
|
|
|
OperationName castOpName;
|
2019-05-19 17:56:32 -07:00
|
|
|
|
2019-05-22 11:49:04 -07:00
|
|
|
/// This is a collection of cast values that were generated during the
|
2019-05-19 17:56:32 -07:00
|
|
|
/// conversion process.
|
2019-05-22 11:49:04 -07:00
|
|
|
std::vector<Operation *> castOps;
|
2019-05-19 17:56:32 -07:00
|
|
|
|
|
|
|
|
/// An instance of the unknown location that is used when generating
|
|
|
|
|
/// producers.
|
|
|
|
|
UnknownLoc loc;
|
|
|
|
|
};
|
|
|
|
|
|
2019-05-22 11:49:04 -07:00
|
|
|
constexpr StringLiteral ArgConverter::kCastName;
|
2019-05-19 23:09:29 -07:00
|
|
|
|
2019-05-19 20:54:13 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
// DialectConversionRewriter
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
2019-06-05 09:36:32 -07:00
|
|
|
/// This class contains a snapshot of the current conversion rewriter state.
|
|
|
|
|
/// This is useful when saving and undoing a set of rewrites.
|
|
|
|
|
struct RewriterState {
|
|
|
|
|
RewriterState(unsigned numCreatedOperations, unsigned numReplacements)
|
|
|
|
|
: numCreatedOperations(numCreatedOperations),
|
|
|
|
|
numReplacements(numReplacements) {}
|
|
|
|
|
|
|
|
|
|
/// The current number of created operations.
|
|
|
|
|
unsigned numCreatedOperations;
|
|
|
|
|
|
|
|
|
|
/// The current number of replacements queued.
|
|
|
|
|
unsigned numReplacements;
|
|
|
|
|
};
|
|
|
|
|
|
2019-05-24 10:36:16 -07:00
|
|
|
/// This class implements a pattern rewriter for ConversionPattern
|
2019-05-19 20:54:13 -07:00
|
|
|
/// patterns. It automatically performs remapping of replaced operation values.
|
2019-05-17 22:21:13 -07:00
|
|
|
struct DialectConversionRewriter final : public PatternRewriter {
|
2019-05-22 11:49:04 -07:00
|
|
|
/// This class represents one requested operation replacement via 'replaceOp'.
|
|
|
|
|
struct OpReplacement {
|
|
|
|
|
OpReplacement() = default;
|
|
|
|
|
OpReplacement(Operation *op, ArrayRef<Value *> newValues)
|
|
|
|
|
: op(op), newValues(newValues.begin(), newValues.end()) {}
|
|
|
|
|
|
|
|
|
|
Operation *op;
|
|
|
|
|
SmallVector<Value *, 2> newValues;
|
|
|
|
|
};
|
|
|
|
|
|
2019-06-04 19:18:23 -07:00
|
|
|
DialectConversionRewriter(Region ®ion)
|
|
|
|
|
: PatternRewriter(region), argConverter(region.getContext()) {}
|
2019-05-17 22:21:13 -07:00
|
|
|
~DialectConversionRewriter() = default;
|
|
|
|
|
|
2019-06-05 09:36:32 -07:00
|
|
|
/// Return the current state of the rewriter.
|
|
|
|
|
RewriterState getCurrentState() {
|
|
|
|
|
return RewriterState(createdOps.size(), replacements.size());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Reset the state of the rewriter to a previously saved point.
|
|
|
|
|
void resetState(RewriterState state) {
|
|
|
|
|
// Reset any replaced operations and undo any saved mappings.
|
|
|
|
|
for (auto &repl : llvm::drop_begin(replacements, state.numReplacements))
|
|
|
|
|
for (auto *result : repl.op->getResults())
|
|
|
|
|
mapping.erase(result);
|
|
|
|
|
replacements.resize(state.numReplacements);
|
|
|
|
|
|
|
|
|
|
// Pop all of the newly created operations.
|
|
|
|
|
while (createdOps.size() != state.numCreatedOperations)
|
|
|
|
|
createdOps.pop_back_val()->erase();
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-22 11:49:04 -07:00
|
|
|
/// Cleanup and destroy any generated rewrite operations. This method is
|
|
|
|
|
/// invoked when the conversion process fails.
|
|
|
|
|
void discardRewrites() {
|
|
|
|
|
argConverter.discardRewrites();
|
|
|
|
|
for (auto *op : createdOps) {
|
|
|
|
|
op->dropAllDefinedValueUses();
|
|
|
|
|
op->erase();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Apply all requested operation rewrites. This method is invoked when the
|
|
|
|
|
/// conversion process succeeds.
|
|
|
|
|
void applyRewrites() {
|
|
|
|
|
// Apply all of the rewrites replacements requested during conversion.
|
|
|
|
|
for (auto &repl : replacements) {
|
|
|
|
|
for (unsigned i = 0, e = repl.newValues.size(); i != e; ++i)
|
|
|
|
|
repl.op->getResult(i)->replaceAllUsesWith(repl.newValues[i]);
|
|
|
|
|
repl.op->erase();
|
|
|
|
|
}
|
2019-05-23 11:11:18 -07:00
|
|
|
|
|
|
|
|
argConverter.applyRewrites();
|
2019-05-22 11:49:04 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// PatternRewriter hook for replacing the results of an operation.
|
2019-05-17 22:21:13 -07:00
|
|
|
void replaceOp(Operation *op, ArrayRef<Value *> newValues,
|
|
|
|
|
ArrayRef<Value *> valuesToRemoveIfDead) override {
|
|
|
|
|
assert(newValues.size() == op->getNumResults());
|
2019-06-05 10:08:47 -07:00
|
|
|
|
|
|
|
|
// Create mappings for each of the new result values.
|
|
|
|
|
for (unsigned i = 0, e = newValues.size(); i < e; ++i) {
|
|
|
|
|
assert((newValues[i] || op->getResult(i)->use_empty()) &&
|
|
|
|
|
"result value has remaining uses that must be replaced");
|
|
|
|
|
if (newValues[i])
|
2019-05-22 11:49:04 -07:00
|
|
|
mapping.map(op->getResult(i), newValues[i]);
|
2019-06-05 10:08:47 -07:00
|
|
|
}
|
2019-05-22 11:49:04 -07:00
|
|
|
|
|
|
|
|
// Record the requested operation replacement.
|
|
|
|
|
replacements.emplace_back(op, newValues);
|
2019-05-17 22:21:13 -07:00
|
|
|
}
|
|
|
|
|
|
2019-05-22 11:49:04 -07:00
|
|
|
/// PatternRewriter hook for creating a new operation.
|
2019-05-17 22:21:13 -07:00
|
|
|
Operation *createOperation(const OperationState &state) override {
|
2019-06-04 19:18:23 -07:00
|
|
|
auto *result = OpBuilder::createOperation(state);
|
2019-05-22 11:49:04 -07:00
|
|
|
createdOps.push_back(result);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// PatternRewriter hook for updating the root operation in-place.
|
|
|
|
|
void notifyRootUpdated(Operation *op) override {
|
|
|
|
|
// The rewriter caches changes to the IR to allow for operating in-place and
|
|
|
|
|
// backtracking. The rewrite is currently not capable of backtracking
|
|
|
|
|
// in-place modifications.
|
|
|
|
|
llvm_unreachable("in-place operation updates are not supported");
|
2019-05-17 22:21:13 -07:00
|
|
|
}
|
|
|
|
|
|
2019-05-22 11:49:04 -07:00
|
|
|
/// Remap the given operands to those with potentially different types.
|
|
|
|
|
void remapValues(Operation::operand_range operands,
|
|
|
|
|
SmallVectorImpl<Value *> &remapped) {
|
2019-05-17 22:21:13 -07:00
|
|
|
remapped.reserve(llvm::size(operands));
|
2019-05-19 17:56:32 -07:00
|
|
|
for (Value *operand : operands)
|
|
|
|
|
remapped.push_back(mapping.lookupOrDefault(operand));
|
2019-05-17 22:21:13 -07:00
|
|
|
}
|
|
|
|
|
|
2019-05-22 11:49:04 -07:00
|
|
|
// Mapping between replaced values that differ in type. This happens when
|
|
|
|
|
// replacing a value with one of a different type.
|
2019-05-17 22:21:13 -07:00
|
|
|
BlockAndValueMapping mapping;
|
2019-05-19 17:56:32 -07:00
|
|
|
|
2019-05-22 11:49:04 -07:00
|
|
|
/// Utility used to convert block arguments.
|
|
|
|
|
ArgConverter argConverter;
|
|
|
|
|
|
|
|
|
|
/// Ordered vector of all of the newly created operations during conversion.
|
|
|
|
|
SmallVector<Operation *, 4> createdOps;
|
|
|
|
|
|
|
|
|
|
/// Ordered vector of any requested operation replacements.
|
|
|
|
|
SmallVector<OpReplacement, 4> replacements;
|
2019-05-17 22:21:13 -07:00
|
|
|
};
|
|
|
|
|
} // end anonymous namespace
|
|
|
|
|
|
2019-05-19 20:54:13 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
2019-05-24 10:36:16 -07:00
|
|
|
// ConversionPattern
|
2019-05-19 20:54:13 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
2019-06-06 15:38:08 -07:00
|
|
|
/// Attempt to match and rewrite the IR root at the specified operation.
|
|
|
|
|
PatternMatchResult
|
|
|
|
|
ConversionPattern::matchAndRewrite(Operation *op,
|
|
|
|
|
PatternRewriter &rewriter) const {
|
2019-05-17 22:21:13 -07:00
|
|
|
SmallVector<Value *, 4> operands;
|
|
|
|
|
auto &dialectRewriter = static_cast<DialectConversionRewriter &>(rewriter);
|
2019-05-22 11:49:04 -07:00
|
|
|
dialectRewriter.remapValues(op->getOperands(), operands);
|
2019-05-17 22:21:13 -07:00
|
|
|
|
|
|
|
|
// If this operation has no successors, invoke the rewrite directly.
|
|
|
|
|
if (op->getNumSuccessors() == 0)
|
2019-06-06 15:38:08 -07:00
|
|
|
return matchAndRewrite(op, operands, rewriter);
|
2019-05-17 22:21:13 -07:00
|
|
|
|
|
|
|
|
// Otherwise, we need to remap the successors.
|
|
|
|
|
SmallVector<Block *, 2> destinations;
|
|
|
|
|
destinations.reserve(op->getNumSuccessors());
|
|
|
|
|
|
|
|
|
|
SmallVector<ArrayRef<Value *>, 2> operandsPerDestination;
|
|
|
|
|
unsigned firstSuccessorOperand = op->getSuccessorOperandIndex(0);
|
|
|
|
|
for (unsigned i = 0, seen = 0, e = op->getNumSuccessors(); i < e; ++i) {
|
2019-05-19 17:56:32 -07:00
|
|
|
destinations.push_back(op->getSuccessor(i));
|
2019-05-17 22:21:13 -07:00
|
|
|
|
|
|
|
|
// Lookup the successors operands.
|
|
|
|
|
unsigned n = op->getNumSuccessorOperands(i);
|
|
|
|
|
operandsPerDestination.push_back(
|
|
|
|
|
llvm::makeArrayRef(operands.data() + firstSuccessorOperand + seen, n));
|
|
|
|
|
seen += n;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Rewrite the operation.
|
2019-06-06 15:38:08 -07:00
|
|
|
return matchAndRewrite(
|
|
|
|
|
op,
|
|
|
|
|
llvm::makeArrayRef(operands.data(),
|
|
|
|
|
operands.data() + firstSuccessorOperand),
|
|
|
|
|
destinations, operandsPerDestination, rewriter);
|
2019-05-17 22:21:13 -07:00
|
|
|
}
|
|
|
|
|
|
2019-06-03 12:49:55 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
// OperationLegalizer
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
|
|
namespace {
|
2019-06-06 15:48:14 -07:00
|
|
|
/// A set of rewrite patterns that can be used to legalize a given operation.
|
|
|
|
|
using LegalizationPatterns = SmallVector<RewritePattern *, 1>;
|
2019-06-03 12:49:55 -07:00
|
|
|
|
|
|
|
|
/// This class defines a recursive operation legalizer.
|
|
|
|
|
class OperationLegalizer {
|
|
|
|
|
public:
|
|
|
|
|
OperationLegalizer(ConversionTarget &targetInfo,
|
|
|
|
|
OwningRewritePatternList &patterns)
|
|
|
|
|
: target(targetInfo) {
|
|
|
|
|
buildLegalizationGraph(patterns);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Attempt to legalize the given operation. Returns success if the operation
|
|
|
|
|
/// was legalized, failure otherwise.
|
|
|
|
|
LogicalResult legalize(Operation *op, DialectConversionRewriter &rewriter);
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
/// Attempt to legalize the given operation by applying the provided pattern.
|
|
|
|
|
/// Returns success if the operation was legalized, failure otherwise.
|
|
|
|
|
LogicalResult legalizePattern(Operation *op, RewritePattern *pattern,
|
|
|
|
|
DialectConversionRewriter &rewriter);
|
|
|
|
|
|
|
|
|
|
/// Build an optimistic legalization graph given the provided patterns. This
|
2019-06-06 15:48:14 -07:00
|
|
|
/// function populates 'legalizerPatterns' with the operations that are not
|
|
|
|
|
/// directly legal, but may be transitively legal for the current target given
|
|
|
|
|
/// the provided patterns.
|
2019-06-03 12:49:55 -07:00
|
|
|
void buildLegalizationGraph(OwningRewritePatternList &patterns);
|
|
|
|
|
|
|
|
|
|
/// The current set of patterns that have been applied.
|
|
|
|
|
llvm::SmallPtrSet<RewritePattern *, 8> appliedPatterns;
|
|
|
|
|
|
|
|
|
|
/// The set of legality information for operations transitively supported by
|
|
|
|
|
/// the target.
|
2019-06-06 15:48:14 -07:00
|
|
|
DenseMap<OperationName, LegalizationPatterns> legalizerPatterns;
|
2019-06-03 12:49:55 -07:00
|
|
|
|
|
|
|
|
/// The legalization information provided by the target.
|
|
|
|
|
ConversionTarget ⌖
|
|
|
|
|
};
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
LogicalResult
|
|
|
|
|
OperationLegalizer::legalize(Operation *op,
|
|
|
|
|
DialectConversionRewriter &rewriter) {
|
|
|
|
|
LLVM_DEBUG(llvm::dbgs() << "Legalizing operation : " << op->getName()
|
|
|
|
|
<< "\n");
|
|
|
|
|
|
|
|
|
|
// Check if this was marked legal by the target.
|
2019-06-06 15:48:14 -07:00
|
|
|
if (auto action = target.getOpAction(op->getName())) {
|
2019-06-03 12:49:55 -07:00
|
|
|
// Check if this operation is always legal.
|
|
|
|
|
if (*action == ConversionTarget::LegalizationAction::Legal)
|
|
|
|
|
return success();
|
|
|
|
|
|
2019-06-06 15:48:14 -07:00
|
|
|
// Otherwise, handle dynamic legalization.
|
2019-06-03 12:49:55 -07:00
|
|
|
LLVM_DEBUG(llvm::dbgs() << "- Trying dynamic legalization.\n");
|
|
|
|
|
if (target.isLegal(op))
|
|
|
|
|
return success();
|
|
|
|
|
|
|
|
|
|
// Fallthough to see if a pattern can convert this into a legal operation.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Otherwise, we need to apply a legalization pattern to this operation.
|
2019-06-06 15:48:14 -07:00
|
|
|
auto it = legalizerPatterns.find(op->getName());
|
|
|
|
|
if (it == legalizerPatterns.end()) {
|
|
|
|
|
LLVM_DEBUG(llvm::dbgs() << "-- FAIL : no known legalization path.\n");
|
|
|
|
|
return failure();
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-03 12:49:55 -07:00
|
|
|
// TODO(riverriddle) This currently has no cost model and doesn't prioritize
|
|
|
|
|
// specific patterns in any way.
|
2019-06-06 15:48:14 -07:00
|
|
|
for (auto *pattern : it->second)
|
2019-06-03 12:49:55 -07:00
|
|
|
if (succeeded(legalizePattern(op, pattern, rewriter)))
|
|
|
|
|
return success();
|
|
|
|
|
|
|
|
|
|
LLVM_DEBUG(llvm::dbgs() << "-- FAIL : no matched legalization pattern.\n");
|
|
|
|
|
return failure();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LogicalResult
|
|
|
|
|
OperationLegalizer::legalizePattern(Operation *op, RewritePattern *pattern,
|
|
|
|
|
DialectConversionRewriter &rewriter) {
|
|
|
|
|
LLVM_DEBUG({
|
|
|
|
|
llvm::dbgs() << "-* Applying rewrite pattern '" << op->getName() << " -> (";
|
|
|
|
|
interleaveComma(pattern->getGeneratedOps(), llvm::dbgs());
|
|
|
|
|
llvm::dbgs() << ")'.\n";
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Ensure that we don't cycle by not allowing the same pattern to be
|
|
|
|
|
// applied twice in the same recursion stack.
|
|
|
|
|
// TODO(riverriddle) We could eventually converge, but that requires more
|
|
|
|
|
// complicated analysis.
|
|
|
|
|
if (!appliedPatterns.insert(pattern).second) {
|
|
|
|
|
LLVM_DEBUG(llvm::dbgs() << "-- FAIL: Pattern was already applied.\n");
|
|
|
|
|
return failure();
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-05 09:36:32 -07:00
|
|
|
RewriterState curState = rewriter.getCurrentState();
|
2019-06-03 12:49:55 -07:00
|
|
|
auto cleanupFailure = [&] {
|
2019-06-05 09:36:32 -07:00
|
|
|
// Reset the rewriter state and pop this pattern.
|
|
|
|
|
rewriter.resetState(curState);
|
2019-06-03 12:49:55 -07:00
|
|
|
appliedPatterns.erase(pattern);
|
|
|
|
|
return failure();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Try to rewrite with the given pattern.
|
|
|
|
|
rewriter.setInsertionPoint(op);
|
|
|
|
|
if (!pattern->matchAndRewrite(op, rewriter)) {
|
|
|
|
|
LLVM_DEBUG(llvm::dbgs() << "-- FAIL: Pattern failed to match.\n");
|
|
|
|
|
return cleanupFailure();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Recursively legalize each of the new operations.
|
2019-06-05 09:36:32 -07:00
|
|
|
for (unsigned i = curState.numCreatedOperations,
|
|
|
|
|
e = rewriter.createdOps.size();
|
|
|
|
|
i != e; ++i) {
|
|
|
|
|
if (failed(legalize(rewriter.createdOps[i], rewriter))) {
|
|
|
|
|
LLVM_DEBUG(llvm::dbgs() << "-- FAIL: Generated operation was illegal.\n");
|
|
|
|
|
return cleanupFailure();
|
|
|
|
|
}
|
2019-06-03 12:49:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
appliedPatterns.erase(pattern);
|
|
|
|
|
return success();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OperationLegalizer::buildLegalizationGraph(
|
|
|
|
|
OwningRewritePatternList &patterns) {
|
|
|
|
|
// A mapping between an operation and a set of operations that can be used to
|
|
|
|
|
// generate it.
|
|
|
|
|
DenseMap<OperationName, SmallPtrSet<OperationName, 2>> parentOps;
|
|
|
|
|
// A mapping between an operation and any currently invalid patterns it has.
|
|
|
|
|
DenseMap<OperationName, SmallPtrSet<RewritePattern *, 2>> invalidPatterns;
|
|
|
|
|
// A worklist of patterns to consider for legality.
|
|
|
|
|
llvm::SetVector<RewritePattern *> patternWorklist;
|
|
|
|
|
|
|
|
|
|
// Build the mapping from operations to the parent ops that may generate them.
|
|
|
|
|
for (auto &pattern : patterns) {
|
|
|
|
|
auto root = pattern->getRootKind();
|
|
|
|
|
|
2019-06-06 15:48:14 -07:00
|
|
|
// Skip operations that are always known to be legal.
|
|
|
|
|
if (target.getOpAction(root) == ConversionTarget::LegalizationAction::Legal)
|
2019-06-03 12:49:55 -07:00
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// Add this pattern to the invalid set for the root op and record this root
|
|
|
|
|
// as a parent for any generated operations.
|
|
|
|
|
invalidPatterns[root].insert(pattern.get());
|
|
|
|
|
for (auto op : pattern->getGeneratedOps())
|
|
|
|
|
parentOps[op].insert(root);
|
|
|
|
|
|
2019-06-06 15:48:14 -07:00
|
|
|
// Add this pattern to the worklist.
|
|
|
|
|
patternWorklist.insert(pattern.get());
|
2019-06-03 12:49:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (!patternWorklist.empty()) {
|
|
|
|
|
auto *pattern = patternWorklist.pop_back_val();
|
|
|
|
|
|
|
|
|
|
// Check to see if any of the generated operations are invalid.
|
2019-06-06 15:48:14 -07:00
|
|
|
if (llvm::any_of(pattern->getGeneratedOps(), [&](OperationName op) {
|
|
|
|
|
return !legalizerPatterns.count(op) && !target.getOpAction(op);
|
|
|
|
|
}))
|
2019-06-03 12:49:55 -07:00
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// Otherwise, if all of the generated operation are valid, this op is now
|
|
|
|
|
// legal so add all of the child patterns to the worklist.
|
2019-06-06 15:48:14 -07:00
|
|
|
legalizerPatterns[pattern->getRootKind()].push_back(pattern);
|
2019-06-03 12:49:55 -07:00
|
|
|
invalidPatterns[pattern->getRootKind()].erase(pattern);
|
|
|
|
|
|
|
|
|
|
// Add any invalid patterns of the parent operations to see if they have now
|
|
|
|
|
// become legal.
|
|
|
|
|
for (auto op : parentOps[pattern->getRootKind()])
|
|
|
|
|
patternWorklist.set_union(invalidPatterns[op]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-19 20:54:13 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
// FunctionConverter
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
namespace {
|
2019-05-23 09:23:33 -07:00
|
|
|
// This class converts a single function using the given pattern matcher. If a
|
2019-05-24 18:17:50 -07:00
|
|
|
// TypeConverter object is provided, then the types of block arguments will be
|
|
|
|
|
// converted using the appropriate 'convertType' calls.
|
2019-06-03 12:49:55 -07:00
|
|
|
struct FunctionConverter {
|
|
|
|
|
explicit FunctionConverter(MLIRContext *ctx, ConversionTarget &target,
|
|
|
|
|
OwningRewritePatternList &patterns,
|
2019-05-24 18:17:50 -07:00
|
|
|
TypeConverter *conversion = nullptr)
|
2019-06-03 12:49:55 -07:00
|
|
|
: typeConverter(conversion), opLegalizer(target, patterns) {}
|
Generic dialect conversion pass exercised by LLVM IR lowering
This commit introduces a generic dialect conversion/lowering/legalization pass
and illustrates it on StandardOps->LLVMIR conversion.
It partially reuses the PatternRewriter infrastructure and adds the following
functionality:
- an actual pass;
- non-default pattern constructors;
- one-to-many rewrites;
- rewriting terminators with successors;
- not applying patterns iteratively (unlike the existing greedy rewrite driver);
- ability to change function signature;
- ability to change basic block argument types.
The latter two things required, given the existing API, to create new functions
in the same module. Eventually, this should converge with the rest of
PatternRewriter. However, we may want to keep two pass versions: "heavy" with
function/block argument conversion and "light" that only touches operations.
This pass creates new functions within a module as a means to change function
signature, then creates new blocks with converted argument types in the new
function. Then, it traverses the CFG in DFS-preorder to make sure defs are
converted before uses in the dominated blocks. The generic pass has a minimal
interface with two hooks: one to fill in the set of patterns, and another one
to convert types for functions and blocks. The patterns are defined as
separate classes that can be table-generated in the future.
The LLVM IR lowering pass partially inherits from the existing LLVM IR
translator, in particular for type conversion. It defines a conversion pattern
template, instantiated for different operations, and is a good candidate for
tablegen. The lowering does not yet support loads and stores and is not
connected to the translator as it would have broken the existing flows. Future
patches will add missing support before switching the translator in a single
patch.
PiperOrigin-RevId: 230951202
2019-01-25 12:46:53 -08:00
|
|
|
|
2019-05-22 11:49:04 -07:00
|
|
|
/// Converts the given function to the dialect using hooks defined in
|
2019-05-24 18:17:50 -07:00
|
|
|
/// `typeConverter`. Returns failure on error, success otherwise.
|
2019-05-22 11:49:04 -07:00
|
|
|
LogicalResult convertFunction(Function *f);
|
Generic dialect conversion pass exercised by LLVM IR lowering
This commit introduces a generic dialect conversion/lowering/legalization pass
and illustrates it on StandardOps->LLVMIR conversion.
It partially reuses the PatternRewriter infrastructure and adds the following
functionality:
- an actual pass;
- non-default pattern constructors;
- one-to-many rewrites;
- rewriting terminators with successors;
- not applying patterns iteratively (unlike the existing greedy rewrite driver);
- ability to change function signature;
- ability to change basic block argument types.
The latter two things required, given the existing API, to create new functions
in the same module. Eventually, this should converge with the rest of
PatternRewriter. However, we may want to keep two pass versions: "heavy" with
function/block argument conversion and "light" that only touches operations.
This pass creates new functions within a module as a means to change function
signature, then creates new blocks with converted argument types in the new
function. Then, it traverses the CFG in DFS-preorder to make sure defs are
converted before uses in the dominated blocks. The generic pass has a minimal
interface with two hooks: one to fill in the set of patterns, and another one
to convert types for functions and blocks. The patterns are defined as
separate classes that can be table-generated in the future.
The LLVM IR lowering pass partially inherits from the existing LLVM IR
translator, in particular for type conversion. It defines a conversion pattern
template, instantiated for different operations, and is a good candidate for
tablegen. The lowering does not yet support loads and stores and is not
connected to the translator as it would have broken the existing flows. Future
patches will add missing support before switching the translator in a single
patch.
PiperOrigin-RevId: 230951202
2019-01-25 12:46:53 -08:00
|
|
|
|
2019-05-22 11:49:04 -07:00
|
|
|
/// Converts the given region starting from the entry block and following the
|
2019-05-24 07:00:29 -07:00
|
|
|
/// block successors. Returns failure on error, success otherwise. Prints
|
|
|
|
|
/// error messages at `loc`.
|
2019-05-19 17:56:32 -07:00
|
|
|
LogicalResult convertRegion(DialectConversionRewriter &rewriter,
|
2019-05-24 07:00:29 -07:00
|
|
|
Region ®ion, Location loc);
|
2019-03-28 15:58:53 -07:00
|
|
|
|
2019-05-22 11:49:04 -07:00
|
|
|
/// Converts a block by traversing its operations sequentially, attempting to
|
|
|
|
|
/// match a pattern. If there is no match, recurses the operations regions if
|
|
|
|
|
/// it has any.
|
Generic dialect conversion pass exercised by LLVM IR lowering
This commit introduces a generic dialect conversion/lowering/legalization pass
and illustrates it on StandardOps->LLVMIR conversion.
It partially reuses the PatternRewriter infrastructure and adds the following
functionality:
- an actual pass;
- non-default pattern constructors;
- one-to-many rewrites;
- rewriting terminators with successors;
- not applying patterns iteratively (unlike the existing greedy rewrite driver);
- ability to change function signature;
- ability to change basic block argument types.
The latter two things required, given the existing API, to create new functions
in the same module. Eventually, this should converge with the rest of
PatternRewriter. However, we may want to keep two pass versions: "heavy" with
function/block argument conversion and "light" that only touches operations.
This pass creates new functions within a module as a means to change function
signature, then creates new blocks with converted argument types in the new
function. Then, it traverses the CFG in DFS-preorder to make sure defs are
converted before uses in the dominated blocks. The generic pass has a minimal
interface with two hooks: one to fill in the set of patterns, and another one
to convert types for functions and blocks. The patterns are defined as
separate classes that can be table-generated in the future.
The LLVM IR lowering pass partially inherits from the existing LLVM IR
translator, in particular for type conversion. It defines a conversion pattern
template, instantiated for different operations, and is a good candidate for
tablegen. The lowering does not yet support loads and stores and is not
connected to the translator as it would have broken the existing flows. Future
patches will add missing support before switching the translator in a single
patch.
PiperOrigin-RevId: 230951202
2019-01-25 12:46:53 -08:00
|
|
|
//
|
2019-05-22 11:49:04 -07:00
|
|
|
/// After converting operations, traverses the successor blocks unless they
|
|
|
|
|
/// have been visited already as indicated in `visitedBlocks`.
|
2019-05-19 17:56:32 -07:00
|
|
|
LogicalResult convertBlock(DialectConversionRewriter &rewriter, Block *block,
|
|
|
|
|
DenseSet<Block *> &visitedBlocks);
|
Generic dialect conversion pass exercised by LLVM IR lowering
This commit introduces a generic dialect conversion/lowering/legalization pass
and illustrates it on StandardOps->LLVMIR conversion.
It partially reuses the PatternRewriter infrastructure and adds the following
functionality:
- an actual pass;
- non-default pattern constructors;
- one-to-many rewrites;
- rewriting terminators with successors;
- not applying patterns iteratively (unlike the existing greedy rewrite driver);
- ability to change function signature;
- ability to change basic block argument types.
The latter two things required, given the existing API, to create new functions
in the same module. Eventually, this should converge with the rest of
PatternRewriter. However, we may want to keep two pass versions: "heavy" with
function/block argument conversion and "light" that only touches operations.
This pass creates new functions within a module as a means to change function
signature, then creates new blocks with converted argument types in the new
function. Then, it traverses the CFG in DFS-preorder to make sure defs are
converted before uses in the dominated blocks. The generic pass has a minimal
interface with two hooks: one to fill in the set of patterns, and another one
to convert types for functions and blocks. The patterns are defined as
separate classes that can be table-generated in the future.
The LLVM IR lowering pass partially inherits from the existing LLVM IR
translator, in particular for type conversion. It defines a conversion pattern
template, instantiated for different operations, and is a good candidate for
tablegen. The lowering does not yet support loads and stores and is not
connected to the translator as it would have broken the existing flows. Future
patches will add missing support before switching the translator in a single
patch.
PiperOrigin-RevId: 230951202
2019-01-25 12:46:53 -08:00
|
|
|
|
2019-05-22 11:49:04 -07:00
|
|
|
/// Converts the type of the given block argument. Returns success if the
|
|
|
|
|
/// argument type could be successfully converted, failure otherwise.
|
2019-05-19 17:56:32 -07:00
|
|
|
LogicalResult convertArgument(DialectConversionRewriter &rewriter,
|
|
|
|
|
BlockArgument *arg, Location loc);
|
Generic dialect conversion pass exercised by LLVM IR lowering
This commit introduces a generic dialect conversion/lowering/legalization pass
and illustrates it on StandardOps->LLVMIR conversion.
It partially reuses the PatternRewriter infrastructure and adds the following
functionality:
- an actual pass;
- non-default pattern constructors;
- one-to-many rewrites;
- rewriting terminators with successors;
- not applying patterns iteratively (unlike the existing greedy rewrite driver);
- ability to change function signature;
- ability to change basic block argument types.
The latter two things required, given the existing API, to create new functions
in the same module. Eventually, this should converge with the rest of
PatternRewriter. However, we may want to keep two pass versions: "heavy" with
function/block argument conversion and "light" that only touches operations.
This pass creates new functions within a module as a means to change function
signature, then creates new blocks with converted argument types in the new
function. Then, it traverses the CFG in DFS-preorder to make sure defs are
converted before uses in the dominated blocks. The generic pass has a minimal
interface with two hooks: one to fill in the set of patterns, and another one
to convert types for functions and blocks. The patterns are defined as
separate classes that can be table-generated in the future.
The LLVM IR lowering pass partially inherits from the existing LLVM IR
translator, in particular for type conversion. It defines a conversion pattern
template, instantiated for different operations, and is a good candidate for
tablegen. The lowering does not yet support loads and stores and is not
connected to the translator as it would have broken the existing flows. Future
patches will add missing support before switching the translator in a single
patch.
PiperOrigin-RevId: 230951202
2019-01-25 12:46:53 -08:00
|
|
|
|
2019-05-22 11:49:04 -07:00
|
|
|
/// Pointer to a specific dialect conversion info.
|
2019-05-24 18:17:50 -07:00
|
|
|
TypeConverter *typeConverter;
|
Generic dialect conversion pass exercised by LLVM IR lowering
This commit introduces a generic dialect conversion/lowering/legalization pass
and illustrates it on StandardOps->LLVMIR conversion.
It partially reuses the PatternRewriter infrastructure and adds the following
functionality:
- an actual pass;
- non-default pattern constructors;
- one-to-many rewrites;
- rewriting terminators with successors;
- not applying patterns iteratively (unlike the existing greedy rewrite driver);
- ability to change function signature;
- ability to change basic block argument types.
The latter two things required, given the existing API, to create new functions
in the same module. Eventually, this should converge with the rest of
PatternRewriter. However, we may want to keep two pass versions: "heavy" with
function/block argument conversion and "light" that only touches operations.
This pass creates new functions within a module as a means to change function
signature, then creates new blocks with converted argument types in the new
function. Then, it traverses the CFG in DFS-preorder to make sure defs are
converted before uses in the dominated blocks. The generic pass has a minimal
interface with two hooks: one to fill in the set of patterns, and another one
to convert types for functions and blocks. The patterns are defined as
separate classes that can be table-generated in the future.
The LLVM IR lowering pass partially inherits from the existing LLVM IR
translator, in particular for type conversion. It defines a conversion pattern
template, instantiated for different operations, and is a good candidate for
tablegen. The lowering does not yet support loads and stores and is not
connected to the translator as it would have broken the existing flows. Future
patches will add missing support before switching the translator in a single
patch.
PiperOrigin-RevId: 230951202
2019-01-25 12:46:53 -08:00
|
|
|
|
2019-06-03 12:49:55 -07:00
|
|
|
/// The legalizer to use when converting operations.
|
|
|
|
|
OperationLegalizer opLegalizer;
|
Generic dialect conversion pass exercised by LLVM IR lowering
This commit introduces a generic dialect conversion/lowering/legalization pass
and illustrates it on StandardOps->LLVMIR conversion.
It partially reuses the PatternRewriter infrastructure and adds the following
functionality:
- an actual pass;
- non-default pattern constructors;
- one-to-many rewrites;
- rewriting terminators with successors;
- not applying patterns iteratively (unlike the existing greedy rewrite driver);
- ability to change function signature;
- ability to change basic block argument types.
The latter two things required, given the existing API, to create new functions
in the same module. Eventually, this should converge with the rest of
PatternRewriter. However, we may want to keep two pass versions: "heavy" with
function/block argument conversion and "light" that only touches operations.
This pass creates new functions within a module as a means to change function
signature, then creates new blocks with converted argument types in the new
function. Then, it traverses the CFG in DFS-preorder to make sure defs are
converted before uses in the dominated blocks. The generic pass has a minimal
interface with two hooks: one to fill in the set of patterns, and another one
to convert types for functions and blocks. The patterns are defined as
separate classes that can be table-generated in the future.
The LLVM IR lowering pass partially inherits from the existing LLVM IR
translator, in particular for type conversion. It defines a conversion pattern
template, instantiated for different operations, and is a good candidate for
tablegen. The lowering does not yet support loads and stores and is not
connected to the translator as it would have broken the existing flows. Future
patches will add missing support before switching the translator in a single
patch.
PiperOrigin-RevId: 230951202
2019-01-25 12:46:53 -08:00
|
|
|
};
|
2019-05-19 20:54:13 -07:00
|
|
|
} // end anonymous namespace
|
Generic dialect conversion pass exercised by LLVM IR lowering
This commit introduces a generic dialect conversion/lowering/legalization pass
and illustrates it on StandardOps->LLVMIR conversion.
It partially reuses the PatternRewriter infrastructure and adds the following
functionality:
- an actual pass;
- non-default pattern constructors;
- one-to-many rewrites;
- rewriting terminators with successors;
- not applying patterns iteratively (unlike the existing greedy rewrite driver);
- ability to change function signature;
- ability to change basic block argument types.
The latter two things required, given the existing API, to create new functions
in the same module. Eventually, this should converge with the rest of
PatternRewriter. However, we may want to keep two pass versions: "heavy" with
function/block argument conversion and "light" that only touches operations.
This pass creates new functions within a module as a means to change function
signature, then creates new blocks with converted argument types in the new
function. Then, it traverses the CFG in DFS-preorder to make sure defs are
converted before uses in the dominated blocks. The generic pass has a minimal
interface with two hooks: one to fill in the set of patterns, and another one
to convert types for functions and blocks. The patterns are defined as
separate classes that can be table-generated in the future.
The LLVM IR lowering pass partially inherits from the existing LLVM IR
translator, in particular for type conversion. It defines a conversion pattern
template, instantiated for different operations, and is a good candidate for
tablegen. The lowering does not yet support loads and stores and is not
connected to the translator as it would have broken the existing flows. Future
patches will add missing support before switching the translator in a single
patch.
PiperOrigin-RevId: 230951202
2019-01-25 12:46:53 -08:00
|
|
|
|
2019-03-08 16:04:42 -08:00
|
|
|
LogicalResult
|
2019-05-19 17:56:32 -07:00
|
|
|
FunctionConverter::convertArgument(DialectConversionRewriter &rewriter,
|
|
|
|
|
BlockArgument *arg, Location loc) {
|
2019-05-24 18:17:50 -07:00
|
|
|
auto convertedType = typeConverter->convertType(arg->getType());
|
2019-05-19 17:56:32 -07:00
|
|
|
if (!convertedType)
|
|
|
|
|
return arg->getContext()->emitError(loc)
|
|
|
|
|
<< "could not convert block argument of type : " << arg->getType();
|
|
|
|
|
|
|
|
|
|
// Generate a replacement value, with the new type, for this argument.
|
2019-05-22 11:49:04 -07:00
|
|
|
if (convertedType != arg->getType())
|
|
|
|
|
rewriter.argConverter.castArgument(arg, convertedType, rewriter.mapping);
|
2019-05-19 17:56:32 -07:00
|
|
|
return success();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LogicalResult
|
|
|
|
|
FunctionConverter::convertBlock(DialectConversionRewriter &rewriter,
|
|
|
|
|
Block *block,
|
|
|
|
|
DenseSet<Block *> &visitedBlocks) {
|
Generic dialect conversion pass exercised by LLVM IR lowering
This commit introduces a generic dialect conversion/lowering/legalization pass
and illustrates it on StandardOps->LLVMIR conversion.
It partially reuses the PatternRewriter infrastructure and adds the following
functionality:
- an actual pass;
- non-default pattern constructors;
- one-to-many rewrites;
- rewriting terminators with successors;
- not applying patterns iteratively (unlike the existing greedy rewrite driver);
- ability to change function signature;
- ability to change basic block argument types.
The latter two things required, given the existing API, to create new functions
in the same module. Eventually, this should converge with the rest of
PatternRewriter. However, we may want to keep two pass versions: "heavy" with
function/block argument conversion and "light" that only touches operations.
This pass creates new functions within a module as a means to change function
signature, then creates new blocks with converted argument types in the new
function. Then, it traverses the CFG in DFS-preorder to make sure defs are
converted before uses in the dominated blocks. The generic pass has a minimal
interface with two hooks: one to fill in the set of patterns, and another one
to convert types for functions and blocks. The patterns are defined as
separate classes that can be table-generated in the future.
The LLVM IR lowering pass partially inherits from the existing LLVM IR
translator, in particular for type conversion. It defines a conversion pattern
template, instantiated for different operations, and is a good candidate for
tablegen. The lowering does not yet support loads and stores and is not
connected to the translator as it would have broken the existing flows. Future
patches will add missing support before switching the translator in a single
patch.
PiperOrigin-RevId: 230951202
2019-01-25 12:46:53 -08:00
|
|
|
// First, add the current block to the list of visited blocks.
|
|
|
|
|
visitedBlocks.insert(block);
|
2019-05-19 17:56:32 -07:00
|
|
|
|
|
|
|
|
// Preserve the successors before rewriting the operations.
|
|
|
|
|
SmallVector<Block *, 4> successors(block->getSuccessors());
|
Generic dialect conversion pass exercised by LLVM IR lowering
This commit introduces a generic dialect conversion/lowering/legalization pass
and illustrates it on StandardOps->LLVMIR conversion.
It partially reuses the PatternRewriter infrastructure and adds the following
functionality:
- an actual pass;
- non-default pattern constructors;
- one-to-many rewrites;
- rewriting terminators with successors;
- not applying patterns iteratively (unlike the existing greedy rewrite driver);
- ability to change function signature;
- ability to change basic block argument types.
The latter two things required, given the existing API, to create new functions
in the same module. Eventually, this should converge with the rest of
PatternRewriter. However, we may want to keep two pass versions: "heavy" with
function/block argument conversion and "light" that only touches operations.
This pass creates new functions within a module as a means to change function
signature, then creates new blocks with converted argument types in the new
function. Then, it traverses the CFG in DFS-preorder to make sure defs are
converted before uses in the dominated blocks. The generic pass has a minimal
interface with two hooks: one to fill in the set of patterns, and another one
to convert types for functions and blocks. The patterns are defined as
separate classes that can be table-generated in the future.
The LLVM IR lowering pass partially inherits from the existing LLVM IR
translator, in particular for type conversion. It defines a conversion pattern
template, instantiated for different operations, and is a good candidate for
tablegen. The lowering does not yet support loads and stores and is not
connected to the translator as it would have broken the existing flows. Future
patches will add missing support before switching the translator in a single
patch.
PiperOrigin-RevId: 230951202
2019-01-25 12:46:53 -08:00
|
|
|
|
|
|
|
|
// Iterate over ops and convert them.
|
2019-05-19 17:56:32 -07:00
|
|
|
for (Operation &op : llvm::make_early_inc_range(*block)) {
|
|
|
|
|
// Traverse any held regions.
|
|
|
|
|
for (auto ®ion : op.getRegions())
|
2019-05-24 07:00:29 -07:00
|
|
|
if (!region.empty() &&
|
|
|
|
|
failed(convertRegion(rewriter, region, op.getLoc())))
|
2019-05-19 17:56:32 -07:00
|
|
|
return failure();
|
2019-06-03 12:49:55 -07:00
|
|
|
|
|
|
|
|
// Legalize the current operation.
|
|
|
|
|
(void)opLegalizer.legalize(&op, rewriter);
|
Generic dialect conversion pass exercised by LLVM IR lowering
This commit introduces a generic dialect conversion/lowering/legalization pass
and illustrates it on StandardOps->LLVMIR conversion.
It partially reuses the PatternRewriter infrastructure and adds the following
functionality:
- an actual pass;
- non-default pattern constructors;
- one-to-many rewrites;
- rewriting terminators with successors;
- not applying patterns iteratively (unlike the existing greedy rewrite driver);
- ability to change function signature;
- ability to change basic block argument types.
The latter two things required, given the existing API, to create new functions
in the same module. Eventually, this should converge with the rest of
PatternRewriter. However, we may want to keep two pass versions: "heavy" with
function/block argument conversion and "light" that only touches operations.
This pass creates new functions within a module as a means to change function
signature, then creates new blocks with converted argument types in the new
function. Then, it traverses the CFG in DFS-preorder to make sure defs are
converted before uses in the dominated blocks. The generic pass has a minimal
interface with two hooks: one to fill in the set of patterns, and another one
to convert types for functions and blocks. The patterns are defined as
separate classes that can be table-generated in the future.
The LLVM IR lowering pass partially inherits from the existing LLVM IR
translator, in particular for type conversion. It defines a conversion pattern
template, instantiated for different operations, and is a good candidate for
tablegen. The lowering does not yet support loads and stores and is not
connected to the translator as it would have broken the existing flows. Future
patches will add missing support before switching the translator in a single
patch.
PiperOrigin-RevId: 230951202
2019-01-25 12:46:53 -08:00
|
|
|
}
|
|
|
|
|
|
2019-05-19 17:56:32 -07:00
|
|
|
// Recurse to children that haven't been visited.
|
|
|
|
|
for (Block *succ : successors) {
|
|
|
|
|
if (visitedBlocks.count(succ))
|
Generic dialect conversion pass exercised by LLVM IR lowering
This commit introduces a generic dialect conversion/lowering/legalization pass
and illustrates it on StandardOps->LLVMIR conversion.
It partially reuses the PatternRewriter infrastructure and adds the following
functionality:
- an actual pass;
- non-default pattern constructors;
- one-to-many rewrites;
- rewriting terminators with successors;
- not applying patterns iteratively (unlike the existing greedy rewrite driver);
- ability to change function signature;
- ability to change basic block argument types.
The latter two things required, given the existing API, to create new functions
in the same module. Eventually, this should converge with the rest of
PatternRewriter. However, we may want to keep two pass versions: "heavy" with
function/block argument conversion and "light" that only touches operations.
This pass creates new functions within a module as a means to change function
signature, then creates new blocks with converted argument types in the new
function. Then, it traverses the CFG in DFS-preorder to make sure defs are
converted before uses in the dominated blocks. The generic pass has a minimal
interface with two hooks: one to fill in the set of patterns, and another one
to convert types for functions and blocks. The patterns are defined as
separate classes that can be table-generated in the future.
The LLVM IR lowering pass partially inherits from the existing LLVM IR
translator, in particular for type conversion. It defines a conversion pattern
template, instantiated for different operations, and is a good candidate for
tablegen. The lowering does not yet support loads and stores and is not
connected to the translator as it would have broken the existing flows. Future
patches will add missing support before switching the translator in a single
patch.
PiperOrigin-RevId: 230951202
2019-01-25 12:46:53 -08:00
|
|
|
continue;
|
2019-05-19 17:56:32 -07:00
|
|
|
if (failed(convertBlock(rewriter, succ, visitedBlocks)))
|
2019-03-10 15:32:54 -07:00
|
|
|
return failure();
|
Generic dialect conversion pass exercised by LLVM IR lowering
This commit introduces a generic dialect conversion/lowering/legalization pass
and illustrates it on StandardOps->LLVMIR conversion.
It partially reuses the PatternRewriter infrastructure and adds the following
functionality:
- an actual pass;
- non-default pattern constructors;
- one-to-many rewrites;
- rewriting terminators with successors;
- not applying patterns iteratively (unlike the existing greedy rewrite driver);
- ability to change function signature;
- ability to change basic block argument types.
The latter two things required, given the existing API, to create new functions
in the same module. Eventually, this should converge with the rest of
PatternRewriter. However, we may want to keep two pass versions: "heavy" with
function/block argument conversion and "light" that only touches operations.
This pass creates new functions within a module as a means to change function
signature, then creates new blocks with converted argument types in the new
function. Then, it traverses the CFG in DFS-preorder to make sure defs are
converted before uses in the dominated blocks. The generic pass has a minimal
interface with two hooks: one to fill in the set of patterns, and another one
to convert types for functions and blocks. The patterns are defined as
separate classes that can be table-generated in the future.
The LLVM IR lowering pass partially inherits from the existing LLVM IR
translator, in particular for type conversion. It defines a conversion pattern
template, instantiated for different operations, and is a good candidate for
tablegen. The lowering does not yet support loads and stores and is not
connected to the translator as it would have broken the existing flows. Future
patches will add missing support before switching the translator in a single
patch.
PiperOrigin-RevId: 230951202
2019-01-25 12:46:53 -08:00
|
|
|
}
|
2019-03-10 15:32:54 -07:00
|
|
|
return success();
|
Generic dialect conversion pass exercised by LLVM IR lowering
This commit introduces a generic dialect conversion/lowering/legalization pass
and illustrates it on StandardOps->LLVMIR conversion.
It partially reuses the PatternRewriter infrastructure and adds the following
functionality:
- an actual pass;
- non-default pattern constructors;
- one-to-many rewrites;
- rewriting terminators with successors;
- not applying patterns iteratively (unlike the existing greedy rewrite driver);
- ability to change function signature;
- ability to change basic block argument types.
The latter two things required, given the existing API, to create new functions
in the same module. Eventually, this should converge with the rest of
PatternRewriter. However, we may want to keep two pass versions: "heavy" with
function/block argument conversion and "light" that only touches operations.
This pass creates new functions within a module as a means to change function
signature, then creates new blocks with converted argument types in the new
function. Then, it traverses the CFG in DFS-preorder to make sure defs are
converted before uses in the dominated blocks. The generic pass has a minimal
interface with two hooks: one to fill in the set of patterns, and another one
to convert types for functions and blocks. The patterns are defined as
separate classes that can be table-generated in the future.
The LLVM IR lowering pass partially inherits from the existing LLVM IR
translator, in particular for type conversion. It defines a conversion pattern
template, instantiated for different operations, and is a good candidate for
tablegen. The lowering does not yet support loads and stores and is not
connected to the translator as it would have broken the existing flows. Future
patches will add missing support before switching the translator in a single
patch.
PiperOrigin-RevId: 230951202
2019-01-25 12:46:53 -08:00
|
|
|
}
|
|
|
|
|
|
2019-05-19 17:56:32 -07:00
|
|
|
LogicalResult
|
|
|
|
|
FunctionConverter::convertRegion(DialectConversionRewriter &rewriter,
|
2019-05-24 07:00:29 -07:00
|
|
|
Region ®ion, Location loc) {
|
2019-05-19 17:56:32 -07:00
|
|
|
assert(!region.empty() && "expected non-empty region");
|
|
|
|
|
|
2019-05-23 09:23:33 -07:00
|
|
|
// Create the arguments of each of the blocks in the region. If a type
|
|
|
|
|
// converter was not provided, then we don't need to change any of the block
|
|
|
|
|
// types.
|
2019-05-24 18:17:50 -07:00
|
|
|
if (typeConverter) {
|
2019-05-23 09:23:33 -07:00
|
|
|
for (Block &block : region)
|
|
|
|
|
for (auto *arg : block.getArguments())
|
2019-05-24 07:00:29 -07:00
|
|
|
if (failed(convertArgument(rewriter, arg, loc)))
|
2019-05-23 09:23:33 -07:00
|
|
|
return failure();
|
|
|
|
|
}
|
2019-03-28 15:58:53 -07:00
|
|
|
|
|
|
|
|
// Start a DFS-order traversal of the CFG to make sure defs are converted
|
|
|
|
|
// before uses in dominated blocks.
|
|
|
|
|
llvm::DenseSet<Block *> visitedBlocks;
|
2019-05-19 17:56:32 -07:00
|
|
|
if (failed(convertBlock(rewriter, ®ion.front(), visitedBlocks)))
|
|
|
|
|
return failure();
|
2019-03-28 15:58:53 -07:00
|
|
|
|
|
|
|
|
// If some blocks are not reachable through successor chains, they should have
|
|
|
|
|
// been removed by the DCE before this.
|
2019-05-19 17:56:32 -07:00
|
|
|
if (visitedBlocks.size() != std::distance(region.begin(), region.end()))
|
2019-05-24 07:00:29 -07:00
|
|
|
return rewriter.getContext()->emitError(loc)
|
|
|
|
|
<< "unreachable blocks were not converted";
|
2019-05-19 17:56:32 -07:00
|
|
|
return success();
|
2019-03-28 15:58:53 -07:00
|
|
|
}
|
|
|
|
|
|
2019-05-22 11:49:04 -07:00
|
|
|
LogicalResult FunctionConverter::convertFunction(Function *f) {
|
|
|
|
|
// If this is an external function, there is nothing else to do.
|
|
|
|
|
if (f->isExternal())
|
|
|
|
|
return success();
|
Generic dialect conversion pass exercised by LLVM IR lowering
This commit introduces a generic dialect conversion/lowering/legalization pass
and illustrates it on StandardOps->LLVMIR conversion.
It partially reuses the PatternRewriter infrastructure and adds the following
functionality:
- an actual pass;
- non-default pattern constructors;
- one-to-many rewrites;
- rewriting terminators with successors;
- not applying patterns iteratively (unlike the existing greedy rewrite driver);
- ability to change function signature;
- ability to change basic block argument types.
The latter two things required, given the existing API, to create new functions
in the same module. Eventually, this should converge with the rest of
PatternRewriter. However, we may want to keep two pass versions: "heavy" with
function/block argument conversion and "light" that only touches operations.
This pass creates new functions within a module as a means to change function
signature, then creates new blocks with converted argument types in the new
function. Then, it traverses the CFG in DFS-preorder to make sure defs are
converted before uses in the dominated blocks. The generic pass has a minimal
interface with two hooks: one to fill in the set of patterns, and another one
to convert types for functions and blocks. The patterns are defined as
separate classes that can be table-generated in the future.
The LLVM IR lowering pass partially inherits from the existing LLVM IR
translator, in particular for type conversion. It defines a conversion pattern
template, instantiated for different operations, and is a good candidate for
tablegen. The lowering does not yet support loads and stores and is not
connected to the translator as it would have broken the existing flows. Future
patches will add missing support before switching the translator in a single
patch.
PiperOrigin-RevId: 230951202
2019-01-25 12:46:53 -08:00
|
|
|
|
2019-05-22 11:49:04 -07:00
|
|
|
// Rewrite the function body.
|
2019-06-04 19:18:23 -07:00
|
|
|
DialectConversionRewriter rewriter(f->getBody());
|
2019-05-24 07:00:29 -07:00
|
|
|
if (failed(convertRegion(rewriter, f->getBody(), f->getLoc()))) {
|
2019-05-23 09:23:33 -07:00
|
|
|
// Reset any of the generated rewrites.
|
|
|
|
|
rewriter.discardRewrites();
|
2019-05-22 11:49:04 -07:00
|
|
|
return failure();
|
2019-05-19 17:56:32 -07:00
|
|
|
}
|
2019-05-22 11:49:04 -07:00
|
|
|
|
|
|
|
|
// Otherwise the conversion succeeded, so apply all rewrites.
|
|
|
|
|
rewriter.applyRewrites();
|
|
|
|
|
return success();
|
Generic dialect conversion pass exercised by LLVM IR lowering
This commit introduces a generic dialect conversion/lowering/legalization pass
and illustrates it on StandardOps->LLVMIR conversion.
It partially reuses the PatternRewriter infrastructure and adds the following
functionality:
- an actual pass;
- non-default pattern constructors;
- one-to-many rewrites;
- rewriting terminators with successors;
- not applying patterns iteratively (unlike the existing greedy rewrite driver);
- ability to change function signature;
- ability to change basic block argument types.
The latter two things required, given the existing API, to create new functions
in the same module. Eventually, this should converge with the rest of
PatternRewriter. However, we may want to keep two pass versions: "heavy" with
function/block argument conversion and "light" that only touches operations.
This pass creates new functions within a module as a means to change function
signature, then creates new blocks with converted argument types in the new
function. Then, it traverses the CFG in DFS-preorder to make sure defs are
converted before uses in the dominated blocks. The generic pass has a minimal
interface with two hooks: one to fill in the set of patterns, and another one
to convert types for functions and blocks. The patterns are defined as
separate classes that can be table-generated in the future.
The LLVM IR lowering pass partially inherits from the existing LLVM IR
translator, in particular for type conversion. It defines a conversion pattern
template, instantiated for different operations, and is a good candidate for
tablegen. The lowering does not yet support loads and stores and is not
connected to the translator as it would have broken the existing flows. Future
patches will add missing support before switching the translator in a single
patch.
PiperOrigin-RevId: 230951202
2019-01-25 12:46:53 -08:00
|
|
|
}
|
|
|
|
|
|
2019-05-19 20:54:13 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
2019-05-24 18:17:50 -07:00
|
|
|
// TypeConverter
|
2019-05-19 20:54:13 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
2019-05-17 22:21:13 -07:00
|
|
|
// Create a function type with arguments and results converted, and argument
|
|
|
|
|
// attributes passed through.
|
2019-05-24 18:17:50 -07:00
|
|
|
FunctionType TypeConverter::convertFunctionSignatureType(
|
2019-05-17 22:21:13 -07:00
|
|
|
FunctionType type, ArrayRef<NamedAttributeList> argAttrs,
|
|
|
|
|
SmallVectorImpl<NamedAttributeList> &convertedArgAttrs) {
|
|
|
|
|
SmallVector<Type, 8> arguments;
|
|
|
|
|
SmallVector<Type, 4> results;
|
|
|
|
|
|
|
|
|
|
arguments.reserve(type.getNumInputs());
|
|
|
|
|
for (auto t : type.getInputs())
|
|
|
|
|
arguments.push_back(convertType(t));
|
|
|
|
|
|
|
|
|
|
results.reserve(type.getNumResults());
|
|
|
|
|
for (auto t : type.getResults())
|
|
|
|
|
results.push_back(convertType(t));
|
|
|
|
|
|
|
|
|
|
// Note this will cause an extra allocation only if we need
|
|
|
|
|
// to grow the caller-provided resulting attribute vector.
|
|
|
|
|
convertedArgAttrs.reserve(arguments.size());
|
|
|
|
|
for (auto attr : argAttrs)
|
|
|
|
|
convertedArgAttrs.push_back(attr);
|
|
|
|
|
|
|
|
|
|
return FunctionType::get(arguments, results, type.getContext());
|
Generic dialect conversion pass exercised by LLVM IR lowering
This commit introduces a generic dialect conversion/lowering/legalization pass
and illustrates it on StandardOps->LLVMIR conversion.
It partially reuses the PatternRewriter infrastructure and adds the following
functionality:
- an actual pass;
- non-default pattern constructors;
- one-to-many rewrites;
- rewriting terminators with successors;
- not applying patterns iteratively (unlike the existing greedy rewrite driver);
- ability to change function signature;
- ability to change basic block argument types.
The latter two things required, given the existing API, to create new functions
in the same module. Eventually, this should converge with the rest of
PatternRewriter. However, we may want to keep two pass versions: "heavy" with
function/block argument conversion and "light" that only touches operations.
This pass creates new functions within a module as a means to change function
signature, then creates new blocks with converted argument types in the new
function. Then, it traverses the CFG in DFS-preorder to make sure defs are
converted before uses in the dominated blocks. The generic pass has a minimal
interface with two hooks: one to fill in the set of patterns, and another one
to convert types for functions and blocks. The patterns are defined as
separate classes that can be table-generated in the future.
The LLVM IR lowering pass partially inherits from the existing LLVM IR
translator, in particular for type conversion. It defines a conversion pattern
template, instantiated for different operations, and is a good candidate for
tablegen. The lowering does not yet support loads and stores and is not
connected to the translator as it would have broken the existing flows. Future
patches will add missing support before switching the translator in a single
patch.
PiperOrigin-RevId: 230951202
2019-01-25 12:46:53 -08:00
|
|
|
}
|
|
|
|
|
|
2019-05-23 09:23:33 -07:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
// applyConversionPatterns
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
Generic dialect conversion pass exercised by LLVM IR lowering
This commit introduces a generic dialect conversion/lowering/legalization pass
and illustrates it on StandardOps->LLVMIR conversion.
It partially reuses the PatternRewriter infrastructure and adds the following
functionality:
- an actual pass;
- non-default pattern constructors;
- one-to-many rewrites;
- rewriting terminators with successors;
- not applying patterns iteratively (unlike the existing greedy rewrite driver);
- ability to change function signature;
- ability to change basic block argument types.
The latter two things required, given the existing API, to create new functions
in the same module. Eventually, this should converge with the rest of
PatternRewriter. However, we may want to keep two pass versions: "heavy" with
function/block argument conversion and "light" that only touches operations.
This pass creates new functions within a module as a means to change function
signature, then creates new blocks with converted argument types in the new
function. Then, it traverses the CFG in DFS-preorder to make sure defs are
converted before uses in the dominated blocks. The generic pass has a minimal
interface with two hooks: one to fill in the set of patterns, and another one
to convert types for functions and blocks. The patterns are defined as
separate classes that can be table-generated in the future.
The LLVM IR lowering pass partially inherits from the existing LLVM IR
translator, in particular for type conversion. It defines a conversion pattern
template, instantiated for different operations, and is a good candidate for
tablegen. The lowering does not yet support loads and stores and is not
connected to the translator as it would have broken the existing flows. Future
patches will add missing support before switching the translator in a single
patch.
PiperOrigin-RevId: 230951202
2019-01-25 12:46:53 -08:00
|
|
|
|
2019-05-23 09:23:33 -07:00
|
|
|
namespace {
|
|
|
|
|
/// This class represents a function to be converted. It allows for converting
|
|
|
|
|
/// the body of functions and the signature in two phases.
|
|
|
|
|
struct ConvertedFunction {
|
|
|
|
|
ConvertedFunction(Function *fn, FunctionType newType,
|
|
|
|
|
ArrayRef<NamedAttributeList> newFunctionArgAttrs)
|
|
|
|
|
: fn(fn), newType(newType),
|
|
|
|
|
newFunctionArgAttrs(newFunctionArgAttrs.begin(),
|
|
|
|
|
newFunctionArgAttrs.end()) {}
|
|
|
|
|
|
|
|
|
|
/// The function to convert.
|
|
|
|
|
Function *fn;
|
|
|
|
|
/// The new type and argument attributes for the function.
|
|
|
|
|
FunctionType newType;
|
|
|
|
|
SmallVector<NamedAttributeList, 4> newFunctionArgAttrs;
|
|
|
|
|
};
|
|
|
|
|
} // end anonymous namespace
|
|
|
|
|
|
2019-05-24 18:17:50 -07:00
|
|
|
/// Convert the given module with the provided conversion patterns and type
|
|
|
|
|
/// conversion object. If conversion fails for specific functions, those
|
|
|
|
|
/// functions remains unmodified.
|
|
|
|
|
LogicalResult
|
2019-06-03 12:49:55 -07:00
|
|
|
mlir::applyConversionPatterns(Module &module, ConversionTarget &target,
|
|
|
|
|
TypeConverter &converter,
|
2019-05-24 18:17:50 -07:00
|
|
|
OwningRewritePatternList &&patterns) {
|
2019-06-04 11:35:21 -07:00
|
|
|
std::vector<Function *> allFunctions;
|
|
|
|
|
allFunctions.reserve(module.getFunctions().size());
|
|
|
|
|
for (auto &func : module)
|
|
|
|
|
allFunctions.push_back(&func);
|
|
|
|
|
return applyConversionPatterns(allFunctions, target, converter,
|
|
|
|
|
std::move(patterns));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Convert the given functions with the provided conversion patterns. This will
|
|
|
|
|
/// convert as many of the operations within each function as possible given the
|
|
|
|
|
/// set of patterns. If conversion fails for specific functions, those functions
|
|
|
|
|
// remains unmodified.
|
|
|
|
|
LogicalResult mlir::applyConversionPatterns(
|
|
|
|
|
ArrayRef<Function *> fns, ConversionTarget &target,
|
|
|
|
|
TypeConverter &converter, OwningRewritePatternList &&patterns) {
|
|
|
|
|
if (fns.empty())
|
|
|
|
|
return success();
|
|
|
|
|
|
2019-06-03 12:49:55 -07:00
|
|
|
// Build the function converter.
|
2019-06-04 11:35:21 -07:00
|
|
|
FunctionConverter funcConverter(fns.front()->getContext(), target, patterns,
|
2019-06-03 12:49:55 -07:00
|
|
|
&converter);
|
Generic dialect conversion pass exercised by LLVM IR lowering
This commit introduces a generic dialect conversion/lowering/legalization pass
and illustrates it on StandardOps->LLVMIR conversion.
It partially reuses the PatternRewriter infrastructure and adds the following
functionality:
- an actual pass;
- non-default pattern constructors;
- one-to-many rewrites;
- rewriting terminators with successors;
- not applying patterns iteratively (unlike the existing greedy rewrite driver);
- ability to change function signature;
- ability to change basic block argument types.
The latter two things required, given the existing API, to create new functions
in the same module. Eventually, this should converge with the rest of
PatternRewriter. However, we may want to keep two pass versions: "heavy" with
function/block argument conversion and "light" that only touches operations.
This pass creates new functions within a module as a means to change function
signature, then creates new blocks with converted argument types in the new
function. Then, it traverses the CFG in DFS-preorder to make sure defs are
converted before uses in the dominated blocks. The generic pass has a minimal
interface with two hooks: one to fill in the set of patterns, and another one
to convert types for functions and blocks. The patterns are defined as
separate classes that can be table-generated in the future.
The LLVM IR lowering pass partially inherits from the existing LLVM IR
translator, in particular for type conversion. It defines a conversion pattern
template, instantiated for different operations, and is a good candidate for
tablegen. The lowering does not yet support loads and stores and is not
connected to the translator as it would have broken the existing flows. Future
patches will add missing support before switching the translator in a single
patch.
PiperOrigin-RevId: 230951202
2019-01-25 12:46:53 -08:00
|
|
|
|
2019-05-22 11:49:04 -07:00
|
|
|
// Try to convert each of the functions within the module. Defer updating the
|
|
|
|
|
// signatures of the functions until after all of the bodies have been
|
|
|
|
|
// converted. This allows for the conversion patterns to still rely on the
|
|
|
|
|
// public signatures of the functions within the module before they are
|
|
|
|
|
// updated.
|
|
|
|
|
std::vector<ConvertedFunction> toConvert;
|
2019-06-04 11:35:21 -07:00
|
|
|
toConvert.reserve(fns.size());
|
|
|
|
|
for (auto *func : fns) {
|
2019-05-22 11:49:04 -07:00
|
|
|
// Convert the function type using the dialect converter.
|
|
|
|
|
SmallVector<NamedAttributeList, 4> newFunctionArgAttrs;
|
2019-05-23 09:23:33 -07:00
|
|
|
FunctionType newType = converter.convertFunctionSignatureType(
|
2019-06-04 11:35:21 -07:00
|
|
|
func->getType(), func->getAllArgAttrs(), newFunctionArgAttrs);
|
2019-05-22 11:49:04 -07:00
|
|
|
if (!newType || !newType.isa<FunctionType>())
|
2019-06-04 11:35:21 -07:00
|
|
|
return func->emitError("could not convert function type");
|
2019-05-22 11:49:04 -07:00
|
|
|
|
|
|
|
|
// Convert the body of this function.
|
2019-06-04 11:35:21 -07:00
|
|
|
if (failed(funcConverter.convertFunction(func)))
|
2019-03-10 15:32:54 -07:00
|
|
|
return failure();
|
Generic dialect conversion pass exercised by LLVM IR lowering
This commit introduces a generic dialect conversion/lowering/legalization pass
and illustrates it on StandardOps->LLVMIR conversion.
It partially reuses the PatternRewriter infrastructure and adds the following
functionality:
- an actual pass;
- non-default pattern constructors;
- one-to-many rewrites;
- rewriting terminators with successors;
- not applying patterns iteratively (unlike the existing greedy rewrite driver);
- ability to change function signature;
- ability to change basic block argument types.
The latter two things required, given the existing API, to create new functions
in the same module. Eventually, this should converge with the rest of
PatternRewriter. However, we may want to keep two pass versions: "heavy" with
function/block argument conversion and "light" that only touches operations.
This pass creates new functions within a module as a means to change function
signature, then creates new blocks with converted argument types in the new
function. Then, it traverses the CFG in DFS-preorder to make sure defs are
converted before uses in the dominated blocks. The generic pass has a minimal
interface with two hooks: one to fill in the set of patterns, and another one
to convert types for functions and blocks. The patterns are defined as
separate classes that can be table-generated in the future.
The LLVM IR lowering pass partially inherits from the existing LLVM IR
translator, in particular for type conversion. It defines a conversion pattern
template, instantiated for different operations, and is a good candidate for
tablegen. The lowering does not yet support loads and stores and is not
connected to the translator as it would have broken the existing flows. Future
patches will add missing support before switching the translator in a single
patch.
PiperOrigin-RevId: 230951202
2019-01-25 12:46:53 -08:00
|
|
|
|
2019-05-22 11:49:04 -07:00
|
|
|
// Add function signature to be updated.
|
2019-06-04 11:35:21 -07:00
|
|
|
toConvert.emplace_back(func, newType.cast<FunctionType>(),
|
2019-05-22 11:49:04 -07:00
|
|
|
newFunctionArgAttrs);
|
Generic dialect conversion pass exercised by LLVM IR lowering
This commit introduces a generic dialect conversion/lowering/legalization pass
and illustrates it on StandardOps->LLVMIR conversion.
It partially reuses the PatternRewriter infrastructure and adds the following
functionality:
- an actual pass;
- non-default pattern constructors;
- one-to-many rewrites;
- rewriting terminators with successors;
- not applying patterns iteratively (unlike the existing greedy rewrite driver);
- ability to change function signature;
- ability to change basic block argument types.
The latter two things required, given the existing API, to create new functions
in the same module. Eventually, this should converge with the rest of
PatternRewriter. However, we may want to keep two pass versions: "heavy" with
function/block argument conversion and "light" that only touches operations.
This pass creates new functions within a module as a means to change function
signature, then creates new blocks with converted argument types in the new
function. Then, it traverses the CFG in DFS-preorder to make sure defs are
converted before uses in the dominated blocks. The generic pass has a minimal
interface with two hooks: one to fill in the set of patterns, and another one
to convert types for functions and blocks. The patterns are defined as
separate classes that can be table-generated in the future.
The LLVM IR lowering pass partially inherits from the existing LLVM IR
translator, in particular for type conversion. It defines a conversion pattern
template, instantiated for different operations, and is a good candidate for
tablegen. The lowering does not yet support loads and stores and is not
connected to the translator as it would have broken the existing flows. Future
patches will add missing support before switching the translator in a single
patch.
PiperOrigin-RevId: 230951202
2019-01-25 12:46:53 -08:00
|
|
|
}
|
|
|
|
|
|
2019-05-22 11:49:04 -07:00
|
|
|
// Finally, update the signatures of all of the converted functions.
|
|
|
|
|
for (auto &it : toConvert) {
|
|
|
|
|
it.fn->setType(it.newType);
|
|
|
|
|
it.fn->setAllArgAttrs(it.newFunctionArgAttrs);
|
2019-05-19 17:56:32 -07:00
|
|
|
}
|
Generic dialect conversion pass exercised by LLVM IR lowering
This commit introduces a generic dialect conversion/lowering/legalization pass
and illustrates it on StandardOps->LLVMIR conversion.
It partially reuses the PatternRewriter infrastructure and adds the following
functionality:
- an actual pass;
- non-default pattern constructors;
- one-to-many rewrites;
- rewriting terminators with successors;
- not applying patterns iteratively (unlike the existing greedy rewrite driver);
- ability to change function signature;
- ability to change basic block argument types.
The latter two things required, given the existing API, to create new functions
in the same module. Eventually, this should converge with the rest of
PatternRewriter. However, we may want to keep two pass versions: "heavy" with
function/block argument conversion and "light" that only touches operations.
This pass creates new functions within a module as a means to change function
signature, then creates new blocks with converted argument types in the new
function. Then, it traverses the CFG in DFS-preorder to make sure defs are
converted before uses in the dominated blocks. The generic pass has a minimal
interface with two hooks: one to fill in the set of patterns, and another one
to convert types for functions and blocks. The patterns are defined as
separate classes that can be table-generated in the future.
The LLVM IR lowering pass partially inherits from the existing LLVM IR
translator, in particular for type conversion. It defines a conversion pattern
template, instantiated for different operations, and is a good candidate for
tablegen. The lowering does not yet support loads and stores and is not
connected to the translator as it would have broken the existing flows. Future
patches will add missing support before switching the translator in a single
patch.
PiperOrigin-RevId: 230951202
2019-01-25 12:46:53 -08:00
|
|
|
|
2019-03-10 15:32:54 -07:00
|
|
|
return success();
|
Generic dialect conversion pass exercised by LLVM IR lowering
This commit introduces a generic dialect conversion/lowering/legalization pass
and illustrates it on StandardOps->LLVMIR conversion.
It partially reuses the PatternRewriter infrastructure and adds the following
functionality:
- an actual pass;
- non-default pattern constructors;
- one-to-many rewrites;
- rewriting terminators with successors;
- not applying patterns iteratively (unlike the existing greedy rewrite driver);
- ability to change function signature;
- ability to change basic block argument types.
The latter two things required, given the existing API, to create new functions
in the same module. Eventually, this should converge with the rest of
PatternRewriter. However, we may want to keep two pass versions: "heavy" with
function/block argument conversion and "light" that only touches operations.
This pass creates new functions within a module as a means to change function
signature, then creates new blocks with converted argument types in the new
function. Then, it traverses the CFG in DFS-preorder to make sure defs are
converted before uses in the dominated blocks. The generic pass has a minimal
interface with two hooks: one to fill in the set of patterns, and another one
to convert types for functions and blocks. The patterns are defined as
separate classes that can be table-generated in the future.
The LLVM IR lowering pass partially inherits from the existing LLVM IR
translator, in particular for type conversion. It defines a conversion pattern
template, instantiated for different operations, and is a good candidate for
tablegen. The lowering does not yet support loads and stores and is not
connected to the translator as it would have broken the existing flows. Future
patches will add missing support before switching the translator in a single
patch.
PiperOrigin-RevId: 230951202
2019-01-25 12:46:53 -08:00
|
|
|
}
|
2019-05-23 09:23:33 -07:00
|
|
|
|
|
|
|
|
/// Convert the given function with the provided conversion patterns. This will
|
|
|
|
|
/// convert as many of the operations within 'fn' as possible given the set of
|
|
|
|
|
/// patterns.
|
|
|
|
|
LogicalResult
|
2019-06-03 12:49:55 -07:00
|
|
|
mlir::applyConversionPatterns(Function &fn, ConversionTarget &target,
|
2019-05-23 09:23:33 -07:00
|
|
|
OwningRewritePatternList &&patterns) {
|
|
|
|
|
// Convert the body of this function.
|
2019-06-03 12:49:55 -07:00
|
|
|
FunctionConverter converter(fn.getContext(), target, patterns);
|
2019-05-23 09:23:33 -07:00
|
|
|
return converter.convertFunction(&fn);
|
|
|
|
|
}
|