[fir] Add fir.insert_on_range conversion

Convert fir.insert_on_range operation to corresponding
llvm.insertvalue operations.

This patch is part of the upstreaming effort from fir-dev branch.

Reviewed By: mehdi_amini

Differential Revision: https://reviews.llvm.org/D112896
This commit is contained in:
Valentin Clement 2021-11-04 10:36:00 +01:00
parent 1e5f814302
commit 3ae8e44215
No known key found for this signature in database
GPG Key ID: 086D54783C928776
2 changed files with 121 additions and 4 deletions

View File

@ -19,6 +19,7 @@
#include "mlir/Conversion/LLVMCommon/TypeConverter.h"
#include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVM.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/Matchers.h"
#include "mlir/Pass/Pass.h"
#include "llvm/ADT/ArrayRef.h"
@ -45,6 +46,25 @@ protected:
}
};
/// FIR conversion pattern template
template <typename FromOp>
class FIROpAndTypeConversion : public FIROpConversion<FromOp> {
public:
using FIROpConversion<FromOp>::FIROpConversion;
using OpAdaptor = typename FromOp::Adaptor;
mlir::LogicalResult
matchAndRewrite(FromOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const final {
mlir::Type ty = this->convertType(op.getType());
return doRewrite(op, ty, adaptor, rewriter);
}
virtual mlir::LogicalResult
doRewrite(FromOp addr, mlir::Type ty, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const = 0;
};
// Lower `fir.address_of` operation to `llvm.address_of` operation.
struct AddrOfOpConversion : public FIROpConversion<fir::AddrOfOp> {
using FIROpConversion::FIROpConversion;
@ -204,6 +224,82 @@ struct ZeroOpConversion : public FIROpConversion<fir::ZeroOp> {
}
};
/// InsertOnRange inserts a value into a sequence over a range of offsets.
struct InsertOnRangeOpConversion
: public FIROpAndTypeConversion<fir::InsertOnRangeOp> {
using FIROpAndTypeConversion::FIROpAndTypeConversion;
// Increments an array of subscripts in a row major fasion.
void incrementSubscripts(const SmallVector<uint64_t> &dims,
SmallVector<uint64_t> &subscripts) const {
for (size_t i = dims.size(); i > 0; --i) {
if (++subscripts[i - 1] < dims[i - 1]) {
return;
}
subscripts[i - 1] = 0;
}
}
mlir::LogicalResult
doRewrite(fir::InsertOnRangeOp range, mlir::Type ty, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const override {
llvm::SmallVector<uint64_t> dims;
auto type = adaptor.getOperands()[0].getType();
// Iteratively extract the array dimensions from the type.
while (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
dims.push_back(t.getNumElements());
type = t.getElementType();
}
SmallVector<uint64_t> lBounds;
SmallVector<uint64_t> uBounds;
// Extract integer value from the attribute
SmallVector<int64_t> coordinates = llvm::to_vector<4>(
llvm::map_range(range.coor(), [](Attribute a) -> int64_t {
return a.cast<IntegerAttr>().getInt();
}));
// Unzip the upper and lower bound and convert to a row major format.
for (auto i = coordinates.rbegin(), e = coordinates.rend(); i != e; ++i) {
uBounds.push_back(*i++);
lBounds.push_back(*i);
}
auto &subscripts = lBounds;
auto loc = range.getLoc();
mlir::Value lastOp = adaptor.getOperands()[0];
mlir::Value insertVal = adaptor.getOperands()[1];
auto i64Ty = rewriter.getI64Type();
while (subscripts != uBounds) {
// Convert uint64_t's to Attribute's.
SmallVector<mlir::Attribute> subscriptAttrs;
for (const auto &subscript : subscripts)
subscriptAttrs.push_back(IntegerAttr::get(i64Ty, subscript));
lastOp = rewriter.create<mlir::LLVM::InsertValueOp>(
loc, ty, lastOp, insertVal,
ArrayAttr::get(range.getContext(), subscriptAttrs));
incrementSubscripts(dims, subscripts);
}
// Convert uint64_t's to Attribute's.
SmallVector<mlir::Attribute> subscriptAttrs;
for (const auto &subscript : subscripts)
subscriptAttrs.push_back(
IntegerAttr::get(rewriter.getI64Type(), subscript));
mlir::ArrayRef<mlir::Attribute> arrayRef(subscriptAttrs);
rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
range, ty, lastOp, insertVal,
ArrayAttr::get(range.getContext(), arrayRef));
return success();
}
};
} // namespace
namespace {
@ -221,10 +317,9 @@ public:
auto *context = getModule().getContext();
fir::LLVMTypeConverter typeConverter{getModule()};
mlir::OwningRewritePatternList pattern(context);
pattern
.insert<AddrOfOpConversion, HasValueOpConversion, GlobalOpConversion,
UndefOpConversion, UnreachableOpConversion, ZeroOpConversion>(
typeConverter);
pattern.insert<AddrOfOpConversion, HasValueOpConversion, GlobalOpConversion,
InsertOnRangeOpConversion, UndefOpConversion,
UnreachableOpConversion, ZeroOpConversion>(typeConverter);
mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern);
mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter,
pattern);

View File

@ -84,6 +84,28 @@ fir.global internal @_QEmultiarray : !fir.array<32x32xi32> {
// -----
// Test global with insert_on_range operation not covering the full array
// in initializer region.
fir.global internal @_QEmultiarray : !fir.array<32xi32> {
%c0_i32 = arith.constant 1 : i32
%0 = fir.undefined !fir.array<32xi32>
%2 = fir.insert_on_range %0, %c0_i32, [5 : index, 31 : index] : (!fir.array<32xi32>, i32) -> !fir.array<32xi32>
fir.has_value %2 : !fir.array<32xi32>
}
// CHECK: llvm.mlir.global internal @_QEmultiarray() : !llvm.array<32 x i32> {
// CHECK: %[[CST:.*]] = llvm.mlir.constant(1 : i32) : i32
// CHECK: %{{.*}} = llvm.mlir.undef : !llvm.array<32 x i32>
// CHECK: %{{.*}} = llvm.insertvalue %[[CST]], %{{.*}}[5] : !llvm.array<32 x i32>
// CHECK-COUNT-24: %{{.*}} = llvm.insertvalue %[[CST]], %{{.*}}[{{.*}}] : !llvm.array<32 x i32>
// CHECK: %{{.*}} = llvm.insertvalue %[[CST]], %{{.*}}[31] : !llvm.array<32 x i32>
// CHECK-NOT: llvm.insertvalue
// CHECK: llvm.return %{{.*}} : !llvm.array<32 x i32>
// CHECK: }
// -----
// Test fir.zero_bits operation with LLVM ptr type
func @zero_test_ptr() {