xref: /llvm-project/flang/lib/Optimizer/Transforms/CharacterConversion.cpp (revision db791b278a414fb6df1acc1799adcf11d8fb9169)
1 //===- CharacterConversion.cpp -- convert between character encodings -----===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "flang/Optimizer/Dialect/FIRDialect.h"
10 #include "flang/Optimizer/Dialect/FIROps.h"
11 #include "flang/Optimizer/Dialect/FIRType.h"
12 #include "flang/Optimizer/Dialect/Support/FIRContext.h"
13 #include "flang/Optimizer/Dialect/Support/KindMapping.h"
14 #include "flang/Optimizer/Transforms/Passes.h"
15 #include "mlir/Dialect/Affine/IR/AffineOps.h"
16 #include "mlir/Dialect/Func/IR/FuncOps.h"
17 #include "mlir/IR/Diagnostics.h"
18 #include "mlir/Pass/Pass.h"
19 #include "mlir/Transforms/DialectConversion.h"
20 #include "llvm/Support/Debug.h"
21 
22 namespace fir {
23 #define GEN_PASS_DEF_CHARACTERCONVERSION
24 #include "flang/Optimizer/Transforms/Passes.h.inc"
25 } // namespace fir
26 
27 #define DEBUG_TYPE "flang-character-conversion"
28 
29 namespace {
30 
31 // TODO: Future hook to select some set of runtime calls.
32 struct CharacterConversionOptions {
33   std::string runtimeName;
34 };
35 
36 class CharacterConvertConversion
37     : public mlir::OpRewritePattern<fir::CharConvertOp> {
38 public:
39   using OpRewritePattern::OpRewritePattern;
40 
41   llvm::LogicalResult
matchAndRewrite(fir::CharConvertOp conv,mlir::PatternRewriter & rewriter) const42   matchAndRewrite(fir::CharConvertOp conv,
43                   mlir::PatternRewriter &rewriter) const override {
44     auto kindMap = fir::getKindMapping(conv->getParentOfType<mlir::ModuleOp>());
45     auto loc = conv.getLoc();
46 
47     LLVM_DEBUG(llvm::dbgs()
48                << "running character conversion on " << conv << '\n');
49 
50     // Establish a loop that executes count iterations.
51     auto zero = rewriter.create<mlir::arith::ConstantIndexOp>(loc, 0);
52     auto one = rewriter.create<mlir::arith::ConstantIndexOp>(loc, 1);
53     auto idxTy = rewriter.getIndexType();
54     auto castCnt = rewriter.create<fir::ConvertOp>(loc, idxTy, conv.getCount());
55     auto countm1 = rewriter.create<mlir::arith::SubIOp>(loc, castCnt, one);
56     auto loop = rewriter.create<fir::DoLoopOp>(loc, zero, countm1, one);
57     auto insPt = rewriter.saveInsertionPoint();
58     rewriter.setInsertionPointToStart(loop.getBody());
59 
60     // For each code point in the `from` string, convert naively to the `to`
61     // string code point. Conversion is done blindly on size only, not value.
62     auto getCharBits = [&](mlir::Type t) {
63       auto chrTy = mlir::cast<fir::CharacterType>(
64           fir::unwrapSequenceType(fir::dyn_cast_ptrEleTy(t)));
65       return kindMap.getCharacterBitsize(chrTy.getFKind());
66     };
67     auto fromBits = getCharBits(conv.getFrom().getType());
68     auto toBits = getCharBits(conv.getTo().getType());
69     auto pointerType = [&](unsigned bits) {
70       return fir::ReferenceType::get(fir::SequenceType::get(
71           fir::SequenceType::ShapeRef{fir::SequenceType::getUnknownExtent()},
72           rewriter.getIntegerType(bits)));
73     };
74     auto fromPtrTy = pointerType(fromBits);
75     auto toTy = rewriter.getIntegerType(toBits);
76     auto toPtrTy = pointerType(toBits);
77     auto fromPtr =
78         rewriter.create<fir::ConvertOp>(loc, fromPtrTy, conv.getFrom());
79     auto toPtr = rewriter.create<fir::ConvertOp>(loc, toPtrTy, conv.getTo());
80     auto getEleTy = [&](unsigned bits) {
81       return fir::ReferenceType::get(rewriter.getIntegerType(bits));
82     };
83     auto fromi = rewriter.create<fir::CoordinateOp>(
84         loc, getEleTy(fromBits), fromPtr,
85         mlir::ValueRange{loop.getInductionVar()});
86     auto toi = rewriter.create<fir::CoordinateOp>(
87         loc, getEleTy(toBits), toPtr, mlir::ValueRange{loop.getInductionVar()});
88     auto load = rewriter.create<fir::LoadOp>(loc, fromi);
89     mlir::Value icast =
90         (fromBits >= toBits)
91             ? rewriter.create<fir::ConvertOp>(loc, toTy, load).getResult()
92             : rewriter.create<mlir::arith::ExtUIOp>(loc, toTy, load)
93                   .getResult();
94     rewriter.replaceOpWithNewOp<fir::StoreOp>(conv, icast, toi);
95     rewriter.restoreInsertionPoint(insPt);
96     return mlir::success();
97   }
98 };
99 
100 /// Rewrite the `fir.char_convert` op into a loop. This pass must be run only on
101 /// fir::CharConvertOp.
102 class CharacterConversion
103     : public fir::impl::CharacterConversionBase<CharacterConversion> {
104 public:
105   using fir::impl::CharacterConversionBase<
106       CharacterConversion>::CharacterConversionBase;
107 
runOnOperation()108   void runOnOperation() override {
109     CharacterConversionOptions clOpts{useRuntimeCalls.getValue()};
110     if (clOpts.runtimeName.empty()) {
111       auto *context = &getContext();
112       auto *func = getOperation();
113       mlir::RewritePatternSet patterns(context);
114       patterns.insert<CharacterConvertConversion>(context);
115       mlir::ConversionTarget target(*context);
116       target.addLegalDialect<mlir::affine::AffineDialect, fir::FIROpsDialect,
117                              mlir::arith::ArithDialect,
118                              mlir::func::FuncDialect>();
119 
120       // apply the patterns
121       target.addIllegalOp<fir::CharConvertOp>();
122       if (mlir::failed(mlir::applyPartialConversion(func, target,
123                                                     std::move(patterns)))) {
124         mlir::emitError(mlir::UnknownLoc::get(context),
125                         "error in rewriting character convert op");
126         signalPassFailure();
127       }
128       return;
129     }
130 
131     // TODO: some sort of runtime supported conversion?
132     signalPassFailure();
133   }
134 };
135 } // end anonymous namespace
136