This is an archive of the discontinued LLVM Phabricator instance.

[flang] Fix problems with constant arrays with lower bounds that are not 1
ClosedPublic

Authored by PeteSteinfeld on Jan 26 2021, 8:21 AM.

Details

Summary

There were two problems with constant arrays whose lower bound is not 1.
First, when folding the arrays, we were creating the folded array to have lower
bounds of 1 but not re-adjusting their lower bounds to the declared values.
Second, we were not calculating the extents correctly. Both of these problems
led to bogus error messages.

I fixed the first problem by adjusting the lower bounds in
NonPointerInitializationExpr() in Evaluate/check-expression.cpp. I found an
existing class and method that did exactly what was needed that was originally
designed to expand a scalar value into an array called ScalarConstantExpander.
I renamed this class to reflect its generalization to ArrayConstantMaker.

I fixed the second problem by changing the formula that calculates upper bounds
in in the function ComputeUpperBound() in Evaluate/shape.cpp.

I added tests that trigger the bogus error messages mentioned above along with
a constant folding tests that uses array operands with shapes that conform but
have different bounds.

Diff Detail

Event Timeline

PeteSteinfeld requested review of this revision.Jan 26 2021, 8:21 AM
PeteSteinfeld created this revision.
Herald added a project: Restricted Project. · View Herald TranscriptJan 26 2021, 8:21 AM
PeteSteinfeld added a project: Restricted Project.Jan 26 2021, 8:22 AM

Can you fix the problem by just calling "x.set_lbounds(GetLowerBounds())" on the folded result array and leaving ScalarConstantExpander alone?

Can you fix the problem by just calling "x.set_lbounds(GetLowerBounds())" on the folded result array and leaving ScalarConstantExpander alone?

The expression that needs to have its lower bounds modified is of type Expr<SomeType>. But the set_lbounds() method is defined for the types Constant<T>, ConstantBase<T>, and ConstantBounds<T>. So to use set_lbounds(), I need to walk down through the layers of Expr<> objects to get to an object of type Constant<T> and then call set_lbounds() on it.

So I could create a class to do this, but that class would be very similar to the exiting class that I've renamed as ArrayConstantMaker. Potential differences would be that it might not require a method that takes Parenthese<T> as an arugment (I'm not sure about this), the call to Reshape() would not be required, and the new class would need fewer constructors.

Thus, it seems to me that it's better to use a single class to create constant arrays with new lower bounds that handles both scalars and arrays.

Let me know if my analysis is wrong, or if you agree with my analysis but not me conclusion.

Can you fix the problem by just calling "x.set_lbounds(GetLowerBounds())" on the folded result array and leaving ScalarConstantExpander alone?

The expression that needs to have its lower bounds modified is of type Expr<SomeType>. But the set_lbounds() method is defined for the types Constant<T>, ConstantBase<T>, and ConstantBounds<T>. So to use set_lbounds(), I need to walk down through the layers of Expr<> objects to get to an object of type Constant<T> and then call set_lbounds() on it.

So I could create a class to do this, but that class would be very similar to the exiting class that I've renamed as ArrayConstantMaker. Potential differences would be that it might not require a method that takes Parenthese<T> as an arugment (I'm not sure about this), the call to Reshape() would not be required, and the new class would need fewer constructors.

Thus, it seems to me that it's better to use a single class to create constant arrays with new lower bounds that handles both scalars and arrays.

Let me know if my analysis is wrong, or if you agree with my analysis but not me conclusion.

I think I'd rather have two specifically purposed facilities for scalar expansion and for setting lower bounds than one mash-up of those two. If you must combine them, make sure that there's a CHECK that ensures that the original array is either scalar or has exactly the same shape.

I implemented a separate class to handle changing the lower bounds of array
constants as suggested by Peter. In the process I noticed that there was an
unused class in Evaluate/check-expression.cpp. Also, when implementing the new
class I found a bug when handling parenthesized expressions which also exists
in the class I was previously using, so I fixed it in both places. I also
added new tests that include parenthesized expressions.

klausler accepted this revision.Jan 27 2021, 3:00 PM
This revision is now accepted and ready to land.Jan 27 2021, 3:00 PM
tskeith added inline comments.Jan 27 2021, 3:09 PM
flang/lib/Evaluate/check-expression.cpp
320

I think this needs to be return std::move(x);

PeteSteinfeld added inline comments.Jan 27 2021, 3:17 PM
flang/lib/Evaluate/check-expression.cpp
320

Thanks, Tim. I'll change it.

tskeith added inline comments.Jan 27 2021, 3:42 PM
flang/lib/Evaluate/check-expression.cpp
312

Since lbounds has to be a non-empty optional, why make it optional at all? I.e. why not declare it as ConstantSubscripts &&lbounds?

PeteSteinfeld added inline comments.Jan 28 2021, 7:15 AM
flang/lib/Evaluate/check-expression.cpp
312

Thanks, Tim. Will do.

Changes in response to comments by Tim. Basically, better handling with
respect to moving data around by using rvalue references and eliminating
unnecessary use of the type "std::optional<>".

tskeith added inline comments.Jan 28 2021, 10:19 AM
flang/test/Evaluate/folding16.f90
4

I think you should be able to add this line to check the lower bound of c:
logical, parameter :: test_c = lbound(c, 1) == -1

But when I tried that it failed. (It's possible I don't understand these folding tests.)

PeteSteinfeld added inline comments.Jan 28 2021, 4:42 PM
flang/test/Evaluate/folding16.f90
4

Good catch! This test already has tests that test for the lower bound of arrays where the lower bound was negative, and the test was not reporting failure. It turns out, though, that the test itself was erroneous because the test script only checks for constants that begin with "test_". I will fix the test and the underlying bug.

I checked the other tests in this directory, and folding09.f90 has the same problem. Stay tuned for another change.

PeteSteinfeld added inline comments.Jan 29 2021, 7:16 AM
flang/test/Evaluate/folding16.f90
4

@tskeith, I've investigated this, and your test reveals two bugs, one with our tests and the other with constant folding of the intrinsic "lbound". Neither is related to the other changes in this commit, though.

So my plan is to merge this change request (almost) as is and then fix these other two bugs in a separate change. The one change I'll make is to the test folding16.f90 to enable the new tests I've added. Let me know if you think that's a bad idea.

tskeith accepted this revision.Jan 29 2021, 7:21 AM
tskeith added inline comments.
flang/test/Evaluate/folding16.f90
4

Sounds good to me.

Responsed to comments from Tim.

Tim noticed that constant folding for the intrinsic "lbounds" wasn't working,
even though we had a test for it which was passing. This revealed a problem in
our tests that I fixed. I'll fix the constant folding problem in a later
change.

This revision was landed with ongoing or failed builds.Jan 29 2021, 8:15 AM
This revision was automatically updated to reflect the committed changes.