1 //===-- Numeric.cpp -- runtime API for numeric intrinsics -----------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "flang/Optimizer/Builder/Runtime/Numeric.h" 10 #include "flang/Optimizer/Builder/BoxValue.h" 11 #include "flang/Optimizer/Builder/Character.h" 12 #include "flang/Optimizer/Builder/FIRBuilder.h" 13 #include "flang/Optimizer/Builder/Runtime/RTBuilder.h" 14 #include "flang/Optimizer/Support/Utils.h" 15 #include "flang/Runtime/numeric.h" 16 #include "mlir/Dialect/Func/IR/FuncOps.h" 17 18 using namespace Fortran::runtime; 19 20 // The real*10 and real*16 placeholders below are used to force the 21 // compilation of the real*10 and real*16 method names on systems that 22 // may not have them in their runtime library. This can occur in the 23 // case of cross compilation, for example. 24 25 /// Placeholder for real*10 version of ErfcScaled Intrinsic 26 struct ForcedErfcScaled10 { 27 static constexpr const char *name = ExpandAndQuoteKey(RTNAME(ErfcScaled10)); 28 static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { 29 return [](mlir::MLIRContext *ctx) { 30 auto ty = mlir::Float80Type::get(ctx); 31 return mlir::FunctionType::get(ctx, {ty}, {ty}); 32 }; 33 } 34 }; 35 36 /// Placeholder for real*16 version of ErfcScaled Intrinsic 37 struct ForcedErfcScaled16 { 38 static constexpr const char *name = ExpandAndQuoteKey(RTNAME(ErfcScaled16)); 39 static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { 40 return [](mlir::MLIRContext *ctx) { 41 auto ty = mlir::Float128Type::get(ctx); 42 return mlir::FunctionType::get(ctx, {ty}, {ty}); 43 }; 44 } 45 }; 46 47 /// Placeholder for real*10 version of Exponent Intrinsic 48 struct ForcedExponent10_4 { 49 static constexpr const char *name = ExpandAndQuoteKey(RTNAME(Exponent10_4)); 50 static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { 51 return [](mlir::MLIRContext *ctx) { 52 auto fltTy = mlir::Float80Type::get(ctx); 53 auto intTy = mlir::IntegerType::get(ctx, 32); 54 return mlir::FunctionType::get(ctx, fltTy, intTy); 55 }; 56 } 57 }; 58 59 struct ForcedExponent10_8 { 60 static constexpr const char *name = ExpandAndQuoteKey(RTNAME(Exponent10_8)); 61 static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { 62 return [](mlir::MLIRContext *ctx) { 63 auto fltTy = mlir::Float80Type::get(ctx); 64 auto intTy = mlir::IntegerType::get(ctx, 64); 65 return mlir::FunctionType::get(ctx, fltTy, intTy); 66 }; 67 } 68 }; 69 70 /// Placeholder for real*16 version of Exponent Intrinsic 71 struct ForcedExponent16_4 { 72 static constexpr const char *name = ExpandAndQuoteKey(RTNAME(Exponent16_4)); 73 static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { 74 return [](mlir::MLIRContext *ctx) { 75 auto fltTy = mlir::Float128Type::get(ctx); 76 auto intTy = mlir::IntegerType::get(ctx, 32); 77 return mlir::FunctionType::get(ctx, fltTy, intTy); 78 }; 79 } 80 }; 81 82 struct ForcedExponent16_8 { 83 static constexpr const char *name = ExpandAndQuoteKey(RTNAME(Exponent16_8)); 84 static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { 85 return [](mlir::MLIRContext *ctx) { 86 auto fltTy = mlir::Float128Type::get(ctx); 87 auto intTy = mlir::IntegerType::get(ctx, 64); 88 return mlir::FunctionType::get(ctx, fltTy, intTy); 89 }; 90 } 91 }; 92 93 /// Placeholder for real*10 version of Fraction Intrinsic 94 struct ForcedFraction10 { 95 static constexpr const char *name = ExpandAndQuoteKey(RTNAME(Fraction10)); 96 static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { 97 return [](mlir::MLIRContext *ctx) { 98 auto ty = mlir::Float80Type::get(ctx); 99 return mlir::FunctionType::get(ctx, {ty}, {ty}); 100 }; 101 } 102 }; 103 104 /// Placeholder for real*16 version of Fraction Intrinsic 105 struct ForcedFraction16 { 106 static constexpr const char *name = ExpandAndQuoteKey(RTNAME(Fraction16)); 107 static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { 108 return [](mlir::MLIRContext *ctx) { 109 auto ty = mlir::Float128Type::get(ctx); 110 return mlir::FunctionType::get(ctx, {ty}, {ty}); 111 }; 112 } 113 }; 114 115 /// Placeholder for real*10 version of Mod Intrinsic 116 struct ForcedMod10 { 117 static constexpr const char *name = ExpandAndQuoteKey(RTNAME(ModReal10)); 118 static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { 119 return [](mlir::MLIRContext *ctx) { 120 auto fltTy = mlir::Float80Type::get(ctx); 121 auto strTy = fir::ReferenceType::get(mlir::IntegerType::get(ctx, 8)); 122 auto intTy = mlir::IntegerType::get(ctx, 8 * sizeof(int)); 123 return mlir::FunctionType::get(ctx, {fltTy, fltTy, strTy, intTy}, 124 {fltTy}); 125 }; 126 } 127 }; 128 129 /// Placeholder for real*16 version of Mod Intrinsic 130 struct ForcedMod16 { 131 static constexpr const char *name = ExpandAndQuoteKey(RTNAME(ModReal16)); 132 static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { 133 return [](mlir::MLIRContext *ctx) { 134 auto fltTy = mlir::Float128Type::get(ctx); 135 auto strTy = fir::ReferenceType::get(mlir::IntegerType::get(ctx, 8)); 136 auto intTy = mlir::IntegerType::get(ctx, 8 * sizeof(int)); 137 return mlir::FunctionType::get(ctx, {fltTy, fltTy, strTy, intTy}, 138 {fltTy}); 139 }; 140 } 141 }; 142 143 /// Placeholder for real*10 version of Modulo Intrinsic 144 struct ForcedModulo10 { 145 static constexpr const char *name = ExpandAndQuoteKey(RTNAME(ModuloReal10)); 146 static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { 147 return [](mlir::MLIRContext *ctx) { 148 auto fltTy = mlir::Float80Type::get(ctx); 149 auto strTy = fir::ReferenceType::get(mlir::IntegerType::get(ctx, 8)); 150 auto intTy = mlir::IntegerType::get(ctx, 8 * sizeof(int)); 151 return mlir::FunctionType::get(ctx, {fltTy, fltTy, strTy, intTy}, 152 {fltTy}); 153 }; 154 } 155 }; 156 157 /// Placeholder for real*16 version of Modulo Intrinsic 158 struct ForcedModulo16 { 159 static constexpr const char *name = ExpandAndQuoteKey(RTNAME(ModuloReal16)); 160 static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { 161 return [](mlir::MLIRContext *ctx) { 162 auto fltTy = mlir::Float128Type::get(ctx); 163 auto strTy = fir::ReferenceType::get(mlir::IntegerType::get(ctx, 8)); 164 auto intTy = mlir::IntegerType::get(ctx, 8 * sizeof(int)); 165 return mlir::FunctionType::get(ctx, {fltTy, fltTy, strTy, intTy}, 166 {fltTy}); 167 }; 168 } 169 }; 170 171 /// Placeholder for real*10 version of Nearest Intrinsic 172 struct ForcedNearest10 { 173 static constexpr const char *name = ExpandAndQuoteKey(RTNAME(Nearest10)); 174 static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { 175 return [](mlir::MLIRContext *ctx) { 176 auto fltTy = mlir::Float80Type::get(ctx); 177 auto boolTy = mlir::IntegerType::get(ctx, 1); 178 return mlir::FunctionType::get(ctx, {fltTy, boolTy}, {fltTy}); 179 }; 180 } 181 }; 182 183 /// Placeholder for real*16 version of Nearest Intrinsic 184 struct ForcedNearest16 { 185 static constexpr const char *name = ExpandAndQuoteKey(RTNAME(Nearest16)); 186 static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { 187 return [](mlir::MLIRContext *ctx) { 188 auto fltTy = mlir::Float128Type::get(ctx); 189 auto boolTy = mlir::IntegerType::get(ctx, 1); 190 return mlir::FunctionType::get(ctx, {fltTy, boolTy}, {fltTy}); 191 }; 192 } 193 }; 194 195 /// Placeholder for real*10 version of RRSpacing Intrinsic 196 struct ForcedRRSpacing10 { 197 static constexpr const char *name = ExpandAndQuoteKey(RTNAME(RRSpacing10)); 198 static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { 199 return [](mlir::MLIRContext *ctx) { 200 auto ty = mlir::Float80Type::get(ctx); 201 return mlir::FunctionType::get(ctx, {ty}, {ty}); 202 }; 203 } 204 }; 205 206 /// Placeholder for real*16 version of RRSpacing Intrinsic 207 struct ForcedRRSpacing16 { 208 static constexpr const char *name = ExpandAndQuoteKey(RTNAME(RRSpacing16)); 209 static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { 210 return [](mlir::MLIRContext *ctx) { 211 auto ty = mlir::Float128Type::get(ctx); 212 return mlir::FunctionType::get(ctx, {ty}, {ty}); 213 }; 214 } 215 }; 216 217 /// Placeholder for real*10 version of Scale Intrinsic 218 struct ForcedScale10 { 219 static constexpr const char *name = ExpandAndQuoteKey(RTNAME(Scale10)); 220 static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { 221 return [](mlir::MLIRContext *ctx) { 222 auto fltTy = mlir::Float80Type::get(ctx); 223 auto intTy = mlir::IntegerType::get(ctx, 64); 224 return mlir::FunctionType::get(ctx, {fltTy, intTy}, {fltTy}); 225 }; 226 } 227 }; 228 229 /// Placeholder for real*16 version of Scale Intrinsic 230 struct ForcedScale16 { 231 static constexpr const char *name = ExpandAndQuoteKey(RTNAME(Scale16)); 232 static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { 233 return [](mlir::MLIRContext *ctx) { 234 auto fltTy = mlir::Float128Type::get(ctx); 235 auto intTy = mlir::IntegerType::get(ctx, 64); 236 return mlir::FunctionType::get(ctx, {fltTy, intTy}, {fltTy}); 237 }; 238 } 239 }; 240 241 /// Placeholder for real*10 version of RRSpacing Intrinsic 242 struct ForcedSetExponent10 { 243 static constexpr const char *name = ExpandAndQuoteKey(RTNAME(SetExponent10)); 244 static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { 245 return [](mlir::MLIRContext *ctx) { 246 auto fltTy = mlir::Float80Type::get(ctx); 247 auto intTy = mlir::IntegerType::get(ctx, 64); 248 return mlir::FunctionType::get(ctx, {fltTy, intTy}, {fltTy}); 249 }; 250 } 251 }; 252 253 /// Placeholder for real*10 version of RRSpacing Intrinsic 254 struct ForcedSetExponent16 { 255 static constexpr const char *name = ExpandAndQuoteKey(RTNAME(SetExponent16)); 256 static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { 257 return [](mlir::MLIRContext *ctx) { 258 auto fltTy = mlir::Float128Type::get(ctx); 259 auto intTy = mlir::IntegerType::get(ctx, 64); 260 return mlir::FunctionType::get(ctx, {fltTy, intTy}, {fltTy}); 261 }; 262 } 263 }; 264 265 /// Placeholder for real*10 version of Spacing Intrinsic 266 struct ForcedSpacing10 { 267 static constexpr const char *name = ExpandAndQuoteKey(RTNAME(Spacing10)); 268 static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { 269 return [](mlir::MLIRContext *ctx) { 270 auto ty = mlir::Float80Type::get(ctx); 271 return mlir::FunctionType::get(ctx, {ty}, {ty}); 272 }; 273 } 274 }; 275 276 /// Placeholder for real*16 version of Spacing Intrinsic 277 struct ForcedSpacing16 { 278 static constexpr const char *name = ExpandAndQuoteKey(RTNAME(Spacing16)); 279 static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { 280 return [](mlir::MLIRContext *ctx) { 281 auto ty = mlir::Float128Type::get(ctx); 282 return mlir::FunctionType::get(ctx, {ty}, {ty}); 283 }; 284 } 285 }; 286 287 /// Generate call to Exponent intrinsic runtime routine. 288 mlir::Value fir::runtime::genExponent(fir::FirOpBuilder &builder, 289 mlir::Location loc, mlir::Type resultType, 290 mlir::Value x) { 291 mlir::func::FuncOp func; 292 mlir::Type fltTy = x.getType(); 293 if (fltTy.isF32()) { 294 if (resultType.isInteger(32)) 295 func = fir::runtime::getRuntimeFunc<mkRTKey(Exponent4_4)>(loc, builder); 296 else if (resultType.isInteger(64)) 297 func = fir::runtime::getRuntimeFunc<mkRTKey(Exponent4_8)>(loc, builder); 298 } else if (fltTy.isF64()) { 299 if (resultType.isInteger(32)) 300 func = fir::runtime::getRuntimeFunc<mkRTKey(Exponent8_4)>(loc, builder); 301 else if (resultType.isInteger(64)) 302 func = fir::runtime::getRuntimeFunc<mkRTKey(Exponent8_8)>(loc, builder); 303 } else if (fltTy.isF80()) { 304 if (resultType.isInteger(32)) 305 func = fir::runtime::getRuntimeFunc<ForcedExponent10_4>(loc, builder); 306 else if (resultType.isInteger(64)) 307 func = fir::runtime::getRuntimeFunc<ForcedExponent10_8>(loc, builder); 308 } else if (fltTy.isF128()) { 309 if (resultType.isInteger(32)) 310 func = fir::runtime::getRuntimeFunc<ForcedExponent16_4>(loc, builder); 311 else if (resultType.isInteger(64)) 312 func = fir::runtime::getRuntimeFunc<ForcedExponent16_8>(loc, builder); 313 } else 314 fir::intrinsicTypeTODO(builder, fltTy, loc, "EXPONENT"); 315 316 auto funcTy = func.getFunctionType(); 317 llvm::SmallVector<mlir::Value> args = { 318 builder.createConvert(loc, funcTy.getInput(0), x)}; 319 320 return builder.create<fir::CallOp>(loc, func, args).getResult(0); 321 } 322 323 /// Generate call to Fraction intrinsic runtime routine. 324 mlir::Value fir::runtime::genFraction(fir::FirOpBuilder &builder, 325 mlir::Location loc, mlir::Value x) { 326 mlir::func::FuncOp func; 327 mlir::Type fltTy = x.getType(); 328 if (fltTy.isF32()) 329 func = fir::runtime::getRuntimeFunc<mkRTKey(Fraction4)>(loc, builder); 330 else if (fltTy.isF64()) 331 func = fir::runtime::getRuntimeFunc<mkRTKey(Fraction8)>(loc, builder); 332 else if (fltTy.isF80()) 333 func = fir::runtime::getRuntimeFunc<ForcedFraction10>(loc, builder); 334 else if (fltTy.isF128()) 335 func = fir::runtime::getRuntimeFunc<ForcedFraction16>(loc, builder); 336 else 337 fir::intrinsicTypeTODO(builder, fltTy, loc, "FRACTION"); 338 339 auto funcTy = func.getFunctionType(); 340 llvm::SmallVector<mlir::Value> args = { 341 builder.createConvert(loc, funcTy.getInput(0), x)}; 342 343 return builder.create<fir::CallOp>(loc, func, args).getResult(0); 344 } 345 346 /// Generate call to Mod intrinsic runtime routine. 347 mlir::Value fir::runtime::genMod(fir::FirOpBuilder &builder, mlir::Location loc, 348 mlir::Value a, mlir::Value p) { 349 mlir::func::FuncOp func; 350 mlir::Type fltTy = a.getType(); 351 352 if (fltTy != p.getType()) 353 fir::emitFatalError(loc, "arguments type mismatch in MOD"); 354 355 if (fltTy.isF32()) 356 func = fir::runtime::getRuntimeFunc<mkRTKey(ModReal4)>(loc, builder); 357 else if (fltTy.isF64()) 358 func = fir::runtime::getRuntimeFunc<mkRTKey(ModReal8)>(loc, builder); 359 else if (fltTy.isF80()) 360 func = fir::runtime::getRuntimeFunc<ForcedMod10>(loc, builder); 361 else if (fltTy.isF128()) 362 func = fir::runtime::getRuntimeFunc<ForcedMod16>(loc, builder); 363 else 364 fir::intrinsicTypeTODO(builder, fltTy, loc, "MOD"); 365 366 auto funcTy = func.getFunctionType(); 367 auto sourceFile = fir::factory::locationToFilename(builder, loc); 368 auto sourceLine = 369 fir::factory::locationToLineNo(builder, loc, funcTy.getInput(3)); 370 auto args = fir::runtime::createArguments(builder, loc, funcTy, a, p, 371 sourceFile, sourceLine); 372 373 return builder.create<fir::CallOp>(loc, func, args).getResult(0); 374 } 375 376 /// Generate call to Modulo intrinsic runtime routine. 377 mlir::Value fir::runtime::genModulo(fir::FirOpBuilder &builder, 378 mlir::Location loc, mlir::Value a, 379 mlir::Value p) { 380 mlir::func::FuncOp func; 381 mlir::Type fltTy = a.getType(); 382 383 if (fltTy != p.getType()) 384 fir::emitFatalError(loc, "arguments type mismatch in MOD"); 385 386 // MODULO is lowered into math operations in intrinsics lowering, 387 // so genModulo() should only be used for F128 data type now. 388 if (fltTy.isF32()) 389 func = fir::runtime::getRuntimeFunc<mkRTKey(ModuloReal4)>(loc, builder); 390 else if (fltTy.isF64()) 391 func = fir::runtime::getRuntimeFunc<mkRTKey(ModuloReal8)>(loc, builder); 392 else if (fltTy.isF80()) 393 func = fir::runtime::getRuntimeFunc<ForcedModulo10>(loc, builder); 394 else if (fltTy.isF128()) 395 func = fir::runtime::getRuntimeFunc<ForcedModulo16>(loc, builder); 396 else 397 fir::intrinsicTypeTODO(builder, fltTy, loc, "MODULO"); 398 399 auto funcTy = func.getFunctionType(); 400 auto sourceFile = fir::factory::locationToFilename(builder, loc); 401 auto sourceLine = 402 fir::factory::locationToLineNo(builder, loc, funcTy.getInput(3)); 403 auto args = fir::runtime::createArguments(builder, loc, funcTy, a, p, 404 sourceFile, sourceLine); 405 406 return builder.create<fir::CallOp>(loc, func, args).getResult(0); 407 } 408 409 /// Generate call to Nearest intrinsic or a "Next" intrinsic module procedure. 410 mlir::Value fir::runtime::genNearest(fir::FirOpBuilder &builder, 411 mlir::Location loc, mlir::Value x, 412 mlir::Value valueUp) { 413 mlir::func::FuncOp func; 414 mlir::Type fltTy = x.getType(); 415 416 if (fltTy.isF32()) 417 func = fir::runtime::getRuntimeFunc<mkRTKey(Nearest4)>(loc, builder); 418 else if (fltTy.isF64()) 419 func = fir::runtime::getRuntimeFunc<mkRTKey(Nearest8)>(loc, builder); 420 else if (fltTy.isF80()) 421 func = fir::runtime::getRuntimeFunc<ForcedNearest10>(loc, builder); 422 else if (fltTy.isF128()) 423 func = fir::runtime::getRuntimeFunc<ForcedNearest16>(loc, builder); 424 else 425 fir::intrinsicTypeTODO(builder, fltTy, loc, "NEAREST"); 426 427 auto funcTy = func.getFunctionType(); 428 auto args = fir::runtime::createArguments(builder, loc, funcTy, x, valueUp); 429 430 return builder.create<fir::CallOp>(loc, func, args).getResult(0); 431 } 432 433 /// Generate call to RRSpacing intrinsic runtime routine. 434 mlir::Value fir::runtime::genRRSpacing(fir::FirOpBuilder &builder, 435 mlir::Location loc, mlir::Value x) { 436 mlir::func::FuncOp func; 437 mlir::Type fltTy = x.getType(); 438 439 if (fltTy.isF32()) 440 func = fir::runtime::getRuntimeFunc<mkRTKey(RRSpacing4)>(loc, builder); 441 else if (fltTy.isF64()) 442 func = fir::runtime::getRuntimeFunc<mkRTKey(RRSpacing8)>(loc, builder); 443 else if (fltTy.isF80()) 444 func = fir::runtime::getRuntimeFunc<ForcedRRSpacing10>(loc, builder); 445 else if (fltTy.isF128()) 446 func = fir::runtime::getRuntimeFunc<ForcedRRSpacing16>(loc, builder); 447 else 448 fir::intrinsicTypeTODO(builder, fltTy, loc, "RRSPACING"); 449 450 auto funcTy = func.getFunctionType(); 451 llvm::SmallVector<mlir::Value> args = { 452 builder.createConvert(loc, funcTy.getInput(0), x)}; 453 454 return builder.create<fir::CallOp>(loc, func, args).getResult(0); 455 } 456 457 /// Generate call to ErfcScaled intrinsic runtime routine. 458 mlir::Value fir::runtime::genErfcScaled(fir::FirOpBuilder &builder, 459 mlir::Location loc, mlir::Value x) { 460 mlir::func::FuncOp func; 461 mlir::Type fltTy = x.getType(); 462 463 if (fltTy.isF32()) 464 func = fir::runtime::getRuntimeFunc<mkRTKey(ErfcScaled4)>(loc, builder); 465 else if (fltTy.isF64()) 466 func = fir::runtime::getRuntimeFunc<mkRTKey(ErfcScaled8)>(loc, builder); 467 else if (fltTy.isF80()) 468 func = fir::runtime::getRuntimeFunc<ForcedErfcScaled10>(loc, builder); 469 else if (fltTy.isF128()) 470 func = fir::runtime::getRuntimeFunc<ForcedErfcScaled16>(loc, builder); 471 else 472 fir::intrinsicTypeTODO(builder, fltTy, loc, "ERFC_SCALED"); 473 474 auto funcTy = func.getFunctionType(); 475 llvm::SmallVector<mlir::Value> args = { 476 builder.createConvert(loc, funcTy.getInput(0), x)}; 477 478 return builder.create<fir::CallOp>(loc, func, args).getResult(0); 479 } 480 481 /// Generate call to Scale intrinsic runtime routine. 482 mlir::Value fir::runtime::genScale(fir::FirOpBuilder &builder, 483 mlir::Location loc, mlir::Value x, 484 mlir::Value i) { 485 mlir::func::FuncOp func; 486 mlir::Type fltTy = x.getType(); 487 488 if (fltTy.isF32()) 489 func = fir::runtime::getRuntimeFunc<mkRTKey(Scale4)>(loc, builder); 490 else if (fltTy.isF64()) 491 func = fir::runtime::getRuntimeFunc<mkRTKey(Scale8)>(loc, builder); 492 else if (fltTy.isF80()) 493 func = fir::runtime::getRuntimeFunc<ForcedScale10>(loc, builder); 494 else if (fltTy.isF128()) 495 func = fir::runtime::getRuntimeFunc<ForcedScale16>(loc, builder); 496 else 497 fir::intrinsicTypeTODO(builder, fltTy, loc, "SCALE"); 498 499 auto funcTy = func.getFunctionType(); 500 auto args = fir::runtime::createArguments(builder, loc, funcTy, x, i); 501 502 return builder.create<fir::CallOp>(loc, func, args).getResult(0); 503 } 504 505 /// Generate call to Selected_char_kind intrinsic runtime routine. 506 mlir::Value fir::runtime::genSelectedCharKind(fir::FirOpBuilder &builder, 507 mlir::Location loc, 508 mlir::Value name, 509 mlir::Value length) { 510 mlir::func::FuncOp func = 511 fir::runtime::getRuntimeFunc<mkRTKey(SelectedCharKind)>(loc, builder); 512 auto fTy = func.getFunctionType(); 513 auto sourceFile = fir::factory::locationToFilename(builder, loc); 514 auto sourceLine = 515 fir::factory::locationToLineNo(builder, loc, fTy.getInput(1)); 516 if (!fir::isa_ref_type(name.getType())) 517 fir::emitFatalError(loc, "argument address for runtime not found"); 518 519 auto args = fir::runtime::createArguments(builder, loc, fTy, sourceFile, 520 sourceLine, name, length); 521 522 return builder.create<fir::CallOp>(loc, func, args).getResult(0); 523 } 524 525 /// Generate call to Selected_int_kind intrinsic runtime routine. 526 mlir::Value fir::runtime::genSelectedIntKind(fir::FirOpBuilder &builder, 527 mlir::Location loc, 528 mlir::Value x) { 529 mlir::func::FuncOp func = 530 fir::runtime::getRuntimeFunc<mkRTKey(SelectedIntKind)>(loc, builder); 531 auto fTy = func.getFunctionType(); 532 auto sourceFile = fir::factory::locationToFilename(builder, loc); 533 auto sourceLine = 534 fir::factory::locationToLineNo(builder, loc, fTy.getInput(1)); 535 if (!fir::isa_ref_type(x.getType())) 536 fir::emitFatalError(loc, "argument address for runtime not found"); 537 mlir::Type eleTy = fir::unwrapRefType(x.getType()); 538 mlir::Value xKind = builder.createIntegerConstant( 539 loc, fTy.getInput(3), eleTy.getIntOrFloatBitWidth() / 8); 540 auto args = fir::runtime::createArguments(builder, loc, fTy, sourceFile, 541 sourceLine, x, xKind); 542 543 return builder.create<fir::CallOp>(loc, func, args).getResult(0); 544 } 545 546 /// Generate call to Selected_logical_kind intrinsic runtime routine. 547 mlir::Value fir::runtime::genSelectedLogicalKind(fir::FirOpBuilder &builder, 548 mlir::Location loc, 549 mlir::Value x) { 550 mlir::func::FuncOp func = 551 fir::runtime::getRuntimeFunc<mkRTKey(SelectedLogicalKind)>(loc, builder); 552 auto fTy = func.getFunctionType(); 553 auto sourceFile = fir::factory::locationToFilename(builder, loc); 554 auto sourceLine = 555 fir::factory::locationToLineNo(builder, loc, fTy.getInput(1)); 556 if (!fir::isa_ref_type(x.getType())) 557 fir::emitFatalError(loc, "argument address for runtime not found"); 558 mlir::Type eleTy = fir::unwrapRefType(x.getType()); 559 mlir::Value xKind = builder.createIntegerConstant( 560 loc, fTy.getInput(3), eleTy.getIntOrFloatBitWidth() / 8); 561 auto args = fir::runtime::createArguments(builder, loc, fTy, sourceFile, 562 sourceLine, x, xKind); 563 564 return builder.create<fir::CallOp>(loc, func, args).getResult(0); 565 } 566 567 /// Generate call to Selected_real_kind intrinsic runtime routine. 568 mlir::Value fir::runtime::genSelectedRealKind(fir::FirOpBuilder &builder, 569 mlir::Location loc, 570 mlir::Value precision, 571 mlir::Value range, 572 mlir::Value radix) { 573 mlir::func::FuncOp func = 574 fir::runtime::getRuntimeFunc<mkRTKey(SelectedRealKind)>(loc, builder); 575 auto fTy = func.getFunctionType(); 576 auto getArgKinds = [&](mlir::Value arg, int argKindIndex) -> mlir::Value { 577 if (fir::isa_ref_type(arg.getType())) { 578 mlir::Type eleTy = fir::unwrapRefType(arg.getType()); 579 return builder.createIntegerConstant(loc, fTy.getInput(argKindIndex), 580 eleTy.getIntOrFloatBitWidth() / 8); 581 } else { 582 return builder.createIntegerConstant(loc, fTy.getInput(argKindIndex), 0); 583 } 584 }; 585 586 auto sourceFile = fir::factory::locationToFilename(builder, loc); 587 auto sourceLine = 588 fir::factory::locationToLineNo(builder, loc, fTy.getInput(1)); 589 mlir::Value pKind = getArgKinds(precision, 3); 590 mlir::Value rKind = getArgKinds(range, 5); 591 mlir::Value dKind = getArgKinds(radix, 7); 592 auto args = fir::runtime::createArguments(builder, loc, fTy, sourceFile, 593 sourceLine, precision, pKind, range, 594 rKind, radix, dKind); 595 596 return builder.create<fir::CallOp>(loc, func, args).getResult(0); 597 } 598 599 /// Generate call to Set_exponent intrinsic runtime routine. 600 mlir::Value fir::runtime::genSetExponent(fir::FirOpBuilder &builder, 601 mlir::Location loc, mlir::Value x, 602 mlir::Value i) { 603 mlir::func::FuncOp func; 604 mlir::Type fltTy = x.getType(); 605 606 if (fltTy.isF32()) 607 func = fir::runtime::getRuntimeFunc<mkRTKey(SetExponent4)>(loc, builder); 608 else if (fltTy.isF64()) 609 func = fir::runtime::getRuntimeFunc<mkRTKey(SetExponent8)>(loc, builder); 610 else if (fltTy.isF80()) 611 func = fir::runtime::getRuntimeFunc<ForcedSetExponent10>(loc, builder); 612 else if (fltTy.isF128()) 613 func = fir::runtime::getRuntimeFunc<ForcedSetExponent16>(loc, builder); 614 else 615 fir::intrinsicTypeTODO(builder, fltTy, loc, "SET_EXPONENT"); 616 617 auto funcTy = func.getFunctionType(); 618 auto args = fir::runtime::createArguments(builder, loc, funcTy, x, i); 619 620 return builder.create<fir::CallOp>(loc, func, args).getResult(0); 621 } 622 623 /// Generate call to Spacing intrinsic runtime routine. 624 mlir::Value fir::runtime::genSpacing(fir::FirOpBuilder &builder, 625 mlir::Location loc, mlir::Value x) { 626 mlir::func::FuncOp func; 627 mlir::Type fltTy = x.getType(); 628 // TODO: for f16/bf16, there are better alternatives that do not require 629 // casting the argument (resp. result) to (resp. from) f32, but this requires 630 // knowing that the target runtime has been compiled with std::float16_t or 631 // std::bfloat16_t support, which is not an information available here for 632 // now. 633 if (fltTy.isF32()) 634 func = fir::runtime::getRuntimeFunc<mkRTKey(Spacing4)>(loc, builder); 635 else if (fltTy.isF64()) 636 func = fir::runtime::getRuntimeFunc<mkRTKey(Spacing8)>(loc, builder); 637 else if (fltTy.isF80()) 638 func = fir::runtime::getRuntimeFunc<ForcedSpacing10>(loc, builder); 639 else if (fltTy.isF128()) 640 func = fir::runtime::getRuntimeFunc<ForcedSpacing16>(loc, builder); 641 else if (fltTy.isF16()) 642 func = fir::runtime::getRuntimeFunc<mkRTKey(Spacing2By4)>(loc, builder); 643 else if (fltTy.isBF16()) 644 func = fir::runtime::getRuntimeFunc<mkRTKey(Spacing3By4)>(loc, builder); 645 else 646 fir::intrinsicTypeTODO(builder, fltTy, loc, "SPACING"); 647 648 auto funcTy = func.getFunctionType(); 649 llvm::SmallVector<mlir::Value> args = { 650 builder.createConvert(loc, funcTy.getInput(0), x)}; 651 652 mlir::Value res = builder.create<fir::CallOp>(loc, func, args).getResult(0); 653 return builder.createConvert(loc, fltTy, res); 654 } 655