@@ -881,10 +881,12 @@ class IsContiguousHelper
881
881
public:
882
882
using Result = std::optional<bool >; // tri-state
883
883
using Base = AnyTraverse<IsContiguousHelper, Result>;
884
- explicit IsContiguousHelper (
885
- FoldingContext &c, bool namedConstantSectionsAreContiguous)
886
- : Base{*this }, context_{c}, namedConstantSectionsAreContiguous_{
887
- namedConstantSectionsAreContiguous} {}
884
+ explicit IsContiguousHelper (FoldingContext &c,
885
+ bool namedConstantSectionsAreContiguous,
886
+ bool firstDimensionStride1 = false )
887
+ : Base{*this }, context_{c},
888
+ namedConstantSectionsAreContiguous_{namedConstantSectionsAreContiguous},
889
+ firstDimensionStride1_{firstDimensionStride1} {}
888
890
using Base::operator ();
889
891
890
892
template <typename T> Result operator ()(const Constant<T> &) const {
@@ -956,13 +958,14 @@ class IsContiguousHelper
956
958
if (!*baseIsContiguous) {
957
959
return false ;
958
960
}
959
- // TODO could be true if base contiguous and this is only component, or
960
- // if base has only one element?
961
+ // TODO: should be true if base is contiguous and this is only
962
+ // component, or when the base has at most one element
961
963
}
962
964
return std::nullopt;
963
965
}
964
966
}
965
967
Result operator ()(const ComplexPart &x) const {
968
+ // TODO: should be true when base is empty array, too
966
969
return x.complex ().Rank () == 0 ;
967
970
}
968
971
Result operator ()(const Substring &x) const {
@@ -1061,6 +1064,9 @@ class IsContiguousHelper
1061
1064
auto dims{subscript.size ()};
1062
1065
std::vector<bool > knownPartialSlice (dims, false );
1063
1066
for (auto j{dims}; j-- > 0 ;) {
1067
+ if (j == 0 && firstDimensionStride1_ && !result.value_or (true )) {
1068
+ result.reset (); // ignore problems on later dimensions
1069
+ }
1064
1070
std::optional<ConstantSubscript> dimLbound;
1065
1071
std::optional<ConstantSubscript> dimUbound;
1066
1072
std::optional<ConstantSubscript> dimExtent;
@@ -1083,18 +1089,20 @@ class IsContiguousHelper
1083
1089
dimExtent = 0 ;
1084
1090
}
1085
1091
}
1086
-
1087
1092
if (const auto *triplet{std::get_if<Triplet>(&subscript[j].u )}) {
1088
1093
++rank;
1094
+ const Expr<SubscriptInteger> *lowerBound{triplet->GetLower ()};
1095
+ const Expr<SubscriptInteger> *upperBound{triplet->GetUpper ()};
1096
+ std::optional<ConstantSubscript> lowerVal{lowerBound
1097
+ ? ToInt64 (Fold (context_, Expr<SubscriptInteger>{*lowerBound}))
1098
+ : dimLbound};
1099
+ std::optional<ConstantSubscript> upperVal{upperBound
1100
+ ? ToInt64 (Fold (context_, Expr<SubscriptInteger>{*upperBound}))
1101
+ : dimUbound};
1089
1102
if (auto stride{ToInt64 (triplet->stride ())}) {
1090
- const Expr<SubscriptInteger> *lowerBound{triplet->GetLower ()};
1091
- const Expr<SubscriptInteger> *upperBound{triplet->GetUpper ()};
1092
- std::optional<ConstantSubscript> lowerVal{lowerBound
1093
- ? ToInt64 (Fold (context_, Expr<SubscriptInteger>{*lowerBound}))
1094
- : dimLbound};
1095
- std::optional<ConstantSubscript> upperVal{upperBound
1096
- ? ToInt64 (Fold (context_, Expr<SubscriptInteger>{*upperBound}))
1097
- : dimUbound};
1103
+ if (j == 0 && *stride == 1 && firstDimensionStride1_) {
1104
+ result = *stride == 1 ; // contiguous or empty if so
1105
+ }
1098
1106
if (lowerVal && upperVal) {
1099
1107
if (*lowerVal < *upperVal) {
1100
1108
if (*stride < 0 ) {
@@ -1110,23 +1118,31 @@ class IsContiguousHelper
1110
1118
*lowerVal + *stride >= *upperVal) {
1111
1119
result = false ; // discontiguous if not empty
1112
1120
}
1113
- } else {
1114
- mayBeEmpty = true ;
1121
+ } else { // bounds known and equal
1122
+ if (j == 0 && firstDimensionStride1_) {
1123
+ result = true ; // stride doesn't matter
1124
+ }
1125
+ }
1126
+ } else { // bounds not both known
1127
+ mayBeEmpty = true ;
1128
+ }
1129
+ } else { // stride not known
1130
+ if (lowerVal && upperVal && *lowerVal == *upperVal) {
1131
+ // stride doesn't matter when bounds are equal
1132
+ if (j == 0 && firstDimensionStride1_) {
1133
+ result = true ;
1115
1134
}
1116
1135
} else {
1117
1136
mayBeEmpty = true ;
1118
1137
}
1119
- } else {
1120
- mayBeEmpty = true ;
1121
1138
}
1122
- } else if (subscript[j].Rank () > 0 ) {
1139
+ } else if (subscript[j].Rank () > 0 ) { // vector subscript
1123
1140
++rank;
1124
1141
if (!result) {
1125
- result = false ; // vector subscript
1142
+ result = false ;
1126
1143
}
1127
1144
mayBeEmpty = true ;
1128
- } else {
1129
- // Scalar subscript.
1145
+ } else { // scalar subscript
1130
1146
if (dimExtent && *dimExtent > 1 ) {
1131
1147
knownPartialSlice[j] = true ;
1132
1148
}
@@ -1138,7 +1154,7 @@ class IsContiguousHelper
1138
1154
if (result) {
1139
1155
return result;
1140
1156
}
1141
- // Not provably discontiguous at this point.
1157
+ // Not provably contiguous or discontiguous at this point.
1142
1158
// Return "true" if simply contiguous, otherwise nullopt.
1143
1159
for (auto j{subscript.size ()}; j-- > 0 ;) {
1144
1160
if (const auto *triplet{std::get_if<Triplet>(&subscript[j].u )}) {
@@ -1170,33 +1186,36 @@ class IsContiguousHelper
1170
1186
1171
1187
FoldingContext &context_;
1172
1188
bool namedConstantSectionsAreContiguous_{false };
1189
+ bool firstDimensionStride1_{false };
1173
1190
};
1174
1191
1175
1192
template <typename A>
1176
1193
std::optional<bool > IsContiguous (const A &x, FoldingContext &context,
1177
- bool namedConstantSectionsAreContiguous) {
1194
+ bool namedConstantSectionsAreContiguous, bool firstDimensionStride1 ) {
1178
1195
if (!IsVariable (x) &&
1179
1196
(namedConstantSectionsAreContiguous || !ExtractDataRef (x, true , true ))) {
1180
1197
return true ;
1181
1198
} else {
1182
- return IsContiguousHelper{context, namedConstantSectionsAreContiguous}(x);
1199
+ return IsContiguousHelper{
1200
+ context, namedConstantSectionsAreContiguous, firstDimensionStride1}(x);
1183
1201
}
1184
1202
}
1185
1203
1186
1204
template std::optional<bool > IsContiguous (const Expr<SomeType> &,
1187
- FoldingContext &, bool namedConstantSectionsAreContiguous);
1205
+ FoldingContext &, bool namedConstantSectionsAreContiguous,
1206
+ bool firstDimensionStride1);
1188
1207
template std::optional<bool > IsContiguous (const ArrayRef &, FoldingContext &,
1189
- bool namedConstantSectionsAreContiguous);
1208
+ bool namedConstantSectionsAreContiguous, bool firstDimensionStride1 );
1190
1209
template std::optional<bool > IsContiguous (const Substring &, FoldingContext &,
1191
- bool namedConstantSectionsAreContiguous);
1210
+ bool namedConstantSectionsAreContiguous, bool firstDimensionStride1 );
1192
1211
template std::optional<bool > IsContiguous (const Component &, FoldingContext &,
1193
- bool namedConstantSectionsAreContiguous);
1212
+ bool namedConstantSectionsAreContiguous, bool firstDimensionStride1 );
1194
1213
template std::optional<bool > IsContiguous (const ComplexPart &, FoldingContext &,
1195
- bool namedConstantSectionsAreContiguous);
1214
+ bool namedConstantSectionsAreContiguous, bool firstDimensionStride1 );
1196
1215
template std::optional<bool > IsContiguous (const CoarrayRef &, FoldingContext &,
1197
- bool namedConstantSectionsAreContiguous);
1198
- template std::optional<bool > IsContiguous (
1199
- const Symbol &, FoldingContext &, bool namedConstantSectionsAreContiguous );
1216
+ bool namedConstantSectionsAreContiguous, bool firstDimensionStride1 );
1217
+ template std::optional<bool > IsContiguous (const Symbol &, FoldingContext &,
1218
+ bool namedConstantSectionsAreContiguous, bool firstDimensionStride1 );
1200
1219
1201
1220
// IsErrorExpr()
1202
1221
struct IsErrorExprHelper : public AnyTraverse <IsErrorExprHelper, bool > {
0 commit comments