@@ -453,8 +453,12 @@ struct IntrinsicLibrary {
453
453
fir::ExtendedValue genDotProduct (mlir::Type,
454
454
llvm::ArrayRef<fir::ExtendedValue>);
455
455
fir::ExtendedValue genEoshift (mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
456
+ mlir::Value genExponent (mlir::Type, llvm::ArrayRef<mlir::Value>);
456
457
template <Extremum, ExtremumBehavior>
457
458
mlir::Value genExtremum (mlir::Type, llvm::ArrayRef<mlir::Value>);
459
+ mlir::Value genFloor (mlir::Type, llvm::ArrayRef<mlir::Value>);
460
+ mlir::Value genFraction (mlir::Type resultType,
461
+ mlir::ArrayRef<mlir::Value> args);
458
462
// / Lowering for the IAND intrinsic. The IAND intrinsic expects two arguments
459
463
// / in the llvm::ArrayRef.
460
464
mlir::Value genIand (mlir::Type, llvm::ArrayRef<mlir::Value>);
@@ -466,13 +470,18 @@ struct IntrinsicLibrary {
466
470
mlir::Value genIshft (mlir::Type, llvm::ArrayRef<mlir::Value>);
467
471
mlir::Value genIshftc (mlir::Type, llvm::ArrayRef<mlir::Value>);
468
472
fir::ExtendedValue genLbound (mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
469
- fir::ExtendedValue genNull (mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
470
473
fir::ExtendedValue genLen (mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
471
474
fir::ExtendedValue genLenTrim (mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
472
475
fir::ExtendedValue genMaxloc (mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
473
476
fir::ExtendedValue genMaxval (mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
474
477
fir::ExtendedValue genMinloc (mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
475
478
fir::ExtendedValue genMinval (mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
479
+ mlir::Value genMod (mlir::Type, llvm::ArrayRef<mlir::Value>);
480
+ mlir::Value genModulo (mlir::Type, llvm::ArrayRef<mlir::Value>);
481
+ mlir::Value genNint (mlir::Type, llvm::ArrayRef<mlir::Value>);
482
+ mlir::Value genNot (mlir::Type, llvm::ArrayRef<mlir::Value>);
483
+ fir::ExtendedValue genNull (mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
484
+ fir::ExtendedValue genProduct (mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
476
485
void genRandomInit (llvm::ArrayRef<fir::ExtendedValue>);
477
486
void genRandomNumber (llvm::ArrayRef<fir::ExtendedValue>);
478
487
void genRandomSeed (llvm::ArrayRef<fir::ExtendedValue>);
@@ -636,6 +645,9 @@ static constexpr IntrinsicHandler handlers[]{
636
645
{" boundary" , asBox, handleDynamicOptional},
637
646
{" dim" , asValue}}},
638
647
/* isElemental=*/ false },
648
+ {" exponent" , &I::genExponent},
649
+ {" floor" , &I::genFloor},
650
+ {" fraction" , &I::genFraction},
639
651
{" iachar" , &I::genIchar},
640
652
{" iand" , &I::genIand},
641
653
{" ibclr" , &I::genIbclr},
@@ -684,7 +696,17 @@ static constexpr IntrinsicHandler handlers[]{
684
696
{" dim" , asValue},
685
697
{" mask" , asBox, handleDynamicOptional}}},
686
698
/* isElemental=*/ false },
699
+ {" mod" , &I::genMod},
700
+ {" modulo" , &I::genModulo},
701
+ {" nint" , &I::genNint},
702
+ {" not" , &I::genNot},
687
703
{" null" , &I::genNull, {{{" mold" , asInquired}}}, /* isElemental=*/ false },
704
+ {" product" ,
705
+ &I::genProduct,
706
+ {{{" array" , asBox},
707
+ {" dim" , asValue},
708
+ {" mask" , asBox, handleDynamicOptional}}},
709
+ /* isElemental=*/ false },
688
710
{" random_init" ,
689
711
&I::genRandomInit,
690
712
{{{" repeatable" , asValue}, {" image_distinct" , asValue}}},
@@ -795,12 +817,33 @@ static mlir::FunctionType genF64F64F64FuncType(mlir::MLIRContext *context) {
795
817
return mlir::FunctionType::get (context, {t, t}, {t});
796
818
}
797
819
820
+ template <int Bits>
821
+ static mlir::FunctionType genIntF64FuncType (mlir::MLIRContext *context) {
822
+ auto t = mlir::FloatType::getF64 (context);
823
+ auto r = mlir::IntegerType::get (context, Bits);
824
+ return mlir::FunctionType::get (context, {t}, {r});
825
+ }
826
+
827
+ template <int Bits>
828
+ static mlir::FunctionType genIntF32FuncType (mlir::MLIRContext *context) {
829
+ auto t = mlir::FloatType::getF32 (context);
830
+ auto r = mlir::IntegerType::get (context, Bits);
831
+ return mlir::FunctionType::get (context, {t}, {r});
832
+ }
833
+
798
834
// TODO : Fill-up this table with more intrinsic.
799
835
// Note: These are also defined as operations in LLVM dialect. See if this
800
836
// can be use and has advantages.
801
837
static constexpr RuntimeFunction llvmIntrinsics[] = {
802
838
{" abs" , " llvm.fabs.f32" , genF32F32FuncType},
803
839
{" abs" , " llvm.fabs.f64" , genF64F64FuncType},
840
+ // llvm.floor is used for FLOOR, but returns real.
841
+ {" floor" , " llvm.floor.f32" , genF32F32FuncType},
842
+ {" floor" , " llvm.floor.f64" , genF64F64FuncType},
843
+ {" nint" , " llvm.lround.i64.f64" , genIntF64FuncType<64 >},
844
+ {" nint" , " llvm.lround.i64.f32" , genIntF32FuncType<64 >},
845
+ {" nint" , " llvm.lround.i32.f64" , genIntF64FuncType<32 >},
846
+ {" nint" , " llvm.lround.i32.f32" , genIntF32FuncType<32 >},
804
847
{" pow" , " llvm.pow.f32" , genF32F32F32FuncType},
805
848
{" pow" , " llvm.pow.f64" , genF64F64F64FuncType},
806
849
};
@@ -1890,6 +1933,38 @@ IntrinsicLibrary::genEoshift(mlir::Type resultType,
1890
1933
" unexpected result for EOSHIFT" );
1891
1934
}
1892
1935
1936
+ // EXPONENT
1937
+ mlir::Value IntrinsicLibrary::genExponent (mlir::Type resultType,
1938
+ llvm::ArrayRef<mlir::Value> args) {
1939
+ assert (args.size () == 1 );
1940
+
1941
+ return builder.createConvert (
1942
+ loc, resultType,
1943
+ fir::runtime::genExponent (builder, loc, resultType,
1944
+ fir::getBase (args[0 ])));
1945
+ }
1946
+
1947
+ // FLOOR
1948
+ mlir::Value IntrinsicLibrary::genFloor (mlir::Type resultType,
1949
+ llvm::ArrayRef<mlir::Value> args) {
1950
+ // Optional KIND argument.
1951
+ assert (args.size () >= 1 );
1952
+ mlir::Value arg = args[0 ];
1953
+ // Use LLVM floor that returns real.
1954
+ mlir::Value floor = genRuntimeCall (" floor" , arg.getType (), {arg});
1955
+ return builder.createConvert (loc, resultType, floor);
1956
+ }
1957
+
1958
+ // FRACTION
1959
+ mlir::Value IntrinsicLibrary::genFraction (mlir::Type resultType,
1960
+ llvm::ArrayRef<mlir::Value> args) {
1961
+ assert (args.size () == 1 );
1962
+
1963
+ return builder.createConvert (
1964
+ loc, resultType,
1965
+ fir::runtime::genFraction (builder, loc, fir::getBase (args[0 ])));
1966
+ }
1967
+
1893
1968
// IAND
1894
1969
mlir::Value IntrinsicLibrary::genIand (mlir::Type resultType,
1895
1970
llvm::ArrayRef<mlir::Value> args) {
@@ -2238,6 +2313,83 @@ mlir::Value IntrinsicLibrary::genExtremum(mlir::Type,
2238
2313
return result;
2239
2314
}
2240
2315
2316
+ // MOD
2317
+ mlir::Value IntrinsicLibrary::genMod (mlir::Type resultType,
2318
+ llvm::ArrayRef<mlir::Value> args) {
2319
+ assert (args.size () == 2 );
2320
+ if (resultType.isa <mlir::IntegerType>())
2321
+ return builder.create <mlir::arith::RemSIOp>(loc, args[0 ], args[1 ]);
2322
+
2323
+ // Use runtime. Note that mlir::arith::RemFOp implements floating point
2324
+ // remainder, but it does not work with fir::Real type.
2325
+ // TODO: consider using mlir::arith::RemFOp when possible, that may help
2326
+ // folding and optimizations.
2327
+ return genRuntimeCall (" mod" , resultType, args);
2328
+ }
2329
+
2330
+ // MODULO
2331
+ mlir::Value IntrinsicLibrary::genModulo (mlir::Type resultType,
2332
+ llvm::ArrayRef<mlir::Value> args) {
2333
+ assert (args.size () == 2 );
2334
+ // No floored modulo op in LLVM/MLIR yet. TODO: add one to MLIR.
2335
+ // In the meantime, use a simple inlined implementation based on truncated
2336
+ // modulo (MOD(A, P) implemented by RemIOp, RemFOp). This avoids making manual
2337
+ // division and multiplication from MODULO formula.
2338
+ // - If A/P > 0 or MOD(A,P)=0, then INT(A/P) = FLOOR(A/P), and MODULO = MOD.
2339
+ // - Otherwise, when A/P < 0 and MOD(A,P) !=0, then MODULO(A, P) =
2340
+ // A-FLOOR(A/P)*P = A-(INT(A/P)-1)*P = A-INT(A/P)*P+P = MOD(A,P)+P
2341
+ // Note that A/P < 0 if and only if A and P signs are different.
2342
+ if (resultType.isa <mlir::IntegerType>()) {
2343
+ auto remainder =
2344
+ builder.create <mlir::arith::RemSIOp>(loc, args[0 ], args[1 ]);
2345
+ auto argXor = builder.create <mlir::arith::XOrIOp>(loc, args[0 ], args[1 ]);
2346
+ mlir::Value zero = builder.createIntegerConstant (loc, argXor.getType (), 0 );
2347
+ auto argSignDifferent = builder.create <mlir::arith::CmpIOp>(
2348
+ loc, mlir::arith::CmpIPredicate::slt, argXor, zero);
2349
+ auto remainderIsNotZero = builder.create <mlir::arith::CmpIOp>(
2350
+ loc, mlir::arith::CmpIPredicate::ne, remainder, zero);
2351
+ auto mustAddP = builder.create <mlir::arith::AndIOp>(loc, remainderIsNotZero,
2352
+ argSignDifferent);
2353
+ auto remPlusP =
2354
+ builder.create <mlir::arith::AddIOp>(loc, remainder, args[1 ]);
2355
+ return builder.create <mlir::arith::SelectOp>(loc, mustAddP, remPlusP,
2356
+ remainder);
2357
+ }
2358
+ // Real case
2359
+ auto remainder = builder.create <mlir::arith::RemFOp>(loc, args[0 ], args[1 ]);
2360
+ mlir::Value zero = builder.createRealZeroConstant (loc, remainder.getType ());
2361
+ auto remainderIsNotZero = builder.create <mlir::arith::CmpFOp>(
2362
+ loc, mlir::arith::CmpFPredicate::UNE, remainder, zero);
2363
+ auto aLessThanZero = builder.create <mlir::arith::CmpFOp>(
2364
+ loc, mlir::arith::CmpFPredicate::OLT, args[0 ], zero);
2365
+ auto pLessThanZero = builder.create <mlir::arith::CmpFOp>(
2366
+ loc, mlir::arith::CmpFPredicate::OLT, args[1 ], zero);
2367
+ auto argSignDifferent =
2368
+ builder.create <mlir::arith::XOrIOp>(loc, aLessThanZero, pLessThanZero);
2369
+ auto mustAddP = builder.create <mlir::arith::AndIOp>(loc, remainderIsNotZero,
2370
+ argSignDifferent);
2371
+ auto remPlusP = builder.create <mlir::arith::AddFOp>(loc, remainder, args[1 ]);
2372
+ return builder.create <mlir::arith::SelectOp>(loc, mustAddP, remPlusP,
2373
+ remainder);
2374
+ }
2375
+
2376
+ // NINT
2377
+ mlir::Value IntrinsicLibrary::genNint (mlir::Type resultType,
2378
+ llvm::ArrayRef<mlir::Value> args) {
2379
+ assert (args.size () >= 1 );
2380
+ // Skip optional kind argument to search the runtime; it is already reflected
2381
+ // in result type.
2382
+ return genRuntimeCall (" nint" , resultType, {args[0 ]});
2383
+ }
2384
+
2385
+ // NOT
2386
+ mlir::Value IntrinsicLibrary::genNot (mlir::Type resultType,
2387
+ llvm::ArrayRef<mlir::Value> args) {
2388
+ assert (args.size () == 1 );
2389
+ mlir::Value allOnes = builder.createIntegerConstant (loc, resultType, -1 );
2390
+ return builder.create <mlir::arith::XOrIOp>(loc, args[0 ], allOnes);
2391
+ }
2392
+
2241
2393
// NULL
2242
2394
fir::ExtendedValue
2243
2395
IntrinsicLibrary::genNull (mlir::Type, llvm::ArrayRef<fir::ExtendedValue> args) {
@@ -2255,6 +2407,15 @@ IntrinsicLibrary::genNull(mlir::Type, llvm::ArrayRef<fir::ExtendedValue> args) {
2255
2407
return fir::MutableBoxValue (boxStorage, mold->nonDeferredLenParams (), {});
2256
2408
}
2257
2409
2410
+ // PRODUCT
2411
+ fir::ExtendedValue
2412
+ IntrinsicLibrary::genProduct (mlir::Type resultType,
2413
+ llvm::ArrayRef<fir::ExtendedValue> args) {
2414
+ return genProdOrSum (fir::runtime::genProduct, fir::runtime::genProductDim,
2415
+ resultType, builder, loc, stmtCtx,
2416
+ " unexpected result for Product" , args);
2417
+ }
2418
+
2258
2419
// RANDOM_INIT
2259
2420
void IntrinsicLibrary::genRandomInit (llvm::ArrayRef<fir::ExtendedValue> args) {
2260
2421
assert (args.size () == 2 );
0 commit comments