@@ -1944,6 +1944,128 @@ llvm::LogicalResult fir::EmboxOp::verify() {
19441944 return mlir::success ();
19451945}
19461946
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+
19472069// ===----------------------------------------------------------------------===//
19482070// EmboxCharOp
19492071// ===----------------------------------------------------------------------===//
@@ -4794,41 +4916,20 @@ mlir::Type fir::applyPathToType(mlir::Type eleTy, mlir::ValueRange path) {
47944916 return eleTy;
47954917}
47964918
4797- bool fir::reboxPreservesContinuity (fir::ReboxOp rebox, bool checkWhole) {
4919+ bool fir::reboxPreservesContinuity (fir::ReboxOp rebox,
4920+ bool mayHaveNonDefaultLowerBounds,
4921+ bool checkWhole) {
47984922 // If slicing is not involved, then the rebox does not affect
47994923 // the continuity of the array.
48004924 auto sliceArg = rebox.getSlice ();
48014925 if (!sliceArg)
48024926 return true ;
48034927
48044928 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+
48324933 return false ;
48334934}
48344935
0 commit comments