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