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