[flang-commits] [flang] 6eb7634 - [fir] Add character conversion pass
Valentin Clement via flang-commits
flang-commits at lists.llvm.org
Sun Oct 10 11:20:18 PDT 2021
Author: Jean Perier
Date: 2021-10-10T20:20:09+02:00
New Revision: 6eb7634f301a0ef6465f514ae8cc4634602470a2
URL: https://github.com/llvm/llvm-project/commit/6eb7634f301a0ef6465f514ae8cc4634602470a2
DIFF: https://github.com/llvm/llvm-project/commit/6eb7634f301a0ef6465f514ae8cc4634602470a2.diff
LOG: [fir] Add character conversion pass
Upstream the character conversion pass.
Translates entities of one CHARACTER KIND to another.
By default the translation is to naively zero-extend or truncate a code
point to fit the destination size.
This patch is part of the upstreaming effort from fir-dev branch.
Co-authored-by: Eric Schweitz <eschweitz at nvidia.com>
Co-authored-by: Valentin Clement <clementval at gmail.com>
Reviewed By: schweitz
Differential Revision: https://reviews.llvm.org/D111405
Added:
flang/lib/Optimizer/Transforms/CharacterConversion.cpp
flang/test/Fir/char-conversion.fir
Modified:
flang/include/flang/Optimizer/Transforms/Passes.h
flang/include/flang/Optimizer/Transforms/Passes.td
flang/lib/Optimizer/Transforms/CMakeLists.txt
Removed:
################################################################################
diff --git a/flang/include/flang/Optimizer/Transforms/Passes.h b/flang/include/flang/Optimizer/Transforms/Passes.h
index f89e80c889e92..fc689b0372976 100644
--- a/flang/include/flang/Optimizer/Transforms/Passes.h
+++ b/flang/include/flang/Optimizer/Transforms/Passes.h
@@ -27,6 +27,7 @@ namespace fir {
//===----------------------------------------------------------------------===//
std::unique_ptr<mlir::Pass> createAffineDemotionPass();
+std::unique_ptr<mlir::Pass> createCharacterConversionPass();
std::unique_ptr<mlir::Pass> createExternalNameConversionPass();
std::unique_ptr<mlir::Pass> createPromoteToAffinePass();
diff --git a/flang/include/flang/Optimizer/Transforms/Passes.td b/flang/include/flang/Optimizer/Transforms/Passes.td
index 1929480dc5ecb..b207ad70ba9a1 100644
--- a/flang/include/flang/Optimizer/Transforms/Passes.td
+++ b/flang/include/flang/Optimizer/Transforms/Passes.td
@@ -55,6 +55,24 @@ def AffineDialectDemotion : FunctionPass<"demote-affine"> {
];
}
+def CharacterConversion : Pass<"character-conversion"> {
+ let summary = "Convert CHARACTER entities with
diff erent KINDs";
+ let description = [{
+ Translates entities of one CHARACTER KIND to another.
+
+ By default the translation is to naively zero-extend or truncate a code
+ point to fit the destination size.
+ }];
+ let constructor = "::fir::createCharacterConversionPass()";
+ let dependentDialects = [ "fir::FIROpsDialect" ];
+ let options = [
+ Option<"useRuntimeCalls", "use-runtime-calls",
+ "std::string", /*default=*/"std::string{}",
+ "Generate runtime calls to a named set of conversion routines. "
+ "By default, the conversions may produce unexpected results.">
+ ];
+}
+
def ExternalNameConversion : Pass<"external-name-interop", "mlir::ModuleOp"> {
let summary = "Convert name for external interoperability";
let description = [{
diff --git a/flang/lib/Optimizer/Transforms/CMakeLists.txt b/flang/lib/Optimizer/Transforms/CMakeLists.txt
index dbb0d46aa95d1..6465ba8c5599f 100644
--- a/flang/lib/Optimizer/Transforms/CMakeLists.txt
+++ b/flang/lib/Optimizer/Transforms/CMakeLists.txt
@@ -1,6 +1,7 @@
add_flang_library(FIRTransforms
AffinePromotion.cpp
AffineDemotion.cpp
+ CharacterConversion.cpp
Inliner.cpp
ExternalNameConversion.cpp
diff --git a/flang/lib/Optimizer/Transforms/CharacterConversion.cpp b/flang/lib/Optimizer/Transforms/CharacterConversion.cpp
new file mode 100644
index 0000000000000..90c519396b615
--- /dev/null
+++ b/flang/lib/Optimizer/Transforms/CharacterConversion.cpp
@@ -0,0 +1,128 @@
+//===- CharacterConversion.cpp -- convert between character encodings -----===//
+//
+// Part of the LLVM Project, 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "PassDetail.h"
+#include "flang/Optimizer/Dialect/FIRDialect.h"
+#include "flang/Optimizer/Dialect/FIROps.h"
+#include "flang/Optimizer/Dialect/FIRType.h"
+#include "flang/Optimizer/Support/FIRContext.h"
+#include "flang/Optimizer/Support/KindMapping.h"
+#include "flang/Optimizer/Transforms/Passes.h"
+#include "mlir/Dialect/StandardOps/IR/Ops.h"
+#include "mlir/IR/Diagnostics.h"
+#include "mlir/Pass/Pass.h"
+#include "mlir/Transforms/DialectConversion.h"
+#include "llvm/Support/Debug.h"
+
+#define DEBUG_TYPE "flang-character-conversion"
+
+namespace {
+
+// TODO: Future hook to select some set of runtime calls.
+struct CharacterConversionOptions {
+ std::string runtimeName;
+};
+
+class CharacterConvertConversion
+ : public mlir::OpRewritePattern<fir::CharConvertOp> {
+public:
+ using OpRewritePattern::OpRewritePattern;
+
+ mlir::LogicalResult
+ matchAndRewrite(fir::CharConvertOp conv,
+ mlir::PatternRewriter &rewriter) const override {
+ auto kindMap = fir::getKindMapping(conv->getParentOfType<mlir::ModuleOp>());
+ auto loc = conv.getLoc();
+
+ LLVM_DEBUG(llvm::dbgs()
+ << "running character conversion on " << conv << '\n');
+
+ // Establish a loop that executes count iterations.
+ auto zero = rewriter.create<mlir::ConstantIndexOp>(loc, 0);
+ auto one = rewriter.create<mlir::ConstantIndexOp>(loc, 1);
+ auto idxTy = rewriter.getIndexType();
+ auto castCnt = rewriter.create<fir::ConvertOp>(loc, idxTy, conv.count());
+ auto countm1 = rewriter.create<mlir::SubIOp>(loc, castCnt, one);
+ auto loop = rewriter.create<fir::DoLoopOp>(loc, zero, countm1, one);
+ auto insPt = rewriter.saveInsertionPoint();
+ rewriter.setInsertionPointToStart(loop.getBody());
+
+ // For each code point in the `from` string, convert naively to the `to`
+ // string code point. Conversion is done blindly on size only, not value.
+ auto getCharBits = [&](mlir::Type t) {
+ auto chrTy = fir::unwrapSequenceType(fir::dyn_cast_ptrEleTy(t))
+ .cast<fir::CharacterType>();
+ return kindMap.getCharacterBitsize(chrTy.getFKind());
+ };
+ auto fromBits = getCharBits(conv.from().getType());
+ auto toBits = getCharBits(conv.to().getType());
+ auto pointerType = [&](unsigned bits) {
+ return fir::ReferenceType::get(fir::SequenceType::get(
+ fir::SequenceType::ShapeRef{fir::SequenceType::getUnknownExtent()},
+ rewriter.getIntegerType(bits)));
+ };
+ auto fromPtrTy = pointerType(fromBits);
+ auto toTy = rewriter.getIntegerType(toBits);
+ auto toPtrTy = pointerType(toBits);
+ auto fromPtr = rewriter.create<fir::ConvertOp>(loc, fromPtrTy, conv.from());
+ auto toPtr = rewriter.create<fir::ConvertOp>(loc, toPtrTy, conv.to());
+ auto getEleTy = [&](unsigned bits) {
+ return fir::ReferenceType::get(rewriter.getIntegerType(bits));
+ };
+ auto fromi = rewriter.create<fir::CoordinateOp>(
+ loc, getEleTy(fromBits), fromPtr,
+ mlir::ValueRange{loop.getInductionVar()});
+ auto toi = rewriter.create<fir::CoordinateOp>(
+ loc, getEleTy(toBits), toPtr, mlir::ValueRange{loop.getInductionVar()});
+ auto load = rewriter.create<fir::LoadOp>(loc, fromi);
+ mlir::Value icast =
+ (fromBits >= toBits)
+ ? rewriter.create<fir::ConvertOp>(loc, toTy, load).getResult()
+ : rewriter.create<mlir::ZeroExtendIOp>(loc, toTy, load).getResult();
+ rewriter.replaceOpWithNewOp<fir::StoreOp>(conv, icast, toi);
+ rewriter.restoreInsertionPoint(insPt);
+ return mlir::success();
+ }
+};
+
+/// Rewrite the `fir.char_convert` op into a loop. This pass must be run only on
+/// fir::CharConvertOp.
+class CharacterConversion
+ : public fir::CharacterConversionBase<CharacterConversion> {
+public:
+ void runOnOperation() override {
+ CharacterConversionOptions clOpts{useRuntimeCalls.getValue()};
+ if (clOpts.runtimeName.empty()) {
+ auto *context = &getContext();
+ auto *func = getOperation();
+ mlir::OwningRewritePatternList patterns(context);
+ patterns.insert<CharacterConvertConversion>(context);
+ mlir::ConversionTarget target(*context);
+ target.addLegalDialect<mlir::AffineDialect, fir::FIROpsDialect,
+ mlir::StandardOpsDialect>();
+
+ // apply the patterns
+ target.addIllegalOp<fir::CharConvertOp>();
+ if (mlir::failed(mlir::applyPartialConversion(func, target,
+ std::move(patterns)))) {
+ mlir::emitError(mlir::UnknownLoc::get(context),
+ "error in rewriting character convert op");
+ signalPassFailure();
+ }
+ return;
+ }
+
+ // TODO: some sort of runtime supported conversion?
+ signalPassFailure();
+ }
+};
+} // end anonymous namespace
+
+std::unique_ptr<mlir::Pass> fir::createCharacterConversionPass() {
+ return std::make_unique<CharacterConversion>();
+}
diff --git a/flang/test/Fir/char-conversion.fir b/flang/test/Fir/char-conversion.fir
new file mode 100644
index 0000000000000..e47096d5c419f
--- /dev/null
+++ b/flang/test/Fir/char-conversion.fir
@@ -0,0 +1,29 @@
+// RUN: fir-opt --character-conversion %s | FileCheck %s
+
+func @char_convert() {
+ %1 = fir.undefined i32
+ %2 = fir.undefined !fir.ref<!fir.char<1>>
+ %3 = fir.undefined !fir.ref<!fir.array<?x!fir.char<2,?>>>
+ fir.char_convert %2 for %1 to %3 : !fir.ref<!fir.char<1>>, i32, !fir.ref<!fir.array<?x!fir.char<2,?>>>
+ return
+}
+
+// CHECK-LABEL: func @char_convert() {
+// CHECK: %[[VAL_0:.*]] = fir.undefined i32
+// CHECK: %[[VAL_1:.*]] = fir.undefined !fir.ref<!fir.char<1>>
+// CHECK: %[[VAL_2:.*]] = fir.undefined !fir.ref<!fir.array<?x!fir.char<2,?>>>
+// CHECK: %[[VAL_3:.*]] = constant 0 : index
+// CHECK: %[[VAL_4:.*]] = constant 1 : index
+// CHECK: %[[VAL_5:.*]] = fir.convert %[[VAL_0]] : (i32) -> index
+// CHECK: %[[VAL_6:.*]] = subi %[[VAL_5]], %[[VAL_4]] : index
+// CHECK: fir.do_loop %[[VAL_7:.*]] = %[[VAL_3]] to %[[VAL_6]] step %[[VAL_4]] {
+// CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<!fir.char<1>>) -> !fir.ref<!fir.array<?xi8>>
+// CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.array<?x!fir.char<2,?>>>) -> !fir.ref<!fir.array<?xi16>>
+// CHECK: %[[VAL_10:.*]] = fir.coordinate_of %[[VAL_8]], %[[VAL_7]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+// CHECK: %[[VAL_11:.*]] = fir.coordinate_of %[[VAL_9]], %[[VAL_7]] : (!fir.ref<!fir.array<?xi16>>, index) -> !fir.ref<i16>
+// CHECK: %[[VAL_12:.*]] = fir.load %[[VAL_10]] : !fir.ref<i8>
+// CHECK: %[[VAL_13:.*]] = zexti %[[VAL_12]] : i8 to i16
+// CHECK: fir.store %[[VAL_13]] to %[[VAL_11]] : !fir.ref<i16>
+// CHECK: }
+// CHECK: return
+// CHECK: }
More information about the flang-commits
mailing list