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