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/StandardOps/IR/Ops.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 37 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.count()); 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.from().getType()); 63 auto toBits = getCharBits(conv.to().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 = rewriter.create<fir::ConvertOp>(loc, fromPtrTy, conv.from()); 73 auto toPtr = rewriter.create<fir::ConvertOp>(loc, toPtrTy, conv.to()); 74 auto getEleTy = [&](unsigned bits) { 75 return fir::ReferenceType::get(rewriter.getIntegerType(bits)); 76 }; 77 auto fromi = rewriter.create<fir::CoordinateOp>( 78 loc, getEleTy(fromBits), fromPtr, 79 mlir::ValueRange{loop.getInductionVar()}); 80 auto toi = rewriter.create<fir::CoordinateOp>( 81 loc, getEleTy(toBits), toPtr, mlir::ValueRange{loop.getInductionVar()}); 82 auto load = rewriter.create<fir::LoadOp>(loc, fromi); 83 mlir::Value icast = 84 (fromBits >= toBits) 85 ? rewriter.create<fir::ConvertOp>(loc, toTy, load).getResult() 86 : rewriter.create<mlir::arith::ExtUIOp>(loc, toTy, load) 87 .getResult(); 88 rewriter.replaceOpWithNewOp<fir::StoreOp>(conv, icast, toi); 89 rewriter.restoreInsertionPoint(insPt); 90 return mlir::success(); 91 } 92 }; 93 94 /// Rewrite the `fir.char_convert` op into a loop. This pass must be run only on 95 /// fir::CharConvertOp. 96 class CharacterConversion 97 : public fir::CharacterConversionBase<CharacterConversion> { 98 public: 99 void runOnOperation() override { 100 CharacterConversionOptions clOpts{useRuntimeCalls.getValue()}; 101 if (clOpts.runtimeName.empty()) { 102 auto *context = &getContext(); 103 auto *func = getOperation(); 104 mlir::OwningRewritePatternList patterns(context); 105 patterns.insert<CharacterConvertConversion>(context); 106 mlir::ConversionTarget target(*context); 107 target.addLegalDialect<mlir::AffineDialect, fir::FIROpsDialect, 108 mlir::arith::ArithmeticDialect, 109 mlir::StandardOpsDialect>(); 110 111 // apply the patterns 112 target.addIllegalOp<fir::CharConvertOp>(); 113 if (mlir::failed(mlir::applyPartialConversion(func, target, 114 std::move(patterns)))) { 115 mlir::emitError(mlir::UnknownLoc::get(context), 116 "error in rewriting character convert op"); 117 signalPassFailure(); 118 } 119 return; 120 } 121 122 // TODO: some sort of runtime supported conversion? 123 signalPassFailure(); 124 } 125 }; 126 } // end anonymous namespace 127 128 std::unique_ptr<mlir::Pass> fir::createCharacterConversionPass() { 129 return std::make_unique<CharacterConversion>(); 130 } 131