Previously this was only populated in the create method later. This resolves some of invalid builder paths. This may also be sufficient that type inference functions no longer have to consider whether property conversion has happened (but haven't verified that yet). This also makes Attributes corresponding to Properties as optional inside the set from attributes method. Today that is in effect what happens with Property value initialization and folks use it to define custom C++ types whose default initialization is what they want. This is the behavior users get if they use properties directly. Propagating Attributes without allowing partial setting would require iterating over the dictionary attribute considering the properties of the op type that will be created. This could also have been an additional method generated or optional behavior on the set method. But doing it consistently seems better. In terms of whats lost, it doesn't seem like anything compared to the pure Property path where Property is default value initialized and then partially overwritten (this doesn't seem to buy anything else verification wise). Default valued Properties (as specified ODS side rather than C++ side) triggered error as the containing class was not yet complete but referenced nested class, so that we couldn't have default initializer for them in the parent class. Added an additional forwarding builder to avoid needing to update call sites. This could be split out to separate change. Inlined templated function in unit test that was only used once. Moved initialization earlier where seen.
131 lines
4.5 KiB
C++
131 lines
4.5 KiB
C++
//===-- OneToNTypeFuncConversions.cpp - Func 1:N type conversion-*- C++ -*-===//
|
|
//
|
|
// Licensed 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// The patterns in this file are heavily inspired (and copied from)
|
|
// convertFuncOpTypes in lib/Transforms/Utils/DialectConversion.cpp and the
|
|
// patterns in lib/Dialect/Func/Transforms/FuncConversions.cpp but work for 1:N
|
|
// type conversions.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "mlir/Dialect/Func/Transforms/OneToNFuncConversions.h"
|
|
|
|
#include "mlir/Dialect/Func/IR/FuncOps.h"
|
|
#include "mlir/Transforms/OneToNTypeConversion.h"
|
|
|
|
using namespace mlir;
|
|
using namespace mlir::func;
|
|
|
|
namespace {
|
|
|
|
class ConvertTypesInFuncCallOp : public OneToNOpConversionPattern<CallOp> {
|
|
public:
|
|
using OneToNOpConversionPattern<CallOp>::OneToNOpConversionPattern;
|
|
|
|
LogicalResult
|
|
matchAndRewrite(CallOp op, OpAdaptor adaptor,
|
|
OneToNPatternRewriter &rewriter) const override {
|
|
Location loc = op->getLoc();
|
|
const OneToNTypeMapping &resultMapping = adaptor.getResultMapping();
|
|
|
|
// Nothing to do if the op doesn't have any non-identity conversions for its
|
|
// operands or results.
|
|
if (!adaptor.getOperandMapping().hasNonIdentityConversion() &&
|
|
!resultMapping.hasNonIdentityConversion())
|
|
return failure();
|
|
|
|
// Create new CallOp.
|
|
auto newOp =
|
|
rewriter.create<CallOp>(loc, resultMapping.getConvertedTypes(),
|
|
adaptor.getFlatOperands(), op->getAttrs());
|
|
|
|
rewriter.replaceOp(op, newOp->getResults(), resultMapping);
|
|
return success();
|
|
}
|
|
};
|
|
|
|
class ConvertTypesInFuncFuncOp : public OneToNOpConversionPattern<FuncOp> {
|
|
public:
|
|
using OneToNOpConversionPattern<FuncOp>::OneToNOpConversionPattern;
|
|
|
|
LogicalResult
|
|
matchAndRewrite(FuncOp op, OpAdaptor adaptor,
|
|
OneToNPatternRewriter &rewriter) const override {
|
|
auto *typeConverter = getTypeConverter<OneToNTypeConverter>();
|
|
|
|
// Construct mapping for function arguments.
|
|
OneToNTypeMapping argumentMapping(op.getArgumentTypes());
|
|
if (failed(typeConverter->computeTypeMapping(op.getArgumentTypes(),
|
|
argumentMapping)))
|
|
return failure();
|
|
|
|
// Construct mapping for function results.
|
|
OneToNTypeMapping funcResultMapping(op.getResultTypes());
|
|
if (failed(typeConverter->computeTypeMapping(op.getResultTypes(),
|
|
funcResultMapping)))
|
|
return failure();
|
|
|
|
// Nothing to do if the op doesn't have any non-identity conversions for its
|
|
// operands or results.
|
|
if (!argumentMapping.hasNonIdentityConversion() &&
|
|
!funcResultMapping.hasNonIdentityConversion())
|
|
return failure();
|
|
|
|
// Update the function signature in-place.
|
|
auto newType = FunctionType::get(rewriter.getContext(),
|
|
argumentMapping.getConvertedTypes(),
|
|
funcResultMapping.getConvertedTypes());
|
|
rewriter.modifyOpInPlace(op, [&] { op.setType(newType); });
|
|
|
|
// Update block signatures.
|
|
if (!op.isExternal()) {
|
|
Region *region = &op.getBody();
|
|
Block *block = ®ion->front();
|
|
rewriter.applySignatureConversion(block, argumentMapping);
|
|
}
|
|
|
|
return success();
|
|
}
|
|
};
|
|
|
|
class ConvertTypesInFuncReturnOp : public OneToNOpConversionPattern<ReturnOp> {
|
|
public:
|
|
using OneToNOpConversionPattern<ReturnOp>::OneToNOpConversionPattern;
|
|
|
|
LogicalResult
|
|
matchAndRewrite(ReturnOp op, OpAdaptor adaptor,
|
|
OneToNPatternRewriter &rewriter) const override {
|
|
// Nothing to do if there is no non-identity conversion.
|
|
if (!adaptor.getOperandMapping().hasNonIdentityConversion())
|
|
return failure();
|
|
|
|
// Convert operands.
|
|
rewriter.modifyOpInPlace(
|
|
op, [&] { op->setOperands(adaptor.getFlatOperands()); });
|
|
|
|
return success();
|
|
}
|
|
};
|
|
|
|
} // namespace
|
|
|
|
namespace mlir {
|
|
|
|
void populateFuncTypeConversionPatterns(TypeConverter &typeConverter,
|
|
RewritePatternSet &patterns) {
|
|
patterns.add<
|
|
// clang-format off
|
|
ConvertTypesInFuncCallOp,
|
|
ConvertTypesInFuncFuncOp,
|
|
ConvertTypesInFuncReturnOp
|
|
// clang-format on
|
|
>(typeConverter, patterns.getContext());
|
|
}
|
|
|
|
} // namespace mlir
|