Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rename range.stridable to range.strides : strideKind #22441

Merged
merged 3 commits into from
Jun 2, 2023

Conversation

vasslitvinov
Copy link
Member

@vasslitvinov vasslitvinov commented May 31, 2023

This PR switches the boolean field range.stridable to range.strides of the type enum strideKind { one, negOne, positive, negative, any } according to the design discussion concluded in #17131 (comment)

The by operator infers the strides of the resulting range based on its step argument. For example, r by 1 produces r rather than a range with stridable = true; 1..n by anUnsignedInteger produces a range with strideKind.positive; etc.

stridable queries on ranges and domains are still supported without a warning. The warnings have been added to the module and compiler code. In this PR they are commented out and marked with "RSDW" for "range.stridable deprecation warning". They will be enabled in a future PR.

I modified Chapel code outside of modules/internal as little as possible. My goal was make sure that the deprecation code works correctly. To support domain maps that have not been converted from stridable to strideKind, the compiler converts accesses to the former field stridable to the new field strides in BaseRectangularDom and BaseArrOverRectangularDom.

The bulk of updates to test code caters for a mix of un-converted uses of stridable that produce ranges with strideKind.any and strides-base code produces ranges with strideKind.positive or other more specific strideKinds.

The bulk of updates to test .good files updates the strides components of the range and domain types from false to one and from true to positive, any, etc. Some tests get compile-time warnings or errors instead of, or in addition to, the runtime warnings or errors in those cases where the compiler can now determine the corresponding condition statically based on the strides parameter of the range or domain.

While there:

  • add a future test library/standard/Reflection/primitives/ResolvesDmap
  • overhaul range.displayRepresentation() to display all the range fields
  • disallow a range assignment when the corresponding idxType assignment is illegal
  • support safeCast between ranges of identical enum types, because domain assignment+initialization depends on it via chpl_assignDomainWithGetSetIndices()
  • simplify some codes by merging the two branches of if stridable

Development history compressed into 36425cd: 42fa8bf..b8c3c86

Post-merge TODOs:

  • uncomment the deprecation warnings
  • switch the rest of module and test code to strides
  • add deprecation tests
  • update dyno resolver to handle range.strides field in Resolver::exit()
  • rename hasPosNegUnitStride to a better name
  • add tests of new assignment / initialization behaviors

Copy link
Contributor

@DanilaFe DanilaFe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only looked at compiler changes so far. Now moving on to module code.

Comment on lines 926 to 929
if ((!strcmp(ne->name, "boundedType") || !strcmp(ne->name, "stridable"))
&& at->symbol->hasFlag(FLAG_RANGE))
{
if (!strcmp(ne->name, "boundedType")) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could he nice to factor the repeated strcmp occurrences into boolean variables.

Comment on lines 2224 to 2226
while (AggregateType* parentAG = ag->dispatchParents.n == 0 ?
nullptr : ag->dispatchParents.v[0])
{
Copy link
Contributor

@DanilaFe DanilaFe May 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can ag->dispatchParents.v[0] ever be null if n != 0? If not, perhaps a nicer way to write this is:

Suggested change
while (AggregateType* parentAG = ag->dispatchParents.n == 0 ?
nullptr : ag->dispatchParents.v[0])
{
while (ag->dispatchParents.n != 0)
{
AggregateType* parentAG = ag->dispatchParents.v[0]

Comment on lines 926 to 929
if ((!strcmp(ne->name, "boundedType") || !strcmp(ne->name, "stridable"))
&& at->symbol->hasFlag(FLAG_RANGE))
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean to use two-space indents here? I just noticed it's only one space...

static void addRangeDeprecationClone(AggregateType* base, AggregateType* cur,
FnSymbol* fn1) {
// the position of the 'stride' field
int stridesPos = strcmp(base->symbol->name, "BaseRectangularDom") ? 10 : 5;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could these magic numbers 10 and 5 be computed somewhere, just for resilence's sake? Or is the deprecation warning short-term enough that this doesn't matter?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Computing them is probably more hassle than it is worth. I hope we can remove support for range.stridable soon enough that these numbers will remain correct. If these numbers do change, deprecation tests should catch that.

else if (pNamed != nullptr && !strcmp(pNamed->name, "strides"))
pNamed->replace(new NamedExpr("stridable", replSE));
else
se->replace(replSE);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't a type-safe replacement, is it? If I have a init proc that feeds strides to something that expects a strideKind, and then it gets replaced with a bool, it won't work? Or is there an implicit conversion to bool somehow (seems unlikely to me).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code is invoked only on a clone of the function built by AggregateType::buildDefaultInitializer(). Therefore strides is used only when passing to the parent initializer. In this context, the new stridable formal is safe to use because the parent initializers will most likely also have overloads that accept stridable. Otherwise there will be a compilation failure and the user-defined domain map will need to be ported over. Which is an acceptable outcome.

Comment on lines 767 to 769
if (replacedStridable(call, name, use))
; // handled
else

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (replacedStridable(call, name, use))
; // handled
else
if (replacedStridable(call, name, use))
continue; // handled

// Supports deprecation by Vass in 1.31 to implement #17131.
// chpl__buildDomainRuntimeType(..., stridable) -->
// chpl__buildDomainRuntimeType(..., strides) if we are in a DSI class.
bool replacedStridable(CallExpr* parentCall, const char* name,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling this function replacedStridable obfuscates the fact that it has a side effect (described in the comment above).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed to tryReplaceStridable.

Comment on lines 917 to 919
if (sym != NULL) {
if (!replacedStridableSR(name, usymExpr, sym))
resolveUnresolvedSymExpr(usymExpr, sym);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (sym != NULL) {
if (!replacedStridableSR(name, usymExpr, sym))
resolveUnresolvedSymExpr(usymExpr, sym);
if (sym != NULL) {
if (!replacedStridableSR(name, usymExpr, sym))
resolveUnresolvedSymExpr(usymExpr, sym);

@@ -1265,6 +1272,9 @@ static void checkMethodsOverride() {
FnSymbol* eFn = getOverrideCandidateGenericFn(fn);
if (erroredFunctions.count(eFn) == 0) {
if (fn->hasFlag(FLAG_OVERRIDE)) {
if (isDsiNewRectangularDom(fn)) {
// allow, for deprecation by Vass in 1.31 to implement #17131
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A more informative comment explaining why it's allowed would be nice here: "allowed so that child classes can still override stridable-based versions of the procedure, which is now strides-based". (?)

Comment on lines +1299 to +1301
return whole[(...(chpl__computeCyclic(this.idxType, locid, dist.targetLocDom.dims(), dist.startIdx)))]
// supports deprecation by Vass in 1.31 to implement #17131
: domain(rank, idxType, stridable=true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need casts like these?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The enclosing function has two return statements. The types of their return expressions need to match in order for the function to resolve. This return expression may have a domain type with a more specific value of strides than strideKind.any, whereas the other one always has strideKind.any, translated from stridable=true.

So maybe the right solution is to have the other return expression match the type of this return expression. Since I will be updating Cyclic to get rid of stridable altogether when stridable is deprecated in an upcoming PR, I will do that at that point.

Copy link
Contributor

@DanilaFe DanilaFe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to trust the .good file updates, which are mostly false to strideKind.one

@@ -252,7 +266,8 @@ proc computeZeroBasedRanges(ranges: _tuple) {
//

// would like 'whole: domain(?IT,?r,?)'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this still accurate? Particularly ? ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What we really would like is whole: rectangularDomain(?). However, this is assumed throughout DSIUtil.chpl, so I am removing this comment altogether.

@@ -349,7 +366,7 @@ proc densify(sArg: range(?,bounds=?B,stridable=?S), w: range(?IT,?,stridable=fal

// gotta have a special case, e.g.: s=1..0 w=5..6 IT=uint
if isUintType(IT) && s.isEmpty() then
return 1:IT..0:IT;
return new range(IT,B,S);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can't we use densiResult here? Does its behavior diverge or is writing range(IT,B,S) just simpler?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, in this case densiResult(sArg,w) == range(IT,B,S).
I could add a compilerAssert for this. For now, I just added a comment.

Comment on lines 790 to 791
compilerError("rectangular domains are not supported by",
" the distribution ", this.type:string);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
compilerError("rectangular domains are not supported by",
" the distribution ", this.type:string);
compilerError("rectangular domains are not supported by",
" the distribution ", this.type:string);

Comment on lines 725 to 728
if ! chpl_assignStrideIsSafe(a.strides, b.strides) then
compilerError("assigning to a domain with strideKind.",a.strides:string,
" from a domain with strideKind.", b.strides:string,
" without an explicit cast");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if ! chpl_assignStrideIsSafe(a.strides, b.strides) then
compilerError("assigning to a domain with strideKind.",a.strides:string,
" from a domain with strideKind.", b.strides:string,
" without an explicit cast");
if ! chpl_assignStrideIsSafe(a.strides, b.strides) then
compilerError("assigning to a domain with strideKind.",a.strides:string,
" from a domain with strideKind.", b.strides:string,
" without an explicit cast");

for s in chpl__tuplify(this.stride) do
if s < 0 {
warning("arrays and array slices with negatively-strided dimensions are currently unsupported and may lead to unexpected behavior; compile with -snoNegativeStrideWarnings to suppress this warning; the dimension(s) are: ", this.dsiDims());
break;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indentation is confusing here.

}

@chpldoc.nodoc
inline proc range.chpl_lastAsIntForIter {
if bounds == boundKind.both {
return this.lastAsInt;
} else {
if ! stridable {
if strides == strideKind.one {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hasUnitStride here too?

@@ -1349,9 +1650,12 @@ operator :(r: range(?), type t: range(?)) {
HaltWrappers.boundsCheckHalt("indexOrder -- Undefined on a range with ambiguous alignment.");

if ! contains(ind) then return (-1):intIdxType;
if ! stridable {
if strides == strideKind.one {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

more hasUnitStride opportunities?

Comment on lines 3476 to 3557
if ! newStrides.isPosNegOne() { // aka !newStrides.hasParamStride()
const first = this.orderToIndex(myFollowThis.first);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More peculiar indentation

const rStride = ranges(i).stride;
const rSignedStride = rStride:strType,
fSignedStride = followThis(i).stride:strType;
if rStride > 0 {
if ranges(i).hasPositiveStride() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rStride.isPositive()?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I use range.hasPositiveStride() because it is a param in some cases, whereas rStride.isPositive() cannot be a param because rStride is an integer and not a param.

@@ -1,3 +1,4 @@
negativeStrideWarnings.chpl:13: warning: when slicing with a range with a negative stride, the sign of the stride of the original range or domain/array dimension is currently preserved, but will be negated in a future release; compile with -snewSliceRule to switch to this new rule and turn off this warning
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra warning for the same line -- is this okay?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our warnings sometimes do that. I consider it a lower priority to fix this.

Signed-off-by: Vassily Litvinov <vasslitvinov@users.noreply.github.com>
Signed-off-by: Vassily Litvinov <vasslitvinov@users.noreply.github.com>
Signed-off-by: Vassily Litvinov <vasslitvinov@users.noreply.github.com>
@vasslitvinov vasslitvinov merged commit 1634178 into chapel-lang:main Jun 2, 2023
7 checks passed
@vasslitvinov vasslitvinov deleted the range-stridable branch June 2, 2023 06:23
vasslitvinov added a commit to vasslitvinov/chapel that referenced this pull request Jun 2, 2023
Signed-off-by: Vassily Litvinov <vasslitvinov@users.noreply.github.com>
vasslitvinov added a commit that referenced this pull request Jun 2, 2023
#22441 resulted in added `get` communications for the call
rhs.getIndices() that it hoisted out from the loop `for e in
lhs._arrs` in chpl_assignDomainWithGetSetIndices(). While hoisting
helps in many cases, here it was detrimental because this loop had
no iterations at all.

Given that chpl_assignDomainWithGetSetIndices already invokes
rhs.getIndices() outside of the loop, I changed the code
to invoke it just once and reuse its result whenever necessary.

I also moved the call to castIndices(), which #22441 also hoisted out
of the loop, back into the loop. However it probably does not matter
because it will be no-op in most cases, otherwise have low overhead.

r: @benharsh
vasslitvinov added a commit that referenced this pull request Jun 3, 2023
#22441 changed how some range bounds are calculated. As a result,
the compiler now produces a temp called `call_tmp`
where previously it was called `tmp`.

This PR adjusts the expectations that the test `anonymousRangeIter`
makes about the generated code.

Trivial, not reviewed.
vasslitvinov added a commit that referenced this pull request Jun 7, 2023
This updates the modules to the switch in #22441
from `range.stridable` to `range.strides`.

Most of the changes are renamings from `stridable` to `strides` and
replacing `anyStridable()` with `chpl_strideUnion()`. However
occasionally I did some code reorg and simplification, such as merging
two branches of an `if stridable` conditional into code not guarded by a
condition. Notably:

* Added overloads of `domain.stride` and `domain.alignment` that return
  a `param` for 1-D rectangular and sparse domains.
* Simplified `range.readThis()` and `range.init(..., fileReader, serializer)`;
  the latter now "throws", rightfully so.
* Removed an overload of binarySearch() that could result in an
  "ambiguous call" error, defeating its purpose of giving a user-friendly
  error message.
* Eliminated distracting differences in where-clauses of
  fileReader/fileWriter methods in IO.chpl

To do post-merge:
* enable the deprecation warnings that remain commented out since #22441
* create design issues related to uses of chpl_strideUnion et al.,
  see review comments

r: @benharsh
vasslitvinov added a commit that referenced this pull request Jun 8, 2023
This turns on deprecation warnings for uses of range/domain.stridable
introduced in #22441 and switches tests
from range/domain.stridable to `strides`.

While there:

* Fix the bug where `d by (step1:uint, step2:uint)` was not
  producing a positive-strided domain if `d` was such a domain.

* Remove `test/distributions/dm/n.chpl` because it has been unused
  for a long time.

* Remove the future `test/users/vass/crash1callDestructorsMain.chpl`
  because it no longer causes the internal error that it did eight years
  ago and bringing it uptodate with all the language changes since then
  would take a significant amount of time, making it not worth it.

I added back the alternative initializer on LocRADCache that I removed
in #22486 to support deprecation of user domain maps that happen to use it.

r: @jabraham17 @stonea
vasslitvinov added a commit that referenced this pull request Jun 16, 2023
Update the Ranges and Domains and Coercions chapters of the spec and the
comments in the ranges and other primers for the change
`range.stridable` --> `strides: strideKind` in #22441, with follow-ons
#22486 and #22508.

Also remove the remaining occurrences of `BoundedRangeType` from the
spec and primers -- it is deprecated as of #22059.

Remove the `const` return and yield intent in the Procedures, Iterators,
and Tuples sections of the spec -- it is unstable as of #22515. I did
not see any need to update the primers for this change.

While there, I did some rephrasing and restructuring of the text for
better readability or precision.

Post-merge: update the Chapel Evolution document.

r: @benharsh
vasslitvinov added a commit that referenced this pull request Jun 16, 2023
This PR updates the Chapel Evolution document for the change
range.stridable --> strides: strideKind in #22441 / #22486 / #22508
and for the change range.boundedType to range.bounds in #22059.

r: @benharsh
vasslitvinov added a commit that referenced this pull request Jan 4, 2024
#24136)

These features were deprecated in 1.31 as follows:

range.`boundedType` and `BoundedRangeType`
  issue: #17126
  implementation: #22059

range.`stridable`
  issue: #17131
  implementation: #22441, #22486, #22508

This PR removes support for these features, which was added in the above PRs,
and adjusts modules and tests accordingly.

More range/domain deprecated feature removals are next steps.

r: @jabraham17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants