| //===-- Character.cpp -- runtime for CHARACTER type entities --------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "flang/Optimizer/Builder/Runtime/Character.h" |
| #include "flang/Optimizer/Builder/BoxValue.h" |
| #include "flang/Optimizer/Builder/Character.h" |
| #include "flang/Optimizer/Builder/FIRBuilder.h" |
| #include "flang/Optimizer/Builder/Runtime/RTBuilder.h" |
| #include "flang/Optimizer/Builder/Todo.h" |
| #include "flang/Runtime/character.h" |
| #include "mlir/Dialect/Func/IR/FuncOps.h" |
| |
| using namespace Fortran::runtime; |
| |
| /// Generate calls to string handling intrinsics such as index, scan, and |
| /// verify. These are the descriptor based implementations that take four |
| /// arguments (string1, string2, back, kind). |
| template <typename FN> |
| static void genCharacterSearch(FN func, fir::FirOpBuilder &builder, |
| mlir::Location loc, mlir::Value resultBox, |
| mlir::Value string1Box, mlir::Value string2Box, |
| mlir::Value backBox, mlir::Value kind) { |
| |
| auto fTy = func.getFunctionType(); |
| auto sourceFile = fir::factory::locationToFilename(builder, loc); |
| auto sourceLine = |
| fir::factory::locationToLineNo(builder, loc, fTy.getInput(6)); |
| |
| auto args = fir::runtime::createArguments(builder, loc, fTy, resultBox, |
| string1Box, string2Box, backBox, |
| kind, sourceFile, sourceLine); |
| builder.create<fir::CallOp>(loc, func, args); |
| } |
| |
| /// Helper function to recover the KIND from the FIR type. |
| static int discoverKind(mlir::Type ty) { |
| if (auto charTy = mlir::dyn_cast<fir::CharacterType>(ty)) |
| return charTy.getFKind(); |
| if (auto eleTy = fir::dyn_cast_ptrEleTy(ty)) |
| return discoverKind(eleTy); |
| if (auto arrTy = mlir::dyn_cast<fir::SequenceType>(ty)) |
| return discoverKind(arrTy.getEleTy()); |
| if (auto boxTy = mlir::dyn_cast<fir::BoxCharType>(ty)) |
| return discoverKind(boxTy.getEleTy()); |
| if (auto boxTy = mlir::dyn_cast<fir::BoxType>(ty)) |
| return discoverKind(boxTy.getEleTy()); |
| llvm_unreachable("unexpected character type"); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Lower character operations |
| //===----------------------------------------------------------------------===// |
| |
| /// Generate a call to the `ADJUST[L|R]` runtime. |
| /// |
| /// \p resultBox must be an unallocated allocatable used for the temporary |
| /// result. \p StringBox must be a fir.box describing the adjustr string |
| /// argument. The \p adjustFunc should be a mlir::func::FuncOp for the |
| /// appropriate runtime entry function. |
| static void genAdjust(fir::FirOpBuilder &builder, mlir::Location loc, |
| mlir::Value resultBox, mlir::Value stringBox, |
| mlir::func::FuncOp &adjustFunc) { |
| |
| auto fTy = adjustFunc.getFunctionType(); |
| auto sourceLine = |
| fir::factory::locationToLineNo(builder, loc, fTy.getInput(3)); |
| auto sourceFile = fir::factory::locationToFilename(builder, loc); |
| auto args = fir::runtime::createArguments(builder, loc, fTy, resultBox, |
| stringBox, sourceFile, sourceLine); |
| builder.create<fir::CallOp>(loc, adjustFunc, args); |
| } |
| |
| void fir::runtime::genAdjustL(fir::FirOpBuilder &builder, mlir::Location loc, |
| mlir::Value resultBox, mlir::Value stringBox) { |
| auto adjustFunc = |
| fir::runtime::getRuntimeFunc<mkRTKey(Adjustl)>(loc, builder); |
| genAdjust(builder, loc, resultBox, stringBox, adjustFunc); |
| } |
| |
| void fir::runtime::genAdjustR(fir::FirOpBuilder &builder, mlir::Location loc, |
| mlir::Value resultBox, mlir::Value stringBox) { |
| auto adjustFunc = |
| fir::runtime::getRuntimeFunc<mkRTKey(Adjustr)>(loc, builder); |
| genAdjust(builder, loc, resultBox, stringBox, adjustFunc); |
| } |
| |
| mlir::Value |
| fir::runtime::genCharCompare(fir::FirOpBuilder &builder, mlir::Location loc, |
| mlir::arith::CmpIPredicate cmp, |
| mlir::Value lhsBuff, mlir::Value lhsLen, |
| mlir::Value rhsBuff, mlir::Value rhsLen) { |
| mlir::func::FuncOp beginFunc; |
| switch (discoverKind(lhsBuff.getType())) { |
| case 1: |
| beginFunc = fir::runtime::getRuntimeFunc<mkRTKey(CharacterCompareScalar1)>( |
| loc, builder); |
| break; |
| case 2: |
| beginFunc = fir::runtime::getRuntimeFunc<mkRTKey(CharacterCompareScalar2)>( |
| loc, builder); |
| break; |
| case 4: |
| beginFunc = fir::runtime::getRuntimeFunc<mkRTKey(CharacterCompareScalar4)>( |
| loc, builder); |
| break; |
| default: |
| llvm_unreachable("runtime does not support CHARACTER KIND"); |
| } |
| auto fTy = beginFunc.getFunctionType(); |
| auto args = fir::runtime::createArguments(builder, loc, fTy, lhsBuff, rhsBuff, |
| lhsLen, rhsLen); |
| auto tri = builder.create<fir::CallOp>(loc, beginFunc, args).getResult(0); |
| auto zero = builder.createIntegerConstant(loc, tri.getType(), 0); |
| return builder.create<mlir::arith::CmpIOp>(loc, cmp, tri, zero); |
| } |
| |
| mlir::Value fir::runtime::genCharCompare(fir::FirOpBuilder &builder, |
| mlir::Location loc, |
| mlir::arith::CmpIPredicate cmp, |
| const fir::ExtendedValue &lhs, |
| const fir::ExtendedValue &rhs) { |
| if (lhs.getBoxOf<fir::BoxValue>() || rhs.getBoxOf<fir::BoxValue>()) |
| TODO(loc, "character compare from descriptors"); |
| auto allocateIfNotInMemory = [&](mlir::Value base) -> mlir::Value { |
| if (fir::isa_ref_type(base.getType())) |
| return base; |
| auto mem = |
| builder.create<fir::AllocaOp>(loc, base.getType(), /*pinned=*/false); |
| builder.create<fir::StoreOp>(loc, base, mem); |
| return mem; |
| }; |
| auto lhsBuffer = allocateIfNotInMemory(fir::getBase(lhs)); |
| auto rhsBuffer = allocateIfNotInMemory(fir::getBase(rhs)); |
| return genCharCompare(builder, loc, cmp, lhsBuffer, fir::getLen(lhs), |
| rhsBuffer, fir::getLen(rhs)); |
| } |
| |
| mlir::Value fir::runtime::genIndex(fir::FirOpBuilder &builder, |
| mlir::Location loc, int kind, |
| mlir::Value stringBase, |
| mlir::Value stringLen, |
| mlir::Value substringBase, |
| mlir::Value substringLen, mlir::Value back) { |
| mlir::func::FuncOp indexFunc; |
| switch (kind) { |
| case 1: |
| indexFunc = fir::runtime::getRuntimeFunc<mkRTKey(Index1)>(loc, builder); |
| break; |
| case 2: |
| indexFunc = fir::runtime::getRuntimeFunc<mkRTKey(Index2)>(loc, builder); |
| break; |
| case 4: |
| indexFunc = fir::runtime::getRuntimeFunc<mkRTKey(Index4)>(loc, builder); |
| break; |
| default: |
| fir::emitFatalError( |
| loc, "unsupported CHARACTER kind value. Runtime expects 1, 2, or 4."); |
| } |
| auto fTy = indexFunc.getFunctionType(); |
| auto args = |
| fir::runtime::createArguments(builder, loc, fTy, stringBase, stringLen, |
| substringBase, substringLen, back); |
| return builder.create<fir::CallOp>(loc, indexFunc, args).getResult(0); |
| } |
| |
| void fir::runtime::genIndexDescriptor(fir::FirOpBuilder &builder, |
| mlir::Location loc, mlir::Value resultBox, |
| mlir::Value stringBox, |
| mlir::Value substringBox, |
| mlir::Value backOpt, mlir::Value kind) { |
| auto indexFunc = fir::runtime::getRuntimeFunc<mkRTKey(Index)>(loc, builder); |
| genCharacterSearch(indexFunc, builder, loc, resultBox, stringBox, |
| substringBox, backOpt, kind); |
| } |
| |
| void fir::runtime::genRepeat(fir::FirOpBuilder &builder, mlir::Location loc, |
| mlir::Value resultBox, mlir::Value stringBox, |
| mlir::Value ncopies) { |
| auto repeatFunc = fir::runtime::getRuntimeFunc<mkRTKey(Repeat)>(loc, builder); |
| auto fTy = repeatFunc.getFunctionType(); |
| auto sourceFile = fir::factory::locationToFilename(builder, loc); |
| auto sourceLine = |
| fir::factory::locationToLineNo(builder, loc, fTy.getInput(4)); |
| |
| auto args = fir::runtime::createArguments( |
| builder, loc, fTy, resultBox, stringBox, ncopies, sourceFile, sourceLine); |
| builder.create<fir::CallOp>(loc, repeatFunc, args); |
| } |
| |
| void fir::runtime::genTrim(fir::FirOpBuilder &builder, mlir::Location loc, |
| mlir::Value resultBox, mlir::Value stringBox) { |
| auto trimFunc = fir::runtime::getRuntimeFunc<mkRTKey(Trim)>(loc, builder); |
| auto fTy = trimFunc.getFunctionType(); |
| auto sourceFile = fir::factory::locationToFilename(builder, loc); |
| auto sourceLine = |
| fir::factory::locationToLineNo(builder, loc, fTy.getInput(3)); |
| |
| auto args = fir::runtime::createArguments(builder, loc, fTy, resultBox, |
| stringBox, sourceFile, sourceLine); |
| builder.create<fir::CallOp>(loc, trimFunc, args); |
| } |
| |
| void fir::runtime::genScanDescriptor(fir::FirOpBuilder &builder, |
| mlir::Location loc, mlir::Value resultBox, |
| mlir::Value stringBox, mlir::Value setBox, |
| mlir::Value backBox, mlir::Value kind) { |
| auto func = fir::runtime::getRuntimeFunc<mkRTKey(Scan)>(loc, builder); |
| genCharacterSearch(func, builder, loc, resultBox, stringBox, setBox, backBox, |
| kind); |
| } |
| |
| mlir::Value fir::runtime::genScan(fir::FirOpBuilder &builder, |
| mlir::Location loc, int kind, |
| mlir::Value stringBase, mlir::Value stringLen, |
| mlir::Value setBase, mlir::Value setLen, |
| mlir::Value back) { |
| mlir::func::FuncOp func; |
| switch (kind) { |
| case 1: |
| func = fir::runtime::getRuntimeFunc<mkRTKey(Scan1)>(loc, builder); |
| break; |
| case 2: |
| func = fir::runtime::getRuntimeFunc<mkRTKey(Scan2)>(loc, builder); |
| break; |
| case 4: |
| func = fir::runtime::getRuntimeFunc<mkRTKey(Scan4)>(loc, builder); |
| break; |
| default: |
| fir::emitFatalError( |
| loc, "unsupported CHARACTER kind value. Runtime expects 1, 2, or 4."); |
| } |
| auto fTy = func.getFunctionType(); |
| auto args = fir::runtime::createArguments(builder, loc, fTy, stringBase, |
| stringLen, setBase, setLen, back); |
| return builder.create<fir::CallOp>(loc, func, args).getResult(0); |
| } |
| |
| void fir::runtime::genVerifyDescriptor(fir::FirOpBuilder &builder, |
| mlir::Location loc, |
| mlir::Value resultBox, |
| mlir::Value stringBox, |
| mlir::Value setBox, mlir::Value backBox, |
| mlir::Value kind) { |
| auto func = fir::runtime::getRuntimeFunc<mkRTKey(Verify)>(loc, builder); |
| genCharacterSearch(func, builder, loc, resultBox, stringBox, setBox, backBox, |
| kind); |
| } |
| |
| mlir::Value fir::runtime::genVerify(fir::FirOpBuilder &builder, |
| mlir::Location loc, int kind, |
| mlir::Value stringBase, |
| mlir::Value stringLen, mlir::Value setBase, |
| mlir::Value setLen, mlir::Value back) { |
| mlir::func::FuncOp func; |
| switch (kind) { |
| case 1: |
| func = fir::runtime::getRuntimeFunc<mkRTKey(Verify1)>(loc, builder); |
| break; |
| case 2: |
| func = fir::runtime::getRuntimeFunc<mkRTKey(Verify2)>(loc, builder); |
| break; |
| case 4: |
| func = fir::runtime::getRuntimeFunc<mkRTKey(Verify4)>(loc, builder); |
| break; |
| default: |
| fir::emitFatalError( |
| loc, "unsupported CHARACTER kind value. Runtime expects 1, 2, or 4."); |
| } |
| auto fTy = func.getFunctionType(); |
| auto args = fir::runtime::createArguments(builder, loc, fTy, stringBase, |
| stringLen, setBase, setLen, back); |
| return builder.create<fir::CallOp>(loc, func, args).getResult(0); |
| } |