[flang-commits] [flang] 8aa86ac - [flang] Add hlfir.set_length operation
Jean Perier via flang-commits
flang-commits at lists.llvm.org
Mon Dec 19 00:51:18 PST 2022
Author: Jean Perier
Date: 2022-12-19T09:50:46+01:00
New Revision: 8aa86ac3c4bfb71abfa85e2ee9b1aea1e20e9582
URL: https://github.com/llvm/llvm-project/commit/8aa86ac3c4bfb71abfa85e2ee9b1aea1e20e9582
DIFF: https://github.com/llvm/llvm-project/commit/8aa86ac3c4bfb71abfa85e2ee9b1aea1e20e9582.diff
LOG: [flang] Add hlfir.set_length operation
This will implement evaluate::SetLength where the length of
a character entity is changed (with trimming and padding).
Differential Revision: https://reviews.llvm.org/D140219
Added:
flang/test/HLFIR/set_length-codegen.fir
flang/test/HLFIR/set_length.fir
Modified:
flang/include/flang/Optimizer/HLFIR/HLFIROps.td
flang/lib/Optimizer/Builder/HLFIRTools.cpp
flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp
Removed:
################################################################################
diff --git a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
index 7df8d3db74961..b5e2a4493dcbf 100644
--- a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
+++ b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
@@ -236,6 +236,26 @@ def hlfir_ConcatOp : hlfir_Op<"concat", []> {
let hasVerifier = 1;
}
+def hlfir_SetLengthOp : hlfir_Op<"set_length", []> {
+ let summary = "change the length of a character entity";
+ let description = [{
+ Change the length of character entity. This trims or pads the
+ character argument according to the new length.
+ }];
+
+ let arguments = (ins AnyScalarCharacterEntity:$string,
+ AnyIntegerType:$length);
+
+ let results = (outs AnyScalarCharacterExpr);
+
+ let assemblyFormat = [{
+ $string `len` $length
+ attr-dict `:` functional-type(operands, results)
+ }];
+
+ let builders = [OpBuilder<(ins "mlir::Value":$string,"mlir::Value":$len)>];
+}
+
def hlfir_AssociateOp : hlfir_Op<"associate", [AttrSizedOperandSegments,
DeclareOpInterfaceMethods<fir_FortranVariableOpInterface>]> {
let summary = "Create a variable from an expression value";
diff --git a/flang/lib/Optimizer/Builder/HLFIRTools.cpp b/flang/lib/Optimizer/Builder/HLFIRTools.cpp
index 6903140c3331a..b090da69135c1 100644
--- a/flang/lib/Optimizer/Builder/HLFIRTools.cpp
+++ b/flang/lib/Optimizer/Builder/HLFIRTools.cpp
@@ -431,6 +431,9 @@ void hlfir::genLengthParameters(mlir::Location loc, fir::FirOpBuilder &builder,
if (auto concat = expr.getDefiningOp<hlfir::ConcatOp>()) {
result.push_back(concat.getLength());
return;
+ } else if (auto concat = expr.getDefiningOp<hlfir::SetLengthOp>()) {
+ result.push_back(concat.getLength());
+ return;
} else if (auto asExpr = expr.getDefiningOp<hlfir::AsExprOp>()) {
hlfir::genLengthParameters(loc, builder, hlfir::Entity{asExpr.getVar()},
result);
diff --git a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
index 95c4a5306d47c..654414ac8603f 100644
--- a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
+++ b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include "flang/Optimizer/HLFIR/HLFIROps.h"
+#include "flang/Optimizer/Dialect/FIROpsSupport.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/DialectImplementation.h"
@@ -400,6 +401,24 @@ void hlfir::ConcatOp::build(mlir::OpBuilder &builder,
build(builder, result, resultType, strings, len);
}
+//===----------------------------------------------------------------------===//
+// SetLengthOp
+//===----------------------------------------------------------------------===//
+
+void hlfir::SetLengthOp::build(mlir::OpBuilder &builder,
+ mlir::OperationState &result, mlir::Value string,
+ mlir::Value len) {
+ fir::CharacterType::LenType resultTypeLen = fir::CharacterType::unknownLen();
+ if (auto cstLen = fir::getIntIfConstant(len))
+ resultTypeLen = *cstLen;
+ unsigned kind = getCharacterKind(string.getType());
+ auto resultType = hlfir::ExprType::get(
+ builder.getContext(), hlfir::ExprType::Shape{},
+ fir::CharacterType::get(builder.getContext(), kind, resultTypeLen),
+ false);
+ build(builder, result, resultType, string, len);
+}
+
//===----------------------------------------------------------------------===//
// AssociateOp
//===----------------------------------------------------------------------===//
diff --git a/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp b/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp
index 491d75fe4eb1e..90951f8ed32c3 100644
--- a/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp
+++ b/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp
@@ -228,6 +228,36 @@ struct ConcatOpConversion : public mlir::OpConversionPattern<hlfir::ConcatOp> {
}
};
+struct SetLengthOpConversion
+ : public mlir::OpConversionPattern<hlfir::SetLengthOp> {
+ using mlir::OpConversionPattern<hlfir::SetLengthOp>::OpConversionPattern;
+ explicit SetLengthOpConversion(mlir::MLIRContext *ctx)
+ : mlir::OpConversionPattern<hlfir::SetLengthOp>{ctx} {}
+ mlir::LogicalResult
+ matchAndRewrite(hlfir::SetLengthOp setLength, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const override {
+ mlir::Location loc = setLength->getLoc();
+ auto module = setLength->getParentOfType<mlir::ModuleOp>();
+ fir::FirOpBuilder builder(rewriter, fir::getKindMapping(module));
+ // Create a temp with the new length.
+ hlfir::Entity string{getBufferizedExprStorage(adaptor.getString())};
+ auto charType = hlfir::getFortranElementType(setLength.getType());
+ llvm::StringRef tmpName{".tmp"};
+ llvm::SmallVector<mlir::Value, 1> lenParams{adaptor.getLength()};
+ auto alloca = builder.createTemporary(loc, charType, tmpName,
+ /*shape=*/std::nullopt, lenParams);
+ auto declareOp = builder.create<hlfir::DeclareOp>(
+ loc, alloca, tmpName, /*shape=*/mlir::Value{}, lenParams,
+ fir::FortranVariableFlagsAttr{});
+ // Assign string value to the created temp.
+ builder.create<hlfir::AssignOp>(loc, string, declareOp.getBase());
+ mlir::Value bufferizedExpr =
+ packageBufferizedExpr(loc, builder, alloca, false);
+ rewriter.replaceOp(setLength, bufferizedExpr);
+ return mlir::success();
+ }
+};
+
struct AssociateOpConversion
: public mlir::OpConversionPattern<hlfir::AssociateOp> {
using mlir::OpConversionPattern<hlfir::AssociateOp>::OpConversionPattern;
@@ -401,10 +431,11 @@ class BufferizeHLFIR : public hlfir::impl::BufferizeHLFIRBase<BufferizeHLFIR> {
patterns.insert<ApplyOpConversion, AsExprOpConversion, AssignOpConversion,
AssociateOpConversion, ConcatOpConversion,
ElementalOpConversion, EndAssociateOpConversion,
- NoReassocOpConversion>(context);
+ NoReassocOpConversion, SetLengthOpConversion>(context);
mlir::ConversionTarget target(*context);
target.addIllegalOp<hlfir::ApplyOp, hlfir::AssociateOp, hlfir::ElementalOp,
- hlfir::EndAssociateOp, hlfir::YieldElementOp>();
+ hlfir::EndAssociateOp, hlfir::SetLengthOp,
+ hlfir::YieldElementOp>();
target.markUnknownOpDynamicallyLegal([](mlir::Operation *op) {
return llvm::all_of(
op->getResultTypes(),
diff --git a/flang/test/HLFIR/set_length-codegen.fir b/flang/test/HLFIR/set_length-codegen.fir
new file mode 100644
index 0000000000000..a54cfc00ffe17
--- /dev/null
+++ b/flang/test/HLFIR/set_length-codegen.fir
@@ -0,0 +1,33 @@
+// Test hlfir.set_length operation lowering to operations operating on memory.
+// RUN: fir-opt %s -bufferize-hlfir | FileCheck %s
+
+func.func @test_cst_len(%str : !fir.boxchar<1>) {
+ %c10 = arith.constant 10 : index
+ %0 = hlfir.set_length %str len %c10 : (!fir.boxchar<1>, index) -> !hlfir.expr<!fir.char<1,10>>
+ return
+}
+// CHECK-LABEL: func.func @test_cst_len(
+// CHECK-SAME: %[[VAL_0:.*]]: !fir.boxchar<1>) {
+// CHECK: %[[VAL_1:.*]] = fir.alloca !fir.char<1,10> {bindc_name = ".tmp"}
+// CHECK: %[[VAL_2:.*]] = arith.constant 10 : index
+// CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_1]] typeparams %[[VAL_2]] {uniq_name = ".tmp"} : (!fir.ref<!fir.char<1,10>>, index) -> (!fir.ref<!fir.char<1,10>>, !fir.ref<!fir.char<1,10>>)
+// CHECK: hlfir.assign %[[VAL_0]] to %[[VAL_3]]#0 : !fir.boxchar<1>, !fir.ref<!fir.char<1,10>>
+// CHECK: %[[VAL_4:.*]] = arith.constant false
+// CHECK: %[[VAL_5:.*]] = fir.undefined tuple<!fir.ref<!fir.char<1,10>>, i1>
+// CHECK: %[[VAL_6:.*]] = fir.insert_value %[[VAL_5]], %[[VAL_4]], [1 : index] : (tuple<!fir.ref<!fir.char<1,10>>, i1>, i1) -> tuple<!fir.ref<!fir.char<1,10>>, i1>
+// CHECK: %[[VAL_7:.*]] = fir.insert_value %[[VAL_6]], %[[VAL_1]], [0 : index] : (tuple<!fir.ref<!fir.char<1,10>>, i1>, !fir.ref<!fir.char<1,10>>) -> tuple<!fir.ref<!fir.char<1,10>>, i1>
+
+func.func @test_dyn_len(%str : !fir.ref<!fir.char<1,10>>, %len : index) {
+ %0 = hlfir.set_length %str len %len : (!fir.ref<!fir.char<1,10>>, index) -> !hlfir.expr<!fir.char<1,?>>
+ return
+}
+// CHECK-LABEL: func.func @test_dyn_len(
+// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.char<1,10>>,
+// CHECK-SAME: %[[VAL_1:.*]]: index) {
+// CHECK: %[[VAL_2:.*]] = fir.alloca !fir.char<1,?>(%[[VAL_1]] : index) {bindc_name = ".tmp"}
+// CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] typeparams %[[VAL_1]] {uniq_name = ".tmp"} : (!fir.ref<!fir.char<1,?>>, index) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>)
+// CHECK: hlfir.assign %[[VAL_0]] to %[[VAL_3]]#0 : !fir.ref<!fir.char<1,10>>, !fir.boxchar<1>
+// CHECK: %[[VAL_4:.*]] = arith.constant false
+// CHECK: %[[VAL_5:.*]] = fir.undefined tuple<!fir.ref<!fir.char<1,?>>, i1>
+// CHECK: %[[VAL_6:.*]] = fir.insert_value %[[VAL_5]], %[[VAL_4]], [1 : index] : (tuple<!fir.ref<!fir.char<1,?>>, i1>, i1) -> tuple<!fir.ref<!fir.char<1,?>>, i1>
+// CHECK: %[[VAL_7:.*]] = fir.insert_value %[[VAL_6]], %[[VAL_2]], [0 : index] : (tuple<!fir.ref<!fir.char<1,?>>, i1>, !fir.ref<!fir.char<1,?>>) -> tuple<!fir.ref<!fir.char<1,?>>, i1>
diff --git a/flang/test/HLFIR/set_length.fir b/flang/test/HLFIR/set_length.fir
new file mode 100644
index 0000000000000..099a807f25166
--- /dev/null
+++ b/flang/test/HLFIR/set_length.fir
@@ -0,0 +1,30 @@
+// Test hlfir.set_length operation parse, verify (no errors), and unparse.
+// RUN: fir-opt %s | fir-opt | FileCheck %s
+
+func.func @test_cst_len(%str : !fir.boxchar<1>) {
+ %c10 = arith.constant 10 : index
+ %0 = hlfir.set_length %str len %c10 : (!fir.boxchar<1>, index) -> !hlfir.expr<!fir.char<1,10>>
+ return
+}
+// CHECK-LABEL: func.func @test_cst_len(
+// CHECK-SAME: %[[VAL_0:.*]]: !fir.boxchar<1>) {
+// CHECK: %[[VAL_1:.*]] = arith.constant 10 : index
+// CHECK: %[[VAL_2:.*]] = hlfir.set_length %[[VAL_0]] len %[[VAL_1]] : (!fir.boxchar<1>, index) -> !hlfir.expr<!fir.char<1,10>>
+
+func.func @test_dyn_len(%str : !fir.ref<!fir.char<1,10>>, %len : index) {
+ %0 = hlfir.set_length %str len %len : (!fir.ref<!fir.char<1,10>>, index) -> !hlfir.expr<!fir.char<1,?>>
+ return
+}
+// CHECK-LABEL: func.func @test_dyn_len(
+// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.char<1,10>>,
+// CHECK-SAME: %[[VAL_1:.*]]: index) {
+// CHECK: %[[VAL_2:.*]] = hlfir.set_length %[[VAL_0]] len %[[VAL_1]] : (!fir.ref<!fir.char<1,10>>, index) -> !hlfir.expr<!fir.char<1,?>>
+
+func.func @test_from_expr(%str : !hlfir.expr<!fir.char<1,?>>, %len : index) {
+ %0 = hlfir.set_length %str len %len : (!hlfir.expr<!fir.char<1,?>>, index) -> !hlfir.expr<!fir.char<1,?>>
+ return
+}
+// CHECK-LABEL: func.func @test_from_expr(
+// CHECK-SAME: %[[VAL_0:.*]]: !hlfir.expr<!fir.char<1,?>>,
+// CHECK-SAME: %[[VAL_1:.*]]: index) {
+// CHECK: %[[VAL_2:.*]] = hlfir.set_length %[[VAL_0]] len %[[VAL_1]] : (!hlfir.expr<!fir.char<1,?>>, index) -> !hlfir.expr<!fir.char<1,?>>
More information about the flang-commits
mailing list