1 //===-- Character.cpp -----------------------------------------------------===// 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 // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "flang/Optimizer/Builder/Character.h" 14 #include "flang/Lower/Todo.h" 15 #include "flang/Optimizer/Builder/DoLoopHelper.h" 16 #include "llvm/Support/Debug.h" 17 #include <optional> 18 19 #define DEBUG_TYPE "flang-lower-character" 20 21 using namespace mlir; 22 23 //===----------------------------------------------------------------------===// 24 // CharacterExprHelper implementation 25 //===----------------------------------------------------------------------===// 26 27 /// Unwrap base fir.char<kind,len> type. 28 static fir::CharacterType recoverCharacterType(mlir::Type type) { 29 if (auto boxType = type.dyn_cast<fir::BoxCharType>()) 30 return boxType.getEleTy(); 31 while (true) { 32 type = fir::unwrapRefType(type); 33 if (auto boxTy = type.dyn_cast<fir::BoxType>()) 34 type = boxTy.getEleTy(); 35 else 36 break; 37 } 38 return fir::unwrapSequenceType(type).cast<fir::CharacterType>(); 39 } 40 41 /// Get fir.char<kind> type with the same kind as inside str. 42 fir::CharacterType 43 fir::factory::CharacterExprHelper::getCharacterType(mlir::Type type) { 44 assert(isCharacterScalar(type) && "expected scalar character"); 45 return recoverCharacterType(type); 46 } 47 48 fir::CharacterType 49 fir::factory::CharacterExprHelper::getCharType(mlir::Type type) { 50 return recoverCharacterType(type); 51 } 52 53 fir::CharacterType fir::factory::CharacterExprHelper::getCharacterType( 54 const fir::CharBoxValue &box) { 55 return getCharacterType(box.getBuffer().getType()); 56 } 57 58 fir::CharacterType 59 fir::factory::CharacterExprHelper::getCharacterType(mlir::Value str) { 60 return getCharacterType(str.getType()); 61 } 62 63 /// Determine the static size of the character. Returns the computed size, not 64 /// an IR Value. 65 static std::optional<fir::CharacterType::LenType> 66 getCompileTimeLength(const fir::CharBoxValue &box) { 67 auto len = recoverCharacterType(box.getBuffer().getType()).getLen(); 68 if (len == fir::CharacterType::unknownLen()) 69 return {}; 70 return len; 71 } 72 73 /// Detect the precondition that the value `str` does not reside in memory. Such 74 /// values will have a type `!fir.array<...x!fir.char<N>>` or `!fir.char<N>`. 75 LLVM_ATTRIBUTE_UNUSED static bool needToMaterialize(mlir::Value str) { 76 return str.getType().isa<fir::SequenceType>() || fir::isa_char(str.getType()); 77 } 78 79 /// Unwrap integer constant from mlir::Value. 80 static llvm::Optional<std::int64_t> getIntIfConstant(mlir::Value value) { 81 if (auto *definingOp = value.getDefiningOp()) 82 if (auto cst = mlir::dyn_cast<mlir::arith::ConstantOp>(definingOp)) 83 if (auto intAttr = cst.getValue().dyn_cast<mlir::IntegerAttr>()) 84 return intAttr.getInt(); 85 return {}; 86 } 87 88 /// This is called only if `str` does not reside in memory. Such a bare string 89 /// value will be converted into a memory-based temporary and an extended 90 /// boxchar value returned. 91 fir::CharBoxValue 92 fir::factory::CharacterExprHelper::materializeValue(mlir::Value str) { 93 assert(needToMaterialize(str)); 94 auto ty = str.getType(); 95 assert(isCharacterScalar(ty) && "expected scalar character"); 96 auto charTy = ty.dyn_cast<fir::CharacterType>(); 97 if (!charTy || charTy.getLen() == fir::CharacterType::unknownLen()) { 98 LLVM_DEBUG(llvm::dbgs() << "cannot materialize: " << str << '\n'); 99 llvm_unreachable("must be a !fir.char<N> type"); 100 } 101 auto len = builder.createIntegerConstant( 102 loc, builder.getCharacterLengthType(), charTy.getLen()); 103 auto temp = builder.create<fir::AllocaOp>(loc, charTy); 104 builder.create<fir::StoreOp>(loc, str, temp); 105 LLVM_DEBUG(llvm::dbgs() << "materialized as local: " << str << " -> (" << temp 106 << ", " << len << ")\n"); 107 return {temp, len}; 108 } 109 110 fir::ExtendedValue 111 fir::factory::CharacterExprHelper::toExtendedValue(mlir::Value character, 112 mlir::Value len) { 113 auto lenType = builder.getCharacterLengthType(); 114 auto type = character.getType(); 115 auto base = fir::isa_passbyref_type(type) ? character : mlir::Value{}; 116 auto resultLen = len; 117 llvm::SmallVector<mlir::Value> extents; 118 119 if (auto eleType = fir::dyn_cast_ptrEleTy(type)) 120 type = eleType; 121 122 if (auto arrayType = type.dyn_cast<fir::SequenceType>()) { 123 type = arrayType.getEleTy(); 124 auto indexType = builder.getIndexType(); 125 for (auto extent : arrayType.getShape()) { 126 if (extent == fir::SequenceType::getUnknownExtent()) 127 break; 128 extents.emplace_back( 129 builder.createIntegerConstant(loc, indexType, extent)); 130 } 131 // Last extent might be missing in case of assumed-size. If more extents 132 // could not be deduced from type, that's an error (a fir.box should 133 // have been used in the interface). 134 if (extents.size() + 1 < arrayType.getShape().size()) 135 mlir::emitError(loc, "cannot retrieve array extents from type"); 136 } 137 138 if (auto charTy = type.dyn_cast<fir::CharacterType>()) { 139 if (!resultLen && charTy.getLen() != fir::CharacterType::unknownLen()) 140 resultLen = builder.createIntegerConstant(loc, lenType, charTy.getLen()); 141 } else if (auto boxCharType = type.dyn_cast<fir::BoxCharType>()) { 142 auto refType = builder.getRefType(boxCharType.getEleTy()); 143 // If the embox is accessible, use its operand to avoid filling 144 // the generated fir with embox/unbox. 145 mlir::Value boxCharLen; 146 if (auto *definingOp = character.getDefiningOp()) { 147 if (auto box = dyn_cast<fir::EmboxCharOp>(definingOp)) { 148 base = box.getMemref(); 149 boxCharLen = box.getLen(); 150 } 151 } 152 if (!boxCharLen) { 153 auto unboxed = 154 builder.create<fir::UnboxCharOp>(loc, refType, lenType, character); 155 base = builder.createConvert(loc, refType, unboxed.getResult(0)); 156 boxCharLen = unboxed.getResult(1); 157 } 158 if (!resultLen) { 159 resultLen = boxCharLen; 160 } 161 } else if (type.isa<fir::BoxType>()) { 162 mlir::emitError(loc, "descriptor or derived type not yet handled"); 163 } else { 164 llvm_unreachable("Cannot translate mlir::Value to character ExtendedValue"); 165 } 166 167 if (!base) { 168 if (auto load = 169 mlir::dyn_cast_or_null<fir::LoadOp>(character.getDefiningOp())) { 170 base = load.getOperand(); 171 } else { 172 return materializeValue(fir::getBase(character)); 173 } 174 } 175 if (!resultLen) 176 llvm::report_fatal_error("no dynamic length found for character"); 177 if (!extents.empty()) 178 return fir::CharArrayBoxValue{base, resultLen, extents}; 179 return fir::CharBoxValue{base, resultLen}; 180 } 181 182 static mlir::Type getSingletonCharType(mlir::MLIRContext *ctxt, int kind) { 183 return fir::CharacterType::getSingleton(ctxt, kind); 184 } 185 186 mlir::Value 187 fir::factory::CharacterExprHelper::createEmbox(const fir::CharBoxValue &box) { 188 // Base CharBoxValue of CharArrayBoxValue are ok here (do not require a scalar 189 // type) 190 auto charTy = recoverCharacterType(box.getBuffer().getType()); 191 auto boxCharType = 192 fir::BoxCharType::get(builder.getContext(), charTy.getFKind()); 193 auto refType = fir::ReferenceType::get(boxCharType.getEleTy()); 194 mlir::Value buff = box.getBuffer(); 195 // fir.boxchar requires a memory reference. Allocate temp if the character is 196 // not in memory. 197 if (!fir::isa_ref_type(buff.getType())) { 198 auto temp = builder.createTemporary(loc, buff.getType()); 199 builder.create<fir::StoreOp>(loc, buff, temp); 200 buff = temp; 201 } 202 buff = builder.createConvert(loc, refType, buff); 203 // Convert in case the provided length is not of the integer type that must 204 // be used in boxchar. 205 auto len = builder.createConvert(loc, builder.getCharacterLengthType(), 206 box.getLen()); 207 return builder.create<fir::EmboxCharOp>(loc, boxCharType, buff, len); 208 } 209 210 fir::CharBoxValue fir::factory::CharacterExprHelper::toScalarCharacter( 211 const fir::CharArrayBoxValue &box) { 212 if (box.getBuffer().getType().isa<fir::PointerType>()) 213 TODO(loc, "concatenating non contiguous character array into a scalar"); 214 215 // TODO: add a fast path multiplying new length at compile time if the info is 216 // in the array type. 217 auto lenType = builder.getCharacterLengthType(); 218 auto len = builder.createConvert(loc, lenType, box.getLen()); 219 for (auto extent : box.getExtents()) 220 len = builder.create<arith::MulIOp>( 221 loc, len, builder.createConvert(loc, lenType, extent)); 222 223 // TODO: typeLen can be improved in compiled constant cases 224 // TODO: allow bare fir.array<> (no ref) conversion here ? 225 auto typeLen = fir::CharacterType::unknownLen(); 226 auto kind = recoverCharacterType(box.getBuffer().getType()).getFKind(); 227 auto charTy = fir::CharacterType::get(builder.getContext(), kind, typeLen); 228 auto type = fir::ReferenceType::get(charTy); 229 auto buffer = builder.createConvert(loc, type, box.getBuffer()); 230 return {buffer, len}; 231 } 232 233 mlir::Value fir::factory::CharacterExprHelper::createEmbox( 234 const fir::CharArrayBoxValue &box) { 235 // Use same embox as for scalar. It's losing the actual data size information 236 // (We do not multiply the length by the array size), but that is what Fortran 237 // call interfaces using boxchar expect. 238 return createEmbox(static_cast<const fir::CharBoxValue &>(box)); 239 } 240 241 /// Get the address of the element at position \p index of the scalar character 242 /// \p buffer. 243 /// \p buffer must be of type !fir.ref<fir.char<k, len>>. The length may be 244 /// unknown. \p index must have any integer type, and is zero based. The return 245 /// value is a singleton address (!fir.ref<!fir.char<kind>>) 246 mlir::Value 247 fir::factory::CharacterExprHelper::createElementAddr(mlir::Value buffer, 248 mlir::Value index) { 249 // The only way to address an element of a fir.ref<char<kind, len>> is to cast 250 // it to a fir.array<len x fir.char<kind>> and use fir.coordinate_of. 251 auto bufferType = buffer.getType(); 252 assert(fir::isa_ref_type(bufferType)); 253 assert(isCharacterScalar(bufferType)); 254 auto charTy = recoverCharacterType(bufferType); 255 auto singleTy = getSingletonCharType(builder.getContext(), charTy.getFKind()); 256 auto singleRefTy = builder.getRefType(singleTy); 257 auto extent = fir::SequenceType::getUnknownExtent(); 258 if (charTy.getLen() != fir::CharacterType::unknownLen()) 259 extent = charTy.getLen(); 260 auto coorTy = builder.getRefType(fir::SequenceType::get({extent}, singleTy)); 261 262 auto coor = builder.createConvert(loc, coorTy, buffer); 263 auto i = builder.createConvert(loc, builder.getIndexType(), index); 264 return builder.create<fir::CoordinateOp>(loc, singleRefTy, coor, i); 265 } 266 267 /// Load a character out of `buff` from offset `index`. 268 /// `buff` must be a reference to memory. 269 mlir::Value 270 fir::factory::CharacterExprHelper::createLoadCharAt(mlir::Value buff, 271 mlir::Value index) { 272 LLVM_DEBUG(llvm::dbgs() << "load a char: " << buff << " type: " 273 << buff.getType() << " at: " << index << '\n'); 274 return builder.create<fir::LoadOp>(loc, createElementAddr(buff, index)); 275 } 276 277 /// Store the singleton character `c` to `str` at offset `index`. 278 /// `str` must be a reference to memory. 279 void fir::factory::CharacterExprHelper::createStoreCharAt(mlir::Value str, 280 mlir::Value index, 281 mlir::Value c) { 282 LLVM_DEBUG(llvm::dbgs() << "store the char: " << c << " into: " << str 283 << " type: " << str.getType() << " at: " << index 284 << '\n'); 285 auto addr = createElementAddr(str, index); 286 builder.create<fir::StoreOp>(loc, c, addr); 287 } 288 289 // FIXME: this temp is useless... either fir.coordinate_of needs to 290 // work on "loaded" characters (!fir.array<len x fir.char<kind>>) or 291 // character should never be loaded. 292 // If this is a fir.array<>, allocate and store the value so that 293 // fir.cooridnate_of can be use on the value. 294 mlir::Value fir::factory::CharacterExprHelper::getCharBoxBuffer( 295 const fir::CharBoxValue &box) { 296 auto buff = box.getBuffer(); 297 if (fir::isa_char(buff.getType())) { 298 auto newBuff = builder.create<fir::AllocaOp>(loc, buff.getType()); 299 builder.create<fir::StoreOp>(loc, buff, newBuff); 300 return newBuff; 301 } 302 return buff; 303 } 304 305 /// Get the LLVM intrinsic for `memcpy`. Use the 64 bit version. 306 mlir::FuncOp fir::factory::getLlvmMemcpy(fir::FirOpBuilder &builder) { 307 auto ptrTy = builder.getRefType(builder.getIntegerType(8)); 308 llvm::SmallVector<mlir::Type> args = {ptrTy, ptrTy, builder.getI64Type(), 309 builder.getI1Type()}; 310 auto memcpyTy = 311 mlir::FunctionType::get(builder.getContext(), args, llvm::None); 312 return builder.addNamedFunction(builder.getUnknownLoc(), 313 "llvm.memcpy.p0i8.p0i8.i64", memcpyTy); 314 } 315 316 /// Get the LLVM intrinsic for `memmove`. Use the 64 bit version. 317 mlir::FuncOp fir::factory::getLlvmMemmove(fir::FirOpBuilder &builder) { 318 auto ptrTy = builder.getRefType(builder.getIntegerType(8)); 319 llvm::SmallVector<mlir::Type> args = {ptrTy, ptrTy, builder.getI64Type(), 320 builder.getI1Type()}; 321 auto memmoveTy = 322 mlir::FunctionType::get(builder.getContext(), args, llvm::None); 323 return builder.addNamedFunction(builder.getUnknownLoc(), 324 "llvm.memmove.p0i8.p0i8.i64", memmoveTy); 325 } 326 327 /// Get the LLVM intrinsic for `memset`. Use the 64 bit version. 328 mlir::FuncOp fir::factory::getLlvmMemset(fir::FirOpBuilder &builder) { 329 auto ptrTy = builder.getRefType(builder.getIntegerType(8)); 330 llvm::SmallVector<mlir::Type> args = {ptrTy, ptrTy, builder.getI64Type(), 331 builder.getI1Type()}; 332 auto memsetTy = 333 mlir::FunctionType::get(builder.getContext(), args, llvm::None); 334 return builder.addNamedFunction(builder.getUnknownLoc(), 335 "llvm.memset.p0i8.p0i8.i64", memsetTy); 336 } 337 338 /// Get the standard `realloc` function. 339 mlir::FuncOp fir::factory::getRealloc(fir::FirOpBuilder &builder) { 340 auto ptrTy = builder.getRefType(builder.getIntegerType(8)); 341 llvm::SmallVector<mlir::Type> args = {ptrTy, builder.getI64Type()}; 342 auto reallocTy = mlir::FunctionType::get(builder.getContext(), args, {ptrTy}); 343 return builder.addNamedFunction(builder.getUnknownLoc(), "realloc", 344 reallocTy); 345 } 346 347 /// Create a loop to copy `count` characters from `src` to `dest`. Note that the 348 /// KIND indicates the number of bits in a code point. (ASCII, UCS-2, or UCS-4.) 349 void fir::factory::CharacterExprHelper::createCopy( 350 const fir::CharBoxValue &dest, const fir::CharBoxValue &src, 351 mlir::Value count) { 352 auto fromBuff = getCharBoxBuffer(src); 353 auto toBuff = getCharBoxBuffer(dest); 354 LLVM_DEBUG(llvm::dbgs() << "create char copy from: "; src.dump(); 355 llvm::dbgs() << " to: "; dest.dump(); 356 llvm::dbgs() << " count: " << count << '\n'); 357 auto kind = getCharacterKind(src.getBuffer().getType()); 358 // If the src and dest are the same KIND, then use memmove to move the bits. 359 // We don't have to worry about overlapping ranges with memmove. 360 if (getCharacterKind(dest.getBuffer().getType()) == kind) { 361 auto bytes = builder.getKindMap().getCharacterBitsize(kind) / 8; 362 auto i64Ty = builder.getI64Type(); 363 auto kindBytes = builder.createIntegerConstant(loc, i64Ty, bytes); 364 auto castCount = builder.createConvert(loc, i64Ty, count); 365 auto totalBytes = builder.create<arith::MulIOp>(loc, kindBytes, castCount); 366 auto notVolatile = builder.createBool(loc, false); 367 auto memmv = getLlvmMemmove(builder); 368 auto argTys = memmv.getFunctionType().getInputs(); 369 auto toPtr = builder.createConvert(loc, argTys[0], toBuff); 370 auto fromPtr = builder.createConvert(loc, argTys[1], fromBuff); 371 builder.create<fir::CallOp>( 372 loc, memmv, mlir::ValueRange{toPtr, fromPtr, totalBytes, notVolatile}); 373 return; 374 } 375 376 // Convert a CHARACTER of one KIND into a CHARACTER of another KIND. 377 builder.create<fir::CharConvertOp>(loc, src.getBuffer(), count, 378 dest.getBuffer()); 379 } 380 381 void fir::factory::CharacterExprHelper::createPadding( 382 const fir::CharBoxValue &str, mlir::Value lower, mlir::Value upper) { 383 auto blank = createBlankConstant(getCharacterType(str)); 384 // Always create the loop, if upper < lower, no iteration will be 385 // executed. 386 auto toBuff = getCharBoxBuffer(str); 387 fir::factory::DoLoopHelper{builder, loc}.createLoop( 388 lower, upper, [&](fir::FirOpBuilder &, mlir::Value index) { 389 createStoreCharAt(toBuff, index, blank); 390 }); 391 } 392 393 fir::CharBoxValue 394 fir::factory::CharacterExprHelper::createCharacterTemp(mlir::Type type, 395 mlir::Value len) { 396 auto kind = recoverCharacterType(type).getFKind(); 397 auto typeLen = fir::CharacterType::unknownLen(); 398 // If len is a constant, reflect the length in the type. 399 if (auto cstLen = getIntIfConstant(len)) 400 typeLen = *cstLen; 401 auto *ctxt = builder.getContext(); 402 auto charTy = fir::CharacterType::get(ctxt, kind, typeLen); 403 llvm::SmallVector<mlir::Value> lenParams; 404 if (typeLen == fir::CharacterType::unknownLen()) 405 lenParams.push_back(len); 406 auto ref = builder.allocateLocal(loc, charTy, "", ".chrtmp", 407 /*shape=*/llvm::None, lenParams); 408 return {ref, len}; 409 } 410 411 fir::CharBoxValue fir::factory::CharacterExprHelper::createTempFrom( 412 const fir::ExtendedValue &source) { 413 const auto *charBox = source.getCharBox(); 414 if (!charBox) 415 fir::emitFatalError(loc, "source must be a fir::CharBoxValue"); 416 auto len = charBox->getLen(); 417 auto sourceTy = charBox->getBuffer().getType(); 418 auto temp = createCharacterTemp(sourceTy, len); 419 if (fir::isa_ref_type(sourceTy)) { 420 createCopy(temp, *charBox, len); 421 } else { 422 auto ref = builder.createConvert(loc, builder.getRefType(sourceTy), 423 temp.getBuffer()); 424 builder.create<fir::StoreOp>(loc, charBox->getBuffer(), ref); 425 } 426 return temp; 427 } 428 429 // Simple length one character assignment without loops. 430 void fir::factory::CharacterExprHelper::createLengthOneAssign( 431 const fir::CharBoxValue &lhs, const fir::CharBoxValue &rhs) { 432 auto addr = lhs.getBuffer(); 433 auto toTy = fir::unwrapRefType(addr.getType()); 434 mlir::Value val = rhs.getBuffer(); 435 if (fir::isa_ref_type(val.getType())) 436 val = builder.create<fir::LoadOp>(loc, val); 437 val = builder.createConvert(loc, toTy, val); 438 builder.create<fir::StoreOp>(loc, val, addr); 439 } 440 441 /// Returns the minimum of integer mlir::Value \p a and \b. 442 mlir::Value genMin(fir::FirOpBuilder &builder, mlir::Location loc, 443 mlir::Value a, mlir::Value b) { 444 auto cmp = 445 builder.create<arith::CmpIOp>(loc, arith::CmpIPredicate::slt, a, b); 446 return builder.create<mlir::arith::SelectOp>(loc, cmp, a, b); 447 } 448 449 void fir::factory::CharacterExprHelper::createAssign( 450 const fir::CharBoxValue &lhs, const fir::CharBoxValue &rhs) { 451 auto rhsCstLen = getCompileTimeLength(rhs); 452 auto lhsCstLen = getCompileTimeLength(lhs); 453 bool compileTimeSameLength = 454 lhsCstLen && rhsCstLen && *lhsCstLen == *rhsCstLen; 455 456 if (compileTimeSameLength && *lhsCstLen == 1) { 457 createLengthOneAssign(lhs, rhs); 458 return; 459 } 460 461 // Copy the minimum of the lhs and rhs lengths and pad the lhs remainder 462 // if needed. 463 auto copyCount = lhs.getLen(); 464 auto idxTy = builder.getIndexType(); 465 if (!compileTimeSameLength) { 466 auto lhsLen = builder.createConvert(loc, idxTy, lhs.getLen()); 467 auto rhsLen = builder.createConvert(loc, idxTy, rhs.getLen()); 468 copyCount = genMin(builder, loc, lhsLen, rhsLen); 469 } 470 471 // Actual copy 472 createCopy(lhs, rhs, copyCount); 473 474 // Pad if needed. 475 if (!compileTimeSameLength) { 476 auto one = builder.createIntegerConstant(loc, lhs.getLen().getType(), 1); 477 auto maxPadding = builder.create<arith::SubIOp>(loc, lhs.getLen(), one); 478 createPadding(lhs, copyCount, maxPadding); 479 } 480 } 481 482 fir::CharBoxValue fir::factory::CharacterExprHelper::createConcatenate( 483 const fir::CharBoxValue &lhs, const fir::CharBoxValue &rhs) { 484 auto lhsLen = builder.createConvert(loc, builder.getCharacterLengthType(), 485 lhs.getLen()); 486 auto rhsLen = builder.createConvert(loc, builder.getCharacterLengthType(), 487 rhs.getLen()); 488 mlir::Value len = builder.create<arith::AddIOp>(loc, lhsLen, rhsLen); 489 auto temp = createCharacterTemp(getCharacterType(rhs), len); 490 createCopy(temp, lhs, lhsLen); 491 auto one = builder.createIntegerConstant(loc, len.getType(), 1); 492 auto upperBound = builder.create<arith::SubIOp>(loc, len, one); 493 auto lhsLenIdx = builder.createConvert(loc, builder.getIndexType(), lhsLen); 494 auto fromBuff = getCharBoxBuffer(rhs); 495 auto toBuff = getCharBoxBuffer(temp); 496 fir::factory::DoLoopHelper{builder, loc}.createLoop( 497 lhsLenIdx, upperBound, one, 498 [&](fir::FirOpBuilder &bldr, mlir::Value index) { 499 auto rhsIndex = bldr.create<arith::SubIOp>(loc, index, lhsLenIdx); 500 auto charVal = createLoadCharAt(fromBuff, rhsIndex); 501 createStoreCharAt(toBuff, index, charVal); 502 }); 503 return temp; 504 } 505 506 fir::CharBoxValue fir::factory::CharacterExprHelper::createSubstring( 507 const fir::CharBoxValue &box, llvm::ArrayRef<mlir::Value> bounds) { 508 // Constant need to be materialize in memory to use fir.coordinate_of. 509 auto nbounds = bounds.size(); 510 if (nbounds < 1 || nbounds > 2) { 511 mlir::emitError(loc, "Incorrect number of bounds in substring"); 512 return {mlir::Value{}, mlir::Value{}}; 513 } 514 mlir::SmallVector<mlir::Value> castBounds; 515 // Convert bounds to length type to do safe arithmetic on it. 516 for (auto bound : bounds) 517 castBounds.push_back( 518 builder.createConvert(loc, builder.getCharacterLengthType(), bound)); 519 auto lowerBound = castBounds[0]; 520 // FIR CoordinateOp is zero based but Fortran substring are one based. 521 auto one = builder.createIntegerConstant(loc, lowerBound.getType(), 1); 522 auto offset = builder.create<arith::SubIOp>(loc, lowerBound, one).getResult(); 523 auto addr = createElementAddr(box.getBuffer(), offset); 524 auto kind = getCharacterKind(box.getBuffer().getType()); 525 auto charTy = fir::CharacterType::getUnknownLen(builder.getContext(), kind); 526 auto resultType = builder.getRefType(charTy); 527 auto substringRef = builder.createConvert(loc, resultType, addr); 528 529 // Compute the length. 530 mlir::Value substringLen; 531 if (nbounds < 2) { 532 substringLen = 533 builder.create<arith::SubIOp>(loc, box.getLen(), castBounds[0]); 534 } else { 535 substringLen = 536 builder.create<arith::SubIOp>(loc, castBounds[1], castBounds[0]); 537 } 538 substringLen = builder.create<arith::AddIOp>(loc, substringLen, one); 539 540 // Set length to zero if bounds were reversed (Fortran 2018 9.4.1) 541 auto zero = builder.createIntegerConstant(loc, substringLen.getType(), 0); 542 auto cdt = builder.create<arith::CmpIOp>(loc, arith::CmpIPredicate::slt, 543 substringLen, zero); 544 substringLen = 545 builder.create<mlir::arith::SelectOp>(loc, cdt, zero, substringLen); 546 547 return {substringRef, substringLen}; 548 } 549 550 mlir::Value 551 fir::factory::CharacterExprHelper::createLenTrim(const fir::CharBoxValue &str) { 552 // Note: Runtime for LEN_TRIM should also be available at some 553 // point. For now use an inlined implementation. 554 auto indexType = builder.getIndexType(); 555 auto len = builder.createConvert(loc, indexType, str.getLen()); 556 auto one = builder.createIntegerConstant(loc, indexType, 1); 557 auto minusOne = builder.createIntegerConstant(loc, indexType, -1); 558 auto zero = builder.createIntegerConstant(loc, indexType, 0); 559 auto trueVal = builder.createIntegerConstant(loc, builder.getI1Type(), 1); 560 auto blank = createBlankConstantCode(getCharacterType(str)); 561 mlir::Value lastChar = builder.create<arith::SubIOp>(loc, len, one); 562 563 auto iterWhile = 564 builder.create<fir::IterWhileOp>(loc, lastChar, zero, minusOne, trueVal, 565 /*returnFinalCount=*/false, lastChar); 566 auto insPt = builder.saveInsertionPoint(); 567 builder.setInsertionPointToStart(iterWhile.getBody()); 568 auto index = iterWhile.getInductionVar(); 569 // Look for first non-blank from the right of the character. 570 auto fromBuff = getCharBoxBuffer(str); 571 auto elemAddr = createElementAddr(fromBuff, index); 572 auto codeAddr = 573 builder.createConvert(loc, builder.getRefType(blank.getType()), elemAddr); 574 auto c = builder.create<fir::LoadOp>(loc, codeAddr); 575 auto isBlank = 576 builder.create<arith::CmpIOp>(loc, arith::CmpIPredicate::eq, blank, c); 577 llvm::SmallVector<mlir::Value> results = {isBlank, index}; 578 builder.create<fir::ResultOp>(loc, results); 579 builder.restoreInsertionPoint(insPt); 580 // Compute length after iteration (zero if all blanks) 581 mlir::Value newLen = 582 builder.create<arith::AddIOp>(loc, iterWhile.getResult(1), one); 583 auto result = builder.create<mlir::arith::SelectOp>( 584 loc, iterWhile.getResult(0), zero, newLen); 585 return builder.createConvert(loc, builder.getCharacterLengthType(), result); 586 } 587 588 fir::CharBoxValue 589 fir::factory::CharacterExprHelper::createCharacterTemp(mlir::Type type, 590 int len) { 591 assert(len >= 0 && "expected positive length"); 592 auto kind = recoverCharacterType(type).getFKind(); 593 auto charType = fir::CharacterType::get(builder.getContext(), kind, len); 594 auto addr = builder.create<fir::AllocaOp>(loc, charType); 595 auto mlirLen = 596 builder.createIntegerConstant(loc, builder.getCharacterLengthType(), len); 597 return {addr, mlirLen}; 598 } 599 600 // Returns integer with code for blank. The integer has the same 601 // size as the character. Blank has ascii space code for all kinds. 602 mlir::Value fir::factory::CharacterExprHelper::createBlankConstantCode( 603 fir::CharacterType type) { 604 auto bits = builder.getKindMap().getCharacterBitsize(type.getFKind()); 605 auto intType = builder.getIntegerType(bits); 606 return builder.createIntegerConstant(loc, intType, ' '); 607 } 608 609 mlir::Value fir::factory::CharacterExprHelper::createBlankConstant( 610 fir::CharacterType type) { 611 return createSingletonFromCode(createBlankConstantCode(type), 612 type.getFKind()); 613 } 614 615 void fir::factory::CharacterExprHelper::createAssign( 616 const fir::ExtendedValue &lhs, const fir::ExtendedValue &rhs) { 617 if (auto *str = rhs.getBoxOf<fir::CharBoxValue>()) { 618 if (auto *to = lhs.getBoxOf<fir::CharBoxValue>()) { 619 createAssign(*to, *str); 620 return; 621 } 622 } 623 TODO(loc, "character array assignment"); 624 // Note that it is not sure the array aspect should be handled 625 // by this utility. 626 } 627 628 mlir::Value 629 fir::factory::CharacterExprHelper::createEmboxChar(mlir::Value addr, 630 mlir::Value len) { 631 return createEmbox(fir::CharBoxValue{addr, len}); 632 } 633 634 std::pair<mlir::Value, mlir::Value> 635 fir::factory::CharacterExprHelper::createUnboxChar(mlir::Value boxChar) { 636 using T = std::pair<mlir::Value, mlir::Value>; 637 return toExtendedValue(boxChar).match( 638 [](const fir::CharBoxValue &b) -> T { 639 return {b.getBuffer(), b.getLen()}; 640 }, 641 [](const fir::CharArrayBoxValue &b) -> T { 642 return {b.getBuffer(), b.getLen()}; 643 }, 644 [](const auto &) -> T { llvm::report_fatal_error("not a character"); }); 645 } 646 647 bool fir::factory::CharacterExprHelper::isCharacterLiteral(mlir::Type type) { 648 if (auto seqType = type.dyn_cast<fir::SequenceType>()) 649 return (seqType.getShape().size() == 1) && 650 fir::isa_char(seqType.getEleTy()); 651 return false; 652 } 653 654 bool fir::factory::CharacterExprHelper::isCharacterScalar(mlir::Type type) { 655 if (type.isa<fir::BoxCharType>()) 656 return true; 657 type = fir::unwrapRefType(type); 658 if (auto boxTy = type.dyn_cast<fir::BoxType>()) 659 type = boxTy.getEleTy(); 660 type = fir::unwrapRefType(type); 661 return !type.isa<fir::SequenceType>() && fir::isa_char(type); 662 } 663 664 fir::KindTy 665 fir::factory::CharacterExprHelper::getCharacterKind(mlir::Type type) { 666 assert(isCharacterScalar(type) && "expected scalar character"); 667 return recoverCharacterType(type).getFKind(); 668 } 669 670 fir::KindTy 671 fir::factory::CharacterExprHelper::getCharacterOrSequenceKind(mlir::Type type) { 672 return recoverCharacterType(type).getFKind(); 673 } 674 675 bool fir::factory::CharacterExprHelper::isArray(mlir::Type type) { 676 return !isCharacterScalar(type); 677 } 678 679 bool fir::factory::CharacterExprHelper::hasConstantLengthInType( 680 const fir::ExtendedValue &exv) { 681 auto charTy = recoverCharacterType(fir::getBase(exv).getType()); 682 return charTy.hasConstantLen(); 683 } 684 685 mlir::Value 686 fir::factory::CharacterExprHelper::createSingletonFromCode(mlir::Value code, 687 int kind) { 688 auto charType = fir::CharacterType::get(builder.getContext(), kind, 1); 689 auto bits = builder.getKindMap().getCharacterBitsize(kind); 690 auto intType = builder.getIntegerType(bits); 691 auto cast = builder.createConvert(loc, intType, code); 692 auto undef = builder.create<fir::UndefOp>(loc, charType); 693 auto zero = builder.getIntegerAttr(builder.getIndexType(), 0); 694 return builder.create<fir::InsertValueOp>(loc, charType, undef, cast, 695 builder.getArrayAttr(zero)); 696 } 697 698 mlir::Value fir::factory::CharacterExprHelper::extractCodeFromSingleton( 699 mlir::Value singleton) { 700 auto type = getCharacterType(singleton); 701 assert(type.getLen() == 1); 702 auto bits = builder.getKindMap().getCharacterBitsize(type.getFKind()); 703 auto intType = builder.getIntegerType(bits); 704 auto zero = builder.getIntegerAttr(builder.getIndexType(), 0); 705 return builder.create<fir::ExtractValueOp>(loc, intType, singleton, 706 builder.getArrayAttr(zero)); 707 } 708 709 mlir::Value 710 fir::factory::CharacterExprHelper::readLengthFromBox(mlir::Value box) { 711 auto lenTy = builder.getCharacterLengthType(); 712 auto size = builder.create<fir::BoxEleSizeOp>(loc, lenTy, box); 713 auto charTy = recoverCharacterType(box.getType()); 714 auto bits = builder.getKindMap().getCharacterBitsize(charTy.getFKind()); 715 auto width = bits / 8; 716 if (width > 1) { 717 auto widthVal = builder.createIntegerConstant(loc, lenTy, width); 718 return builder.create<arith::DivSIOp>(loc, size, widthVal); 719 } 720 return size; 721 } 722 723 mlir::Value fir::factory::CharacterExprHelper::getLength(mlir::Value memref) { 724 auto memrefType = memref.getType(); 725 auto charType = recoverCharacterType(memrefType); 726 assert(charType && "must be a character type"); 727 if (charType.hasConstantLen()) 728 return builder.createIntegerConstant(loc, builder.getCharacterLengthType(), 729 charType.getLen()); 730 if (memrefType.isa<fir::BoxType>()) 731 return readLengthFromBox(memref); 732 if (memrefType.isa<fir::BoxCharType>()) 733 return createUnboxChar(memref).second; 734 735 // Length cannot be deduced from memref. 736 return {}; 737 } 738 739 std::pair<mlir::Value, mlir::Value> 740 fir::factory::extractCharacterProcedureTuple(fir::FirOpBuilder &builder, 741 mlir::Location loc, 742 mlir::Value tuple) { 743 mlir::TupleType tupleType = tuple.getType().cast<mlir::TupleType>(); 744 mlir::Value addr = builder.create<fir::ExtractValueOp>( 745 loc, tupleType.getType(0), tuple, 746 builder.getArrayAttr( 747 {builder.getIntegerAttr(builder.getIndexType(), 0)})); 748 mlir::Value len = builder.create<fir::ExtractValueOp>( 749 loc, tupleType.getType(1), tuple, 750 builder.getArrayAttr( 751 {builder.getIntegerAttr(builder.getIndexType(), 1)})); 752 return {addr, len}; 753 } 754 755 mlir::Value fir::factory::createCharacterProcedureTuple( 756 fir::FirOpBuilder &builder, mlir::Location loc, mlir::Type argTy, 757 mlir::Value addr, mlir::Value len) { 758 mlir::TupleType tupleType = argTy.cast<mlir::TupleType>(); 759 addr = builder.createConvert(loc, tupleType.getType(0), addr); 760 len = builder.createConvert(loc, tupleType.getType(1), len); 761 mlir::Value tuple = builder.create<fir::UndefOp>(loc, tupleType); 762 tuple = builder.create<fir::InsertValueOp>( 763 loc, tupleType, tuple, addr, 764 builder.getArrayAttr( 765 {builder.getIntegerAttr(builder.getIndexType(), 0)})); 766 tuple = builder.create<fir::InsertValueOp>( 767 loc, tupleType, tuple, len, 768 builder.getArrayAttr( 769 {builder.getIntegerAttr(builder.getIndexType(), 1)})); 770 return tuple; 771 } 772 773 bool fir::factory::isCharacterProcedureTuple(mlir::Type ty) { 774 mlir::TupleType tuple = ty.dyn_cast<mlir::TupleType>(); 775 return tuple && tuple.size() == 2 && 776 tuple.getType(0).isa<mlir::FunctionType>() && 777 fir::isa_integer(tuple.getType(1)); 778 } 779 780 mlir::Type 781 fir::factory::getCharacterProcedureTupleType(mlir::Type funcPointerType) { 782 mlir::MLIRContext *context = funcPointerType.getContext(); 783 mlir::Type lenType = mlir::IntegerType::get(context, 64); 784 return mlir::TupleType::get(context, {funcPointerType, lenType}); 785 } 786