1 //===-- Character.cpp -- runtime for CHARACTER type entities --------------===// 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 "flang/Optimizer/Builder/Runtime/Character.h" 10 #include "flang/Optimizer/Builder/BoxValue.h" 11 #include "flang/Optimizer/Builder/Character.h" 12 #include "flang/Optimizer/Builder/FIRBuilder.h" 13 #include "flang/Optimizer/Builder/Runtime/RTBuilder.h" 14 #include "flang/Optimizer/Builder/Todo.h" 15 #include "flang/Runtime/character.h" 16 #include "mlir/Dialect/Func/IR/FuncOps.h" 17 18 using namespace Fortran::runtime; 19 20 /// Generate calls to string handling intrinsics such as index, scan, and 21 /// verify. These are the descriptor based implementations that take four 22 /// arguments (string1, string2, back, kind). 23 template <typename FN> 24 static void genCharacterSearch(FN func, fir::FirOpBuilder &builder, 25 mlir::Location loc, mlir::Value resultBox, 26 mlir::Value string1Box, mlir::Value string2Box, 27 mlir::Value backBox, mlir::Value kind) { 28 29 auto fTy = func.getFunctionType(); 30 auto sourceFile = fir::factory::locationToFilename(builder, loc); 31 auto sourceLine = 32 fir::factory::locationToLineNo(builder, loc, fTy.getInput(6)); 33 34 auto args = fir::runtime::createArguments(builder, loc, fTy, resultBox, 35 string1Box, string2Box, backBox, 36 kind, sourceFile, sourceLine); 37 builder.create<fir::CallOp>(loc, func, args); 38 } 39 40 /// Helper function to recover the KIND from the FIR type. 41 static int discoverKind(mlir::Type ty) { 42 if (auto charTy = ty.dyn_cast<fir::CharacterType>()) 43 return charTy.getFKind(); 44 if (auto eleTy = fir::dyn_cast_ptrEleTy(ty)) 45 return discoverKind(eleTy); 46 if (auto arrTy = ty.dyn_cast<fir::SequenceType>()) 47 return discoverKind(arrTy.getEleTy()); 48 if (auto boxTy = ty.dyn_cast<fir::BoxCharType>()) 49 return discoverKind(boxTy.getEleTy()); 50 if (auto boxTy = ty.dyn_cast<fir::BoxType>()) 51 return discoverKind(boxTy.getEleTy()); 52 llvm_unreachable("unexpected character type"); 53 } 54 55 //===----------------------------------------------------------------------===// 56 // Lower character operations 57 //===----------------------------------------------------------------------===// 58 59 /// Generate a call to the `ADJUST[L|R]` runtime. 60 /// 61 /// \p resultBox must be an unallocated allocatable used for the temporary 62 /// result. \p StringBox must be a fir.box describing the adjustr string 63 /// argument. The \p adjustFunc should be a mlir::func::FuncOp for the 64 /// appropriate runtime entry function. 65 static void genAdjust(fir::FirOpBuilder &builder, mlir::Location loc, 66 mlir::Value resultBox, mlir::Value stringBox, 67 mlir::func::FuncOp &adjustFunc) { 68 69 auto fTy = adjustFunc.getFunctionType(); 70 auto sourceLine = 71 fir::factory::locationToLineNo(builder, loc, fTy.getInput(3)); 72 auto sourceFile = fir::factory::locationToFilename(builder, loc); 73 auto args = fir::runtime::createArguments(builder, loc, fTy, resultBox, 74 stringBox, sourceFile, sourceLine); 75 builder.create<fir::CallOp>(loc, adjustFunc, args); 76 } 77 78 void fir::runtime::genAdjustL(fir::FirOpBuilder &builder, mlir::Location loc, 79 mlir::Value resultBox, mlir::Value stringBox) { 80 auto adjustFunc = 81 fir::runtime::getRuntimeFunc<mkRTKey(Adjustl)>(loc, builder); 82 genAdjust(builder, loc, resultBox, stringBox, adjustFunc); 83 } 84 85 void fir::runtime::genAdjustR(fir::FirOpBuilder &builder, mlir::Location loc, 86 mlir::Value resultBox, mlir::Value stringBox) { 87 auto adjustFunc = 88 fir::runtime::getRuntimeFunc<mkRTKey(Adjustr)>(loc, builder); 89 genAdjust(builder, loc, resultBox, stringBox, adjustFunc); 90 } 91 92 mlir::Value 93 fir::runtime::genCharCompare(fir::FirOpBuilder &builder, mlir::Location loc, 94 mlir::arith::CmpIPredicate cmp, 95 mlir::Value lhsBuff, mlir::Value lhsLen, 96 mlir::Value rhsBuff, mlir::Value rhsLen) { 97 mlir::func::FuncOp beginFunc; 98 switch (discoverKind(lhsBuff.getType())) { 99 case 1: 100 beginFunc = fir::runtime::getRuntimeFunc<mkRTKey(CharacterCompareScalar1)>( 101 loc, builder); 102 break; 103 case 2: 104 beginFunc = fir::runtime::getRuntimeFunc<mkRTKey(CharacterCompareScalar2)>( 105 loc, builder); 106 break; 107 case 4: 108 beginFunc = fir::runtime::getRuntimeFunc<mkRTKey(CharacterCompareScalar4)>( 109 loc, builder); 110 break; 111 default: 112 llvm_unreachable("runtime does not support CHARACTER KIND"); 113 } 114 auto fTy = beginFunc.getFunctionType(); 115 auto args = fir::runtime::createArguments(builder, loc, fTy, lhsBuff, rhsBuff, 116 lhsLen, rhsLen); 117 auto tri = builder.create<fir::CallOp>(loc, beginFunc, args).getResult(0); 118 auto zero = builder.createIntegerConstant(loc, tri.getType(), 0); 119 return builder.create<mlir::arith::CmpIOp>(loc, cmp, tri, zero); 120 } 121 122 mlir::Value fir::runtime::genCharCompare(fir::FirOpBuilder &builder, 123 mlir::Location loc, 124 mlir::arith::CmpIPredicate cmp, 125 const fir::ExtendedValue &lhs, 126 const fir::ExtendedValue &rhs) { 127 if (lhs.getBoxOf<fir::BoxValue>() || rhs.getBoxOf<fir::BoxValue>()) 128 TODO(loc, "character compare from descriptors"); 129 auto allocateIfNotInMemory = [&](mlir::Value base) -> mlir::Value { 130 if (fir::isa_ref_type(base.getType())) 131 return base; 132 auto mem = 133 builder.create<fir::AllocaOp>(loc, base.getType(), /*pinned=*/false); 134 builder.create<fir::StoreOp>(loc, base, mem); 135 return mem; 136 }; 137 auto lhsBuffer = allocateIfNotInMemory(fir::getBase(lhs)); 138 auto rhsBuffer = allocateIfNotInMemory(fir::getBase(rhs)); 139 return genCharCompare(builder, loc, cmp, lhsBuffer, fir::getLen(lhs), 140 rhsBuffer, fir::getLen(rhs)); 141 } 142 143 mlir::Value fir::runtime::genIndex(fir::FirOpBuilder &builder, 144 mlir::Location loc, int kind, 145 mlir::Value stringBase, 146 mlir::Value stringLen, 147 mlir::Value substringBase, 148 mlir::Value substringLen, mlir::Value back) { 149 mlir::func::FuncOp indexFunc; 150 switch (kind) { 151 case 1: 152 indexFunc = fir::runtime::getRuntimeFunc<mkRTKey(Index1)>(loc, builder); 153 break; 154 case 2: 155 indexFunc = fir::runtime::getRuntimeFunc<mkRTKey(Index2)>(loc, builder); 156 break; 157 case 4: 158 indexFunc = fir::runtime::getRuntimeFunc<mkRTKey(Index4)>(loc, builder); 159 break; 160 default: 161 fir::emitFatalError( 162 loc, "unsupported CHARACTER kind value. Runtime expects 1, 2, or 4."); 163 } 164 auto fTy = indexFunc.getFunctionType(); 165 auto args = 166 fir::runtime::createArguments(builder, loc, fTy, stringBase, stringLen, 167 substringBase, substringLen, back); 168 return builder.create<fir::CallOp>(loc, indexFunc, args).getResult(0); 169 } 170 171 void fir::runtime::genIndexDescriptor(fir::FirOpBuilder &builder, 172 mlir::Location loc, mlir::Value resultBox, 173 mlir::Value stringBox, 174 mlir::Value substringBox, 175 mlir::Value backOpt, mlir::Value kind) { 176 auto indexFunc = fir::runtime::getRuntimeFunc<mkRTKey(Index)>(loc, builder); 177 genCharacterSearch(indexFunc, builder, loc, resultBox, stringBox, 178 substringBox, backOpt, kind); 179 } 180 181 void fir::runtime::genRepeat(fir::FirOpBuilder &builder, mlir::Location loc, 182 mlir::Value resultBox, mlir::Value stringBox, 183 mlir::Value ncopies) { 184 auto repeatFunc = fir::runtime::getRuntimeFunc<mkRTKey(Repeat)>(loc, builder); 185 auto fTy = repeatFunc.getFunctionType(); 186 auto sourceFile = fir::factory::locationToFilename(builder, loc); 187 auto sourceLine = 188 fir::factory::locationToLineNo(builder, loc, fTy.getInput(4)); 189 190 auto args = fir::runtime::createArguments( 191 builder, loc, fTy, resultBox, stringBox, ncopies, sourceFile, sourceLine); 192 builder.create<fir::CallOp>(loc, repeatFunc, args); 193 } 194 195 void fir::runtime::genTrim(fir::FirOpBuilder &builder, mlir::Location loc, 196 mlir::Value resultBox, mlir::Value stringBox) { 197 auto trimFunc = fir::runtime::getRuntimeFunc<mkRTKey(Trim)>(loc, builder); 198 auto fTy = trimFunc.getFunctionType(); 199 auto sourceFile = fir::factory::locationToFilename(builder, loc); 200 auto sourceLine = 201 fir::factory::locationToLineNo(builder, loc, fTy.getInput(3)); 202 203 auto args = fir::runtime::createArguments(builder, loc, fTy, resultBox, 204 stringBox, sourceFile, sourceLine); 205 builder.create<fir::CallOp>(loc, trimFunc, args); 206 } 207 208 void fir::runtime::genScanDescriptor(fir::FirOpBuilder &builder, 209 mlir::Location loc, mlir::Value resultBox, 210 mlir::Value stringBox, mlir::Value setBox, 211 mlir::Value backBox, mlir::Value kind) { 212 auto func = fir::runtime::getRuntimeFunc<mkRTKey(Scan)>(loc, builder); 213 genCharacterSearch(func, builder, loc, resultBox, stringBox, setBox, backBox, 214 kind); 215 } 216 217 mlir::Value fir::runtime::genScan(fir::FirOpBuilder &builder, 218 mlir::Location loc, int kind, 219 mlir::Value stringBase, mlir::Value stringLen, 220 mlir::Value setBase, mlir::Value setLen, 221 mlir::Value back) { 222 mlir::func::FuncOp func; 223 switch (kind) { 224 case 1: 225 func = fir::runtime::getRuntimeFunc<mkRTKey(Scan1)>(loc, builder); 226 break; 227 case 2: 228 func = fir::runtime::getRuntimeFunc<mkRTKey(Scan2)>(loc, builder); 229 break; 230 case 4: 231 func = fir::runtime::getRuntimeFunc<mkRTKey(Scan4)>(loc, builder); 232 break; 233 default: 234 fir::emitFatalError( 235 loc, "unsupported CHARACTER kind value. Runtime expects 1, 2, or 4."); 236 } 237 auto fTy = func.getFunctionType(); 238 auto args = fir::runtime::createArguments(builder, loc, fTy, stringBase, 239 stringLen, setBase, setLen, back); 240 return builder.create<fir::CallOp>(loc, func, args).getResult(0); 241 } 242 243 void fir::runtime::genVerifyDescriptor(fir::FirOpBuilder &builder, 244 mlir::Location loc, 245 mlir::Value resultBox, 246 mlir::Value stringBox, 247 mlir::Value setBox, mlir::Value backBox, 248 mlir::Value kind) { 249 auto func = fir::runtime::getRuntimeFunc<mkRTKey(Verify)>(loc, builder); 250 genCharacterSearch(func, builder, loc, resultBox, stringBox, setBox, backBox, 251 kind); 252 } 253 254 mlir::Value fir::runtime::genVerify(fir::FirOpBuilder &builder, 255 mlir::Location loc, int kind, 256 mlir::Value stringBase, 257 mlir::Value stringLen, mlir::Value setBase, 258 mlir::Value setLen, mlir::Value back) { 259 mlir::func::FuncOp func; 260 switch (kind) { 261 case 1: 262 func = fir::runtime::getRuntimeFunc<mkRTKey(Verify1)>(loc, builder); 263 break; 264 case 2: 265 func = fir::runtime::getRuntimeFunc<mkRTKey(Verify2)>(loc, builder); 266 break; 267 case 4: 268 func = fir::runtime::getRuntimeFunc<mkRTKey(Verify4)>(loc, builder); 269 break; 270 default: 271 fir::emitFatalError( 272 loc, "unsupported CHARACTER kind value. Runtime expects 1, 2, or 4."); 273 } 274 auto fTy = func.getFunctionType(); 275 auto args = fir::runtime::createArguments(builder, loc, fTy, stringBase, 276 stringLen, setBase, setLen, back); 277 return builder.create<fir::CallOp>(loc, func, args).getResult(0); 278 } 279