[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