16eb7634fSJean Perier //===- CharacterConversion.cpp -- convert between character encodings -----===//
26eb7634fSJean Perier //
36eb7634fSJean Perier // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
46eb7634fSJean Perier // See https://llvm.org/LICENSE.txt for license information.
56eb7634fSJean Perier // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
66eb7634fSJean Perier //
76eb7634fSJean Perier //===----------------------------------------------------------------------===//
86eb7634fSJean Perier
96eb7634fSJean Perier #include "PassDetail.h"
106eb7634fSJean Perier #include "flang/Optimizer/Dialect/FIRDialect.h"
116eb7634fSJean Perier #include "flang/Optimizer/Dialect/FIROps.h"
126eb7634fSJean Perier #include "flang/Optimizer/Dialect/FIRType.h"
136eb7634fSJean Perier #include "flang/Optimizer/Support/FIRContext.h"
146eb7634fSJean Perier #include "flang/Optimizer/Support/KindMapping.h"
156eb7634fSJean Perier #include "flang/Optimizer/Transforms/Passes.h"
16*23aa5a74SRiver Riddle #include "mlir/Dialect/Func/IR/FuncOps.h"
176eb7634fSJean Perier #include "mlir/IR/Diagnostics.h"
186eb7634fSJean Perier #include "mlir/Pass/Pass.h"
196eb7634fSJean Perier #include "mlir/Transforms/DialectConversion.h"
206eb7634fSJean Perier #include "llvm/Support/Debug.h"
216eb7634fSJean Perier
226eb7634fSJean Perier #define DEBUG_TYPE "flang-character-conversion"
236eb7634fSJean Perier
246eb7634fSJean Perier namespace {
256eb7634fSJean Perier
266eb7634fSJean Perier // TODO: Future hook to select some set of runtime calls.
276eb7634fSJean Perier struct CharacterConversionOptions {
286eb7634fSJean Perier std::string runtimeName;
296eb7634fSJean Perier };
306eb7634fSJean Perier
316eb7634fSJean Perier class CharacterConvertConversion
326eb7634fSJean Perier : public mlir::OpRewritePattern<fir::CharConvertOp> {
336eb7634fSJean Perier public:
346eb7634fSJean Perier using OpRewritePattern::OpRewritePattern;
356eb7634fSJean Perier
366eb7634fSJean Perier mlir::LogicalResult
matchAndRewrite(fir::CharConvertOp conv,mlir::PatternRewriter & rewriter) const376eb7634fSJean Perier matchAndRewrite(fir::CharConvertOp conv,
386eb7634fSJean Perier mlir::PatternRewriter &rewriter) const override {
396eb7634fSJean Perier auto kindMap = fir::getKindMapping(conv->getParentOfType<mlir::ModuleOp>());
406eb7634fSJean Perier auto loc = conv.getLoc();
416eb7634fSJean Perier
426eb7634fSJean Perier LLVM_DEBUG(llvm::dbgs()
436eb7634fSJean Perier << "running character conversion on " << conv << '\n');
446eb7634fSJean Perier
456eb7634fSJean Perier // Establish a loop that executes count iterations.
46a54f4eaeSMogball auto zero = rewriter.create<mlir::arith::ConstantIndexOp>(loc, 0);
47a54f4eaeSMogball auto one = rewriter.create<mlir::arith::ConstantIndexOp>(loc, 1);
486eb7634fSJean Perier auto idxTy = rewriter.getIndexType();
49149ad3d5SShraiysh Vaishay auto castCnt = rewriter.create<fir::ConvertOp>(loc, idxTy, conv.getCount());
50a54f4eaeSMogball auto countm1 = rewriter.create<mlir::arith::SubIOp>(loc, castCnt, one);
516eb7634fSJean Perier auto loop = rewriter.create<fir::DoLoopOp>(loc, zero, countm1, one);
526eb7634fSJean Perier auto insPt = rewriter.saveInsertionPoint();
536eb7634fSJean Perier rewriter.setInsertionPointToStart(loop.getBody());
546eb7634fSJean Perier
556eb7634fSJean Perier // For each code point in the `from` string, convert naively to the `to`
566eb7634fSJean Perier // string code point. Conversion is done blindly on size only, not value.
576eb7634fSJean Perier auto getCharBits = [&](mlir::Type t) {
586eb7634fSJean Perier auto chrTy = fir::unwrapSequenceType(fir::dyn_cast_ptrEleTy(t))
596eb7634fSJean Perier .cast<fir::CharacterType>();
606eb7634fSJean Perier return kindMap.getCharacterBitsize(chrTy.getFKind());
616eb7634fSJean Perier };
62149ad3d5SShraiysh Vaishay auto fromBits = getCharBits(conv.getFrom().getType());
63149ad3d5SShraiysh Vaishay auto toBits = getCharBits(conv.getTo().getType());
646eb7634fSJean Perier auto pointerType = [&](unsigned bits) {
656eb7634fSJean Perier return fir::ReferenceType::get(fir::SequenceType::get(
666eb7634fSJean Perier fir::SequenceType::ShapeRef{fir::SequenceType::getUnknownExtent()},
676eb7634fSJean Perier rewriter.getIntegerType(bits)));
686eb7634fSJean Perier };
696eb7634fSJean Perier auto fromPtrTy = pointerType(fromBits);
706eb7634fSJean Perier auto toTy = rewriter.getIntegerType(toBits);
716eb7634fSJean Perier auto toPtrTy = pointerType(toBits);
72149ad3d5SShraiysh Vaishay auto fromPtr =
73149ad3d5SShraiysh Vaishay rewriter.create<fir::ConvertOp>(loc, fromPtrTy, conv.getFrom());
74149ad3d5SShraiysh Vaishay auto toPtr = rewriter.create<fir::ConvertOp>(loc, toPtrTy, conv.getTo());
756eb7634fSJean Perier auto getEleTy = [&](unsigned bits) {
766eb7634fSJean Perier return fir::ReferenceType::get(rewriter.getIntegerType(bits));
776eb7634fSJean Perier };
786eb7634fSJean Perier auto fromi = rewriter.create<fir::CoordinateOp>(
796eb7634fSJean Perier loc, getEleTy(fromBits), fromPtr,
806eb7634fSJean Perier mlir::ValueRange{loop.getInductionVar()});
816eb7634fSJean Perier auto toi = rewriter.create<fir::CoordinateOp>(
826eb7634fSJean Perier loc, getEleTy(toBits), toPtr, mlir::ValueRange{loop.getInductionVar()});
836eb7634fSJean Perier auto load = rewriter.create<fir::LoadOp>(loc, fromi);
846eb7634fSJean Perier mlir::Value icast =
856eb7634fSJean Perier (fromBits >= toBits)
866eb7634fSJean Perier ? rewriter.create<fir::ConvertOp>(loc, toTy, load).getResult()
87a54f4eaeSMogball : rewriter.create<mlir::arith::ExtUIOp>(loc, toTy, load)
88a54f4eaeSMogball .getResult();
896eb7634fSJean Perier rewriter.replaceOpWithNewOp<fir::StoreOp>(conv, icast, toi);
906eb7634fSJean Perier rewriter.restoreInsertionPoint(insPt);
916eb7634fSJean Perier return mlir::success();
926eb7634fSJean Perier }
936eb7634fSJean Perier };
946eb7634fSJean Perier
956eb7634fSJean Perier /// Rewrite the `fir.char_convert` op into a loop. This pass must be run only on
966eb7634fSJean Perier /// fir::CharConvertOp.
976eb7634fSJean Perier class CharacterConversion
986eb7634fSJean Perier : public fir::CharacterConversionBase<CharacterConversion> {
996eb7634fSJean Perier public:
runOnOperation()1006eb7634fSJean Perier void runOnOperation() override {
1016eb7634fSJean Perier CharacterConversionOptions clOpts{useRuntimeCalls.getValue()};
1026eb7634fSJean Perier if (clOpts.runtimeName.empty()) {
1036eb7634fSJean Perier auto *context = &getContext();
1046eb7634fSJean Perier auto *func = getOperation();
1059f85c198SRiver Riddle mlir::RewritePatternSet patterns(context);
1066eb7634fSJean Perier patterns.insert<CharacterConvertConversion>(context);
1076eb7634fSJean Perier mlir::ConversionTarget target(*context);
1086eb7634fSJean Perier target.addLegalDialect<mlir::AffineDialect, fir::FIROpsDialect,
109a54f4eaeSMogball mlir::arith::ArithmeticDialect,
110*23aa5a74SRiver Riddle mlir::func::FuncDialect>();
1116eb7634fSJean Perier
1126eb7634fSJean Perier // apply the patterns
1136eb7634fSJean Perier target.addIllegalOp<fir::CharConvertOp>();
1146eb7634fSJean Perier if (mlir::failed(mlir::applyPartialConversion(func, target,
1156eb7634fSJean Perier std::move(patterns)))) {
1166eb7634fSJean Perier mlir::emitError(mlir::UnknownLoc::get(context),
1176eb7634fSJean Perier "error in rewriting character convert op");
1186eb7634fSJean Perier signalPassFailure();
1196eb7634fSJean Perier }
1206eb7634fSJean Perier return;
1216eb7634fSJean Perier }
1226eb7634fSJean Perier
1236eb7634fSJean Perier // TODO: some sort of runtime supported conversion?
1246eb7634fSJean Perier signalPassFailure();
1256eb7634fSJean Perier }
1266eb7634fSJean Perier };
1276eb7634fSJean Perier } // end anonymous namespace
1286eb7634fSJean Perier
createCharacterConversionPass()1296eb7634fSJean Perier std::unique_ptr<mlir::Pass> fir::createCharacterConversionPass() {
1306eb7634fSJean Perier return std::make_unique<CharacterConversion>();
1316eb7634fSJean Perier }
132