29
29
#include " flang/Optimizer/Builder/Runtime/Numeric.h"
30
30
#include " flang/Optimizer/Builder/Runtime/RTBuilder.h"
31
31
#include " flang/Optimizer/Builder/Runtime/Reduction.h"
32
+ #include " flang/Optimizer/Builder/Runtime/Transformational.h"
32
33
#include " flang/Optimizer/Dialect/FIROpsSupport.h"
33
34
#include " flang/Optimizer/Support/FatalError.h"
34
35
#include " mlir/Dialect/LLVMIR/LLVMDialect.h"
@@ -441,21 +442,25 @@ struct IntrinsicLibrary {
441
442
llvm::ArrayRef<fir::ExtendedValue>);
442
443
fir::ExtendedValue genChar (mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
443
444
fir::ExtendedValue genCount (mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
444
- mlir::Value genDim (mlir::Type, llvm::ArrayRef<mlir::Value>);
445
- fir::ExtendedValue genDotProduct (mlir::Type,
446
- llvm::ArrayRef<fir::ExtendedValue>);
447
445
template <mlir::arith::CmpIPredicate pred>
448
446
fir::ExtendedValue genCharacterCompare (mlir::Type,
449
447
llvm::ArrayRef<fir::ExtendedValue>);
450
448
void genCpuTime (llvm::ArrayRef<fir::ExtendedValue>);
449
+ fir::ExtendedValue genCshift (mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
451
450
void genDateAndTime (llvm::ArrayRef<fir::ExtendedValue>);
451
+ mlir::Value genDim (mlir::Type, llvm::ArrayRef<mlir::Value>);
452
+ fir::ExtendedValue genDotProduct (mlir::Type,
453
+ llvm::ArrayRef<fir::ExtendedValue>);
454
+ fir::ExtendedValue genEoshift (mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
452
455
template <Extremum, ExtremumBehavior>
453
456
mlir::Value genExtremum (mlir::Type, llvm::ArrayRef<mlir::Value>);
454
457
// / Lowering for the IAND intrinsic. The IAND intrinsic expects two arguments
455
458
// / in the llvm::ArrayRef.
456
459
mlir::Value genIand (mlir::Type, llvm::ArrayRef<mlir::Value>);
457
460
mlir::Value genIbits (mlir::Type, llvm::ArrayRef<mlir::Value>);
458
461
mlir::Value genIbset (mlir::Type, llvm::ArrayRef<mlir::Value>);
462
+ mlir::Value genIshft (mlir::Type, llvm::ArrayRef<mlir::Value>);
463
+ mlir::Value genIshftc (mlir::Type, llvm::ArrayRef<mlir::Value>);
459
464
fir::ExtendedValue genLbound (mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
460
465
fir::ExtendedValue genNull (mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
461
466
fir::ExtendedValue genLen (mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
@@ -604,6 +609,10 @@ static constexpr IntrinsicHandler handlers[]{
604
609
&I::genCpuTime,
605
610
{{{" time" , asAddr}}},
606
611
/* isElemental=*/ false },
612
+ {" cshift" ,
613
+ &I::genCshift,
614
+ {{{" array" , asAddr}, {" shift" , asAddr}, {" dim" , asValue}}},
615
+ /* isElemental=*/ false },
607
616
{" date_and_time" ,
608
617
&I::genDateAndTime,
609
618
{{{" date" , asAddr, handleDynamicOptional},
@@ -616,9 +625,18 @@ static constexpr IntrinsicHandler handlers[]{
616
625
&I::genDotProduct,
617
626
{{{" vector_a" , asBox}, {" vector_b" , asBox}}},
618
627
/* isElemental=*/ false },
628
+ {" eoshift" ,
629
+ &I::genEoshift,
630
+ {{{" array" , asBox},
631
+ {" shift" , asAddr},
632
+ {" boundary" , asBox, handleDynamicOptional},
633
+ {" dim" , asValue}}},
634
+ /* isElemental=*/ false },
619
635
{" iand" , &I::genIand},
620
636
{" ibits" , &I::genIbits},
621
637
{" ibset" , &I::genIbset},
638
+ {" ishft" , &I::genIshft},
639
+ {" ishftc" , &I::genIshftc},
622
640
{" len" ,
623
641
&I::genLen,
624
642
{{{" string" , asInquired}, {" kind" , asValue}}},
@@ -1724,6 +1742,47 @@ void IntrinsicLibrary::genCpuTime(llvm::ArrayRef<fir::ExtendedValue> args) {
1724
1742
builder.create <fir::StoreOp>(loc, res2, *arg);
1725
1743
}
1726
1744
1745
+ // CSHIFT
1746
+ fir::ExtendedValue
1747
+ IntrinsicLibrary::genCshift (mlir::Type resultType,
1748
+ llvm::ArrayRef<fir::ExtendedValue> args) {
1749
+ assert (args.size () == 3 );
1750
+
1751
+ // Handle required ARRAY argument
1752
+ fir::BoxValue arrayBox = builder.createBox (loc, args[0 ]);
1753
+ mlir::Value array = fir::getBase (arrayBox);
1754
+ unsigned arrayRank = arrayBox.rank ();
1755
+
1756
+ // Create mutable fir.box to be passed to the runtime for the result.
1757
+ mlir::Type resultArrayType = builder.getVarLenSeqTy (resultType, arrayRank);
1758
+ fir::MutableBoxValue resultMutableBox =
1759
+ fir::factory::createTempMutableBox (builder, loc, resultArrayType);
1760
+ mlir::Value resultIrBox =
1761
+ fir::factory::getMutableIRBox (builder, loc, resultMutableBox);
1762
+
1763
+ if (arrayRank == 1 ) {
1764
+ // Vector case
1765
+ // Handle required SHIFT argument as a scalar
1766
+ const mlir::Value *shiftAddr = args[1 ].getUnboxed ();
1767
+ assert (shiftAddr && " nonscalar CSHIFT argument" );
1768
+ auto shift = builder.create <fir::LoadOp>(loc, *shiftAddr);
1769
+
1770
+ fir::runtime::genCshiftVector (builder, loc, resultIrBox, array, shift);
1771
+ } else {
1772
+ // Non-vector case
1773
+ // Handle required SHIFT argument as an array
1774
+ mlir::Value shift = builder.createBox (loc, args[1 ]);
1775
+
1776
+ // Handle optional DIM argument
1777
+ mlir::Value dim =
1778
+ isAbsent (args[2 ])
1779
+ ? builder.createIntegerConstant (loc, builder.getIndexType (), 1 )
1780
+ : fir::getBase (args[2 ]);
1781
+ fir::runtime::genCshift (builder, loc, resultIrBox, array, shift, dim);
1782
+ }
1783
+ return readAndAddCleanUp (resultMutableBox, resultType, " CSHIFT" );
1784
+ }
1785
+
1727
1786
// DATE_AND_TIME
1728
1787
void IntrinsicLibrary::genDateAndTime (llvm::ArrayRef<fir::ExtendedValue> args) {
1729
1788
assert (args.size () == 4 && " date_and_time has 4 args" );
@@ -1768,6 +1827,55 @@ IntrinsicLibrary::genDotProduct(mlir::Type resultType,
1768
1827
stmtCtx, args);
1769
1828
}
1770
1829
1830
+ // EOSHIFT
1831
+ fir::ExtendedValue
1832
+ IntrinsicLibrary::genEoshift (mlir::Type resultType,
1833
+ llvm::ArrayRef<fir::ExtendedValue> args) {
1834
+ assert (args.size () == 4 );
1835
+
1836
+ // Handle required ARRAY argument
1837
+ fir::BoxValue arrayBox = builder.createBox (loc, args[0 ]);
1838
+ mlir::Value array = fir::getBase (arrayBox);
1839
+ unsigned arrayRank = arrayBox.rank ();
1840
+
1841
+ // Create mutable fir.box to be passed to the runtime for the result.
1842
+ mlir::Type resultArrayType = builder.getVarLenSeqTy (resultType, arrayRank);
1843
+ fir::MutableBoxValue resultMutableBox =
1844
+ fir::factory::createTempMutableBox (builder, loc, resultArrayType);
1845
+ mlir::Value resultIrBox =
1846
+ fir::factory::getMutableIRBox (builder, loc, resultMutableBox);
1847
+
1848
+ // Handle optional BOUNDARY argument
1849
+ mlir::Value boundary =
1850
+ isAbsent (args[2 ]) ? builder.create <fir::AbsentOp>(
1851
+ loc, fir::BoxType::get (builder.getNoneType ()))
1852
+ : builder.createBox (loc, args[2 ]);
1853
+
1854
+ if (arrayRank == 1 ) {
1855
+ // Vector case
1856
+ // Handle required SHIFT argument as a scalar
1857
+ const mlir::Value *shiftAddr = args[1 ].getUnboxed ();
1858
+ assert (shiftAddr && " nonscalar EOSHIFT SHIFT argument" );
1859
+ auto shift = builder.create <fir::LoadOp>(loc, *shiftAddr);
1860
+ fir::runtime::genEoshiftVector (builder, loc, resultIrBox, array, shift,
1861
+ boundary);
1862
+ } else {
1863
+ // Non-vector case
1864
+ // Handle required SHIFT argument as an array
1865
+ mlir::Value shift = builder.createBox (loc, args[1 ]);
1866
+
1867
+ // Handle optional DIM argument
1868
+ mlir::Value dim =
1869
+ isAbsent (args[3 ])
1870
+ ? builder.createIntegerConstant (loc, builder.getIndexType (), 1 )
1871
+ : fir::getBase (args[3 ]);
1872
+ fir::runtime::genEoshift (builder, loc, resultIrBox, array, shift, boundary,
1873
+ dim);
1874
+ }
1875
+ return readAndAddCleanUp (resultMutableBox, resultType,
1876
+ " unexpected result for EOSHIFT" );
1877
+ }
1878
+
1771
1879
// IAND
1772
1880
mlir::Value IntrinsicLibrary::genIand (mlir::Type resultType,
1773
1881
llvm::ArrayRef<mlir::Value> args) {
@@ -1816,6 +1924,99 @@ mlir::Value IntrinsicLibrary::genIbset(mlir::Type resultType,
1816
1924
return builder.create <mlir::arith::OrIOp>(loc, args[0 ], mask);
1817
1925
}
1818
1926
1927
+ // ISHFT
1928
+ mlir::Value IntrinsicLibrary::genIshft (mlir::Type resultType,
1929
+ llvm::ArrayRef<mlir::Value> args) {
1930
+ // A conformant ISHFT(I,SHIFT) call satisfies:
1931
+ // abs(SHIFT) <= BIT_SIZE(I)
1932
+ // Return: abs(SHIFT) >= BIT_SIZE(I)
1933
+ // ? 0
1934
+ // : SHIFT < 0
1935
+ // ? I >> abs(SHIFT)
1936
+ // : I << abs(SHIFT)
1937
+ assert (args.size () == 2 );
1938
+ mlir::Value bitSize = builder.createIntegerConstant (
1939
+ loc, resultType, resultType.cast <mlir::IntegerType>().getWidth ());
1940
+ mlir::Value zero = builder.createIntegerConstant (loc, resultType, 0 );
1941
+ mlir::Value shift = builder.createConvert (loc, resultType, args[1 ]);
1942
+ mlir::Value absShift = genAbs (resultType, {shift});
1943
+ auto left = builder.create <mlir::arith::ShLIOp>(loc, args[0 ], absShift);
1944
+ auto right = builder.create <mlir::arith::ShRUIOp>(loc, args[0 ], absShift);
1945
+ auto shiftIsLarge = builder.create <mlir::arith::CmpIOp>(
1946
+ loc, mlir::arith::CmpIPredicate::sge, absShift, bitSize);
1947
+ auto shiftIsNegative = builder.create <mlir::arith::CmpIOp>(
1948
+ loc, mlir::arith::CmpIPredicate::slt, shift, zero);
1949
+ auto sel =
1950
+ builder.create <mlir::arith::SelectOp>(loc, shiftIsNegative, right, left);
1951
+ return builder.create <mlir::arith::SelectOp>(loc, shiftIsLarge, zero, sel);
1952
+ }
1953
+
1954
+ // ISHFTC
1955
+ mlir::Value IntrinsicLibrary::genIshftc (mlir::Type resultType,
1956
+ llvm::ArrayRef<mlir::Value> args) {
1957
+ // A conformant ISHFTC(I,SHIFT,SIZE) call satisfies:
1958
+ // SIZE > 0
1959
+ // SIZE <= BIT_SIZE(I)
1960
+ // abs(SHIFT) <= SIZE
1961
+ // if SHIFT > 0
1962
+ // leftSize = abs(SHIFT)
1963
+ // rightSize = SIZE - abs(SHIFT)
1964
+ // else [if SHIFT < 0]
1965
+ // leftSize = SIZE - abs(SHIFT)
1966
+ // rightSize = abs(SHIFT)
1967
+ // unchanged = SIZE == BIT_SIZE(I) ? 0 : (I >> SIZE) << SIZE
1968
+ // leftMaskShift = BIT_SIZE(I) - leftSize
1969
+ // rightMaskShift = BIT_SIZE(I) - rightSize
1970
+ // left = (I >> rightSize) & (-1 >> leftMaskShift)
1971
+ // right = (I & (-1 >> rightMaskShift)) << leftSize
1972
+ // Return: SHIFT == 0 || SIZE == abs(SHIFT) ? I : (unchanged | left | right)
1973
+ assert (args.size () == 3 );
1974
+ mlir::Value bitSize = builder.createIntegerConstant (
1975
+ loc, resultType, resultType.cast <mlir::IntegerType>().getWidth ());
1976
+ mlir::Value I = args[0 ];
1977
+ mlir::Value shift = builder.createConvert (loc, resultType, args[1 ]);
1978
+ mlir::Value size =
1979
+ args[2 ] ? builder.createConvert (loc, resultType, args[2 ]) : bitSize;
1980
+ mlir::Value zero = builder.createIntegerConstant (loc, resultType, 0 );
1981
+ mlir::Value ones = builder.createIntegerConstant (loc, resultType, -1 );
1982
+ mlir::Value absShift = genAbs (resultType, {shift});
1983
+ auto elseSize = builder.create <mlir::arith::SubIOp>(loc, size, absShift);
1984
+ auto shiftIsZero = builder.create <mlir::arith::CmpIOp>(
1985
+ loc, mlir::arith::CmpIPredicate::eq, shift, zero);
1986
+ auto shiftEqualsSize = builder.create <mlir::arith::CmpIOp>(
1987
+ loc, mlir::arith::CmpIPredicate::eq, absShift, size);
1988
+ auto shiftIsNop =
1989
+ builder.create <mlir::arith::OrIOp>(loc, shiftIsZero, shiftEqualsSize);
1990
+ auto shiftIsPositive = builder.create <mlir::arith::CmpIOp>(
1991
+ loc, mlir::arith::CmpIPredicate::sgt, shift, zero);
1992
+ auto leftSize = builder.create <mlir::arith::SelectOp>(loc, shiftIsPositive,
1993
+ absShift, elseSize);
1994
+ auto rightSize = builder.create <mlir::arith::SelectOp>(loc, shiftIsPositive,
1995
+ elseSize, absShift);
1996
+ auto hasUnchanged = builder.create <mlir::arith::CmpIOp>(
1997
+ loc, mlir::arith::CmpIPredicate::ne, size, bitSize);
1998
+ auto unchangedTmp1 = builder.create <mlir::arith::ShRUIOp>(loc, I, size);
1999
+ auto unchangedTmp2 =
2000
+ builder.create <mlir::arith::ShLIOp>(loc, unchangedTmp1, size);
2001
+ auto unchanged = builder.create <mlir::arith::SelectOp>(loc, hasUnchanged,
2002
+ unchangedTmp2, zero);
2003
+ auto leftMaskShift =
2004
+ builder.create <mlir::arith::SubIOp>(loc, bitSize, leftSize);
2005
+ auto leftMask =
2006
+ builder.create <mlir::arith::ShRUIOp>(loc, ones, leftMaskShift);
2007
+ auto leftTmp = builder.create <mlir::arith::ShRUIOp>(loc, I, rightSize);
2008
+ auto left = builder.create <mlir::arith::AndIOp>(loc, leftTmp, leftMask);
2009
+ auto rightMaskShift =
2010
+ builder.create <mlir::arith::SubIOp>(loc, bitSize, rightSize);
2011
+ auto rightMask =
2012
+ builder.create <mlir::arith::ShRUIOp>(loc, ones, rightMaskShift);
2013
+ auto rightTmp = builder.create <mlir::arith::AndIOp>(loc, I, rightMask);
2014
+ auto right = builder.create <mlir::arith::ShLIOp>(loc, rightTmp, leftSize);
2015
+ auto resTmp = builder.create <mlir::arith::OrIOp>(loc, unchanged, left);
2016
+ auto res = builder.create <mlir::arith::OrIOp>(loc, resTmp, right);
2017
+ return builder.create <mlir::arith::SelectOp>(loc, shiftIsNop, I, res);
2018
+ }
2019
+
1819
2020
// LEN
1820
2021
// Note that this is only used for an unrestricted intrinsic LEN call.
1821
2022
// Other uses of LEN are rewritten as descriptor inquiries by the front-end.
0 commit comments