-
Notifications
You must be signed in to change notification settings - Fork 15.4k
[flang] Improve contiguity checker for component references #153222
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
Conversation
Component references to array values had a couple of TODOs in the contiguity checker; implement them so that contiguity errors/warnings and code generation are more accurate. Specifically, "a(1:1)%b" is contiguous because there's a single element; "a(1:2)%b" is contiguous when the type of "a" has but a single component. The case of multiple components in the type is discontiguous when the array is known to have multiple elements.
|
@llvm/pr-subscribers-flang-fir-hlfir @llvm/pr-subscribers-flang-semantics Author: Peter Klausler (klausler) ChangesComponent references to array values had a couple of TODOs in the contiguity checker; implement them so that contiguity errors/warnings and code generation are more accurate. Specifically, "a(1:1)%b" is contiguous because there's a single element; "a(1:2)%b" is contiguous when the type of "a" has but a single component. The case of multiple components in the type is discontiguous when the array is known to have multiple elements. Full diff: https://github.com/llvm/llvm-project/pull/153222.diff 3 Files Affected:
diff --git a/flang/lib/Evaluate/check-expression.cpp b/flang/lib/Evaluate/check-expression.cpp
index 3d7f01d56c465..e8455bc372846 100644
--- a/flang/lib/Evaluate/check-expression.cpp
+++ b/flang/lib/Evaluate/check-expression.cpp
@@ -951,18 +951,40 @@ class IsContiguousHelper
if (x.base().Rank() == 0) {
return (*this)(x.GetLastSymbol());
} else {
- if (Result baseIsContiguous{(*this)(x.base())}) {
+ const DataRef &base{x.base()};
+ if (Result baseIsContiguous{(*this)(base)}) {
if (!*baseIsContiguous) {
return false;
+ } else {
+ bool sizeKnown{false};
+ if (auto constShape{GetConstantExtents(context_, x)}) {
+ sizeKnown = true;
+ if (GetSize(*constShape) <= 1) {
+ return true; // empty or singleton
+ }
+ }
+ const Symbol &last{base.GetLastSymbol()};
+ if (auto type{DynamicType::From(last)}) {
+ CHECK(type->category() == TypeCategory::Derived);
+ if (!type->IsPolymorphic()) {
+ const auto &derived{type->GetDerivedTypeSpec()};
+ if (const auto *scope{derived.scope()}) {
+ auto iter{scope->begin()};
+ if (++iter == scope->end()) {
+ return true; // type has but one component
+ } else if (sizeKnown) {
+ return false; // multiple components & array size is known > 1
+ }
+ }
+ }
+ }
}
- // TODO: should be true if base is contiguous and this is only
- // component, or when the base has at most one element
}
return std::nullopt;
}
}
Result operator()(const ComplexPart &x) const {
- // TODO: should be true when base is empty array, too
+ // TODO: should be true when base is empty array or singleton, too
return x.complex().Rank() == 0;
}
Result operator()(const Substring &x) const {
diff --git a/flang/test/Lower/components.f90 b/flang/test/Lower/components.f90
index 5afde4bd0a959..f0caddbaaa914 100644
--- a/flang/test/Lower/components.f90
+++ b/flang/test/Lower/components.f90
@@ -136,7 +136,7 @@ subroutine lhs_char_section(a)
! CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_5]] typeparams %[[VAL_6]] {fortran_attrs = #fir.var_attrs<parameter>, uniq_name = "_QQclX68656C6C6F"} : (!fir.ref<!fir.char<1,5>>, index) -> (!fir.ref<!fir.char<1,5>>, !fir.ref<!fir.char<1,5>>)
! CHECK: %[[VAL_8:.*]] = arith.constant 5 : index
! CHECK: %[[VAL_9:.*]] = hlfir.designate %[[VAL_4]]#0{"c"} shape %[[VAL_3]] typeparams %[[VAL_8]] : (!fir.ref<!fir.array<10x!fir.type<_QFlhs_char_sectionTt
-! CHECK: hlfir.assign %[[VAL_7]]#0 to %[[VAL_9]] : !fir.ref<!fir.char<1,5>>, !fir.box<!fir.array<10x!fir.char<1,5>>>
+! CHECK: hlfir.assign %[[VAL_7]]#0 to %[[VAL_9]] : !fir.ref<!fir.char<1,5>>, !fir.ref<!fir.array<10x!fir.char<1,5>>>
! CHECK: return
! CHECK: }
@@ -163,7 +163,7 @@ subroutine rhs_char_section(a, c)
! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_7]](%[[VAL_10]]) typeparams %[[VAL_8]] dummy_scope %[[VAL_2]] {uniq_name = "_QFrhs_char_sectionEc"} : (!fir.ref<!fir.array<10x!fir.char<1,10>>>, !fir.shape<1>, index, !fir.dscope) -> (!fir.ref<!fir.array<10x!fir.char<1,10>>>, !fir.ref<!fir.array<10x!fir.char<1,10>>>)
! CHECK: %[[VAL_12:.*]] = arith.constant 10 : index
! CHECK: %[[VAL_13:.*]] = hlfir.designate %[[VAL_5]]#0{"c"} shape %[[VAL_4]] typeparams %[[VAL_12]] : (!fir.ref<!fir.array<10x!fir.type<_QFrhs_char_sectionTt
-! CHECK: hlfir.assign %[[VAL_13]] to %[[VAL_11]]#0 : !fir.box<!fir.array<10x!fir.char<1,10>>>, !fir.ref<!fir.array<10x!fir.char<1,10>>>
+! CHECK: hlfir.assign %[[VAL_13]] to %[[VAL_11]]#0 : !fir.ref<!fir.array<10x!fir.char<1,10>>>, !fir.ref<!fir.array<10x!fir.char<1,10>>>
! CHECK: return
! CHECK: }
@@ -192,7 +192,7 @@ subroutine elemental_char_section(a, i)
! CHECK: %[[VAL_13:.*]]:2 = hlfir.declare %[[VAL_11]] typeparams %[[VAL_12]] {fortran_attrs = #fir.var_attrs<parameter>, uniq_name = "_QQclX68656C6C6F"} : (!fir.ref<!fir.char<1,5>>, index) -> (!fir.ref<!fir.char<1,5>>, !fir.ref<!fir.char<1,5>>)
! CHECK: %[[VAL_14:.*]] = hlfir.elemental %[[VAL_4]] unordered : (!fir.shape<1>) -> !hlfir.expr<10xi32> {
! CHECK: ^bb0(%[[VAL_15:.*]]: index):
-! CHECK: %[[VAL_16:.*]] = hlfir.designate %[[VAL_10]] (%[[VAL_15]]) typeparams %[[VAL_9]] : (!fir.box<!fir.array<10x!fir.char<1,10>>>, index, index) -> !fir.ref<!fir.char<1,10>>
+! CHECK: %[[VAL_16:.*]] = hlfir.designate %[[VAL_10]] (%[[VAL_15]]) typeparams %[[VAL_9]] : (!fir.ref<!fir.array<10x!fir.char<1,10>>>, index, index) -> !fir.ref<!fir.char<1,10>>
! CHECK: %[[VAL_17:.*]] = arith.constant false
! CHECK: %[[VAL_18:.*]] = fir.convert %[[VAL_16]] : (!fir.ref<!fir.char<1,10>>) -> !fir.ref<i8>
! CHECK: %[[VAL_19:.*]] = fir.convert %[[VAL_9]] : (index) -> i64
diff --git a/flang/test/Semantics/contiguous02.f90 b/flang/test/Semantics/contiguous02.f90
new file mode 100644
index 0000000000000..6543ea92b9403
--- /dev/null
+++ b/flang/test/Semantics/contiguous02.f90
@@ -0,0 +1,27 @@
+! RUN: %python %S/test_errors.py %s %flang_fc1 -pedantic
+subroutine s1
+ type :: d1
+ real :: x
+ end type
+ type :: d2
+ type(d1) :: x
+ end type
+ type(d1), target :: a(5)
+ type(d2), target :: b(5)
+ real, pointer, contiguous :: c(:)
+ c => a%x ! okay, type has single component
+ c => b%x%x ! okay, types have single components
+end
+
+subroutine s2
+ type :: d1
+ real :: x, y
+ end type
+ type(d1), target :: b(5)
+ real, pointer, contiguous :: c(:)
+ !ERROR: CONTIGUOUS pointer may not be associated with a discontiguous target
+ c => b%x
+ c => b(1:1)%x ! okay, one element
+ !ERROR: CONTIGUOUS pointer may not be associated with a discontiguous target
+ c => b(1:2)%x
+end
|
Component references to array values had a couple of TODOs in the contiguity checker; implement them so that contiguity errors/warnings and code generation are more accurate. Specifically, "a(1:1)%b" is contiguous because there's a single element; "a(1:2)%b" is contiguous when the type of "a" has but a single component. The case of multiple components in the type is discontiguous when the array is known to have multiple elements.