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 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.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: 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 129 std::unique_ptr<mlir::Pass> fir::createCharacterConversionPass() { 130 return std::make_unique<CharacterConversion>(); 131 } 132