@@ -1944,6 +1944,128 @@ llvm::LogicalResult fir::EmboxOp::verify() {
1944
1944
return mlir::success ();
1945
1945
}
1946
1946
1947
+ // / Returns true if \p extent matches the extent of the \p box's
1948
+ // / dimension \p dim.
1949
+ static bool isBoxExtent (mlir::Value box, std::int64_t dim, mlir::Value extent) {
1950
+ if (auto op = extent.getDefiningOp <fir::BoxDimsOp>())
1951
+ if (op.getVal () == box && op.getExtent () == extent)
1952
+ if (auto dimOperand = fir::getIntIfConstant (op.getDim ()))
1953
+ return *dimOperand == dim;
1954
+ return false ;
1955
+ }
1956
+
1957
+ // / Returns true if \p lb matches the lower bound of the \p box's
1958
+ // / dimension \p dim. If \p mayHaveNonDefaultLowerBounds is false,
1959
+ // / then \p lb may be an integer constant 1.
1960
+ static bool isBoxLb (mlir::Value box, std::int64_t dim, mlir::Value lb,
1961
+ bool mayHaveNonDefaultLowerBounds = true ) {
1962
+ if (auto op = lb.getDefiningOp <fir::BoxDimsOp>()) {
1963
+ if (op.getVal () == box && op.getLowerBound () == lb)
1964
+ if (auto dimOperand = fir::getIntIfConstant (op.getDim ()))
1965
+ return *dimOperand == dim;
1966
+ } else if (!mayHaveNonDefaultLowerBounds) {
1967
+ if (auto constantLb = fir::getIntIfConstant (lb))
1968
+ return *constantLb == 1 ;
1969
+ }
1970
+ return false ;
1971
+ }
1972
+
1973
+ // / Returns true if \p ub matches the upper bound of the \p box's
1974
+ // / dimension \p dim. If \p mayHaveNonDefaultLowerBounds is false,
1975
+ // / then the dimension's lower bound may be an integer constant 1.
1976
+ // / Note that the upper bound is usually a result of computation
1977
+ // / involving the lower bound and the extent, and the function
1978
+ // / tries its best to recognize the computation pattern.
1979
+ // / The conservative result 'false' does not necessarily mean
1980
+ // / that \p ub is not an actual upper bound value.
1981
+ static bool isBoxUb (mlir::Value box, std::int64_t dim, mlir::Value ub,
1982
+ bool mayHaveNonDefaultLowerBounds = true ) {
1983
+ if (auto sub1 = ub.getDefiningOp <mlir::arith::SubIOp>()) {
1984
+ auto one = fir::getIntIfConstant (sub1.getOperand (1 ));
1985
+ if (!one || *one != 1 )
1986
+ return false ;
1987
+ if (auto add = sub1.getOperand (0 ).getDefiningOp <mlir::arith::AddIOp>())
1988
+ if ((isBoxLb (box, dim, add.getOperand (0 )) &&
1989
+ isBoxExtent (box, dim, add.getOperand (1 ))) ||
1990
+ (isBoxLb (box, dim, add.getOperand (1 )) &&
1991
+ isBoxExtent (box, dim, add.getOperand (0 ))))
1992
+ return true ;
1993
+ } else if (!mayHaveNonDefaultLowerBounds) {
1994
+ return isBoxExtent (box, dim, ub);
1995
+ }
1996
+ return false ;
1997
+ }
1998
+
1999
+ // / Checks if the given \p sliceOp specifies a contiguous
2000
+ // / array slice. If \p checkWhole is true, then the check
2001
+ // / is done for all dimensions, otherwise, only for the innermost
2002
+ // / dimension.
2003
+ // / The simplest way to prove that this is an contiguous slice
2004
+ // / is to check whether the slice stride(s) is 1.
2005
+ // / For more complex cases, extra information must be provided
2006
+ // / by the caller:
2007
+ // / * \p origBox - if not null, then the source array is represented
2008
+ // / with this !fir.box value. The box is used to recognize
2009
+ // / the full dimension slices, which are specified by the triplets
2010
+ // / computed from the dimensions' lower bounds and extents.
2011
+ // / * \p mayHaveNonDefaultLowerBounds may be set to false to indicate
2012
+ // / that the source entity has default lower bounds, so the full
2013
+ // / dimension slices computations may use 1 for the lower bound.
2014
+ static bool isContiguousArraySlice (fir::SliceOp sliceOp, bool checkWhole = true ,
2015
+ mlir::Value origBox = nullptr ,
2016
+ bool mayHaveNonDefaultLowerBounds = true ) {
2017
+ if (sliceOp.getFields ().empty () && sliceOp.getSubstr ().empty ()) {
2018
+ // TODO: generalize code for the triples analysis with
2019
+ // hlfir::designatePreservesContinuity, especially when
2020
+ // recognition of the whole dimension slices is added.
2021
+ auto triples = sliceOp.getTriples ();
2022
+ assert ((triples.size () % 3 ) == 0 && " invalid triples size" );
2023
+
2024
+ // A slice with step=1 in the innermost dimension preserves
2025
+ // the continuity of the array in the innermost dimension.
2026
+ // If checkWhole is false, then check only the innermost slice triples.
2027
+ std::size_t checkUpTo = checkWhole ? triples.size () : 3 ;
2028
+ checkUpTo = std::min (checkUpTo, triples.size ());
2029
+ for (std::size_t i = 0 ; i < checkUpTo; i += 3 ) {
2030
+ if (triples[i] != triples[i + 1 ]) {
2031
+ // This is a section of the dimension. Only allow it
2032
+ // to be the first triple, if the source of the slice
2033
+ // is a boxed array. If it is a raw pointer, then
2034
+ // the result will still be contiguous, as long as
2035
+ // the strides are all ones.
2036
+ // When origBox is not null, we must prove that the triple
2037
+ // covers the whole dimension and the stride is one,
2038
+ // before claiming contiguity for this dimension.
2039
+ if (i != 0 && origBox) {
2040
+ std::int64_t dim = i / 3 ;
2041
+ if (!isBoxLb (origBox, dim, triples[i],
2042
+ mayHaveNonDefaultLowerBounds) ||
2043
+ !isBoxUb (origBox, dim, triples[i + 1 ],
2044
+ mayHaveNonDefaultLowerBounds))
2045
+ return false ;
2046
+ }
2047
+ auto constantStep = fir::getIntIfConstant (triples[i + 2 ]);
2048
+ if (!constantStep || *constantStep != 1 )
2049
+ return false ;
2050
+ }
2051
+ }
2052
+ return true ;
2053
+ }
2054
+ return false ;
2055
+ }
2056
+
2057
+ bool fir::isContiguousEmbox (fir::EmboxOp embox, bool checkWhole) {
2058
+ auto sliceArg = embox.getSlice ();
2059
+ if (!sliceArg)
2060
+ return true ;
2061
+
2062
+ if (auto sliceOp =
2063
+ mlir::dyn_cast_or_null<fir::SliceOp>(sliceArg.getDefiningOp ()))
2064
+ return isContiguousArraySlice (sliceOp, checkWhole);
2065
+
2066
+ return false ;
2067
+ }
2068
+
1947
2069
// ===----------------------------------------------------------------------===//
1948
2070
// EmboxCharOp
1949
2071
// ===----------------------------------------------------------------------===//
@@ -4794,41 +4916,20 @@ mlir::Type fir::applyPathToType(mlir::Type eleTy, mlir::ValueRange path) {
4794
4916
return eleTy;
4795
4917
}
4796
4918
4797
- bool fir::reboxPreservesContinuity (fir::ReboxOp rebox, bool checkWhole) {
4919
+ bool fir::reboxPreservesContinuity (fir::ReboxOp rebox,
4920
+ bool mayHaveNonDefaultLowerBounds,
4921
+ bool checkWhole) {
4798
4922
// If slicing is not involved, then the rebox does not affect
4799
4923
// the continuity of the array.
4800
4924
auto sliceArg = rebox.getSlice ();
4801
4925
if (!sliceArg)
4802
4926
return true ;
4803
4927
4804
4928
if (auto sliceOp =
4805
- mlir::dyn_cast_or_null<fir::SliceOp>(sliceArg.getDefiningOp ())) {
4806
- if (sliceOp.getFields ().empty () && sliceOp.getSubstr ().empty ()) {
4807
- // TODO: generalize code for the triples analysis with
4808
- // hlfir::designatePreservesContinuity, especially when
4809
- // recognition of the whole dimension slices is added.
4810
- auto triples = sliceOp.getTriples ();
4811
- assert ((triples.size () % 3 ) == 0 && " invalid triples size" );
4812
-
4813
- // A slice with step=1 in the innermost dimension preserves
4814
- // the continuity of the array in the innermost dimension.
4815
- // If checkWhole is false, then check only the innermost slice triples.
4816
- std::size_t checkUpTo = checkWhole ? triples.size () : 3 ;
4817
- checkUpTo = std::min (checkUpTo, triples.size ());
4818
- for (std::size_t i = 0 ; i < checkUpTo; i += 3 ) {
4819
- if (triples[i] != triples[i + 1 ]) {
4820
- // This is a section of the dimension. Only allow it
4821
- // to be the first triple.
4822
- if (i != 0 )
4823
- return false ;
4824
- auto constantStep = fir::getIntIfConstant (triples[i + 2 ]);
4825
- if (!constantStep || *constantStep != 1 )
4826
- return false ;
4827
- }
4828
- }
4829
- return true ;
4830
- }
4831
- }
4929
+ mlir::dyn_cast_or_null<fir::SliceOp>(sliceArg.getDefiningOp ()))
4930
+ return isContiguousArraySlice (sliceOp, checkWhole, rebox.getBox (),
4931
+ mayHaveNonDefaultLowerBounds);
4932
+
4832
4933
return false ;
4833
4934
}
4834
4935
0 commit comments