//===- 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 "flang/Optimizer/Dialect/FIRDialect.h" #include "flang/Optimizer/Dialect/FIROps.h" #include "flang/Optimizer/Dialect/FIRType.h" #include "flang/Optimizer/Dialect/Support/FIRContext.h" #include "flang/Optimizer/Dialect/Support/KindMapping.h" #include "flang/Optimizer/Transforms/Passes.h" #include "mlir/Dialect/Affine/IR/AffineOps.h" #include "mlir/Dialect/Func/IR/FuncOps.h" #include "mlir/IR/Diagnostics.h" #include "mlir/Pass/Pass.h" #include "mlir/Transforms/DialectConversion.h" #include "llvm/Support/Debug.h" namespace fir { #define GEN_PASS_DEF_CHARACTERCONVERSION #include "flang/Optimizer/Transforms/Passes.h.inc" } // namespace fir #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 { public: using OpRewritePattern::OpRewritePattern; mlir::LogicalResult matchAndRewrite(fir::CharConvertOp conv, mlir::PatternRewriter &rewriter) const override { auto kindMap = fir::getKindMapping(conv->getParentOfType()); 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(loc, 0); auto one = rewriter.create(loc, 1); auto idxTy = rewriter.getIndexType(); auto castCnt = rewriter.create(loc, idxTy, conv.getCount()); auto countm1 = rewriter.create(loc, castCnt, one); auto loop = rewriter.create(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(); return kindMap.getCharacterBitsize(chrTy.getFKind()); }; auto fromBits = getCharBits(conv.getFrom().getType()); auto toBits = getCharBits(conv.getTo().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(loc, fromPtrTy, conv.getFrom()); auto toPtr = rewriter.create(loc, toPtrTy, conv.getTo()); auto getEleTy = [&](unsigned bits) { return fir::ReferenceType::get(rewriter.getIntegerType(bits)); }; auto fromi = rewriter.create( loc, getEleTy(fromBits), fromPtr, mlir::ValueRange{loop.getInductionVar()}); auto toi = rewriter.create( loc, getEleTy(toBits), toPtr, mlir::ValueRange{loop.getInductionVar()}); auto load = rewriter.create(loc, fromi); mlir::Value icast = (fromBits >= toBits) ? rewriter.create(loc, toTy, load).getResult() : rewriter.create(loc, toTy, load) .getResult(); rewriter.replaceOpWithNewOp(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::impl::CharacterConversionBase { public: void runOnOperation() override { CharacterConversionOptions clOpts{useRuntimeCalls.getValue()}; if (clOpts.runtimeName.empty()) { auto *context = &getContext(); auto *func = getOperation(); mlir::RewritePatternSet patterns(context); patterns.insert(context); mlir::ConversionTarget target(*context); target.addLegalDialect(); // apply the patterns target.addIllegalOp(); 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 fir::createCharacterConversionPass() { return std::make_unique(); }