Files
clang-p2996/mlir/lib/Dialect/Func/Transforms/OneToNFuncConversions.cpp
Jacques Pienaar e67080df99 [mlir][ods] Populate properties in generated builder (#90430)
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.
2024-05-15 03:25:51 -07:00

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 = &region->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