-
Notifications
You must be signed in to change notification settings - Fork 11k
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
[flang][hlfir] Do not emit extra declare for dummy used in BLOCK #69184
Conversation
When a variable is used in a specification expression in a scope, it is added to the list of variables that must be instantiated when lowering the scope. When lowering a BLOCK, this caused instantiateVar to be called again on all the host block variables appearing in block variable specification expressions. This caused an extra declare to be emitted for dummy inside block (for non dummy, instantiateVar is a no-op if the symbol is already mapped). Only call instantiateVar if the symbol is not mapped when lowering BLOCK variables.
@llvm/pr-subscribers-flang-fir-hlfir Author: None (jeanPerier) ChangesWhen a variable is used in a specification expression in a scope, it is added to the list of variables that must be instantiated when lowering the scope. When lowering a BLOCK, this caused instantiateVar to be called again on all the host block variables appearing in block variable specification expressions. This caused an extra declare to be emitted for dummy inside block (for non dummy, instantiateVar is a no-op if the symbol is already mapped). Only call instantiateVar if the symbol is not mapped when lowering BLOCK variables. Full diff: https://github.com/llvm/llvm-project/pull/69184.diff 2 Files Affected:
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 5ac4d822faaae58..e6d6a19009e9de6 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -2610,8 +2610,12 @@ class FirConverter : public Fortran::lower::AbstractConverter {
scopeBlockIdMap.try_emplace(&scope, ++blockId);
Fortran::lower::AggregateStoreMap storeMap;
for (const Fortran::lower::pft::Variable &var :
- Fortran::lower::pft::getScopeVariableList(scope))
- instantiateVar(var, storeMap);
+ Fortran::lower::pft::getScopeVariableList(scope)) {
+ // Do no instantiate again variables from the block host
+ // that appears in specification of block variables.
+ if (!var.hasSymbol() || !lookupSymbol(var.getSymbol()))
+ instantiateVar(var, storeMap);
+ }
} else if (e.getIf<Fortran::parser::EndBlockStmt>()) {
if (eval.lowerAsUnstructured())
maybeStartBlock(e.block);
diff --git a/flang/test/Lower/HLFIR/convert-variable-block.f90 b/flang/test/Lower/HLFIR/convert-variable-block.f90
new file mode 100644
index 000000000000000..30f8eacaaed17bd
--- /dev/null
+++ b/flang/test/Lower/HLFIR/convert-variable-block.f90
@@ -0,0 +1,25 @@
+! Test that hlfir.declare is not created again for dummy arguments
+! used in specifications of BLOCK variables.
+! RUN: bbc -emit-hlfir %s -o - | FileCheck %s
+
+subroutine test(n)
+ integer(8) :: n
+ call before_block()
+ block
+ real :: x(n)
+ call foo(x)
+ end block
+end subroutine
+! CHECK-LABEL: func.func @_QPtest(
+! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<i64> {fir.bindc_name = "n"}) {
+! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFtestEn"} : (!fir.ref<i64>) -> (!fir.ref<i64>, !fir.ref<i64>)
+! CHECK: fir.call @_QPbefore_block() {{.*}}: () -> ()
+! CHECK: %[[VAL_3:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref<i64>
+! CHECK: %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (i64) -> index
+! CHECK: %[[VAL_5:.*]] = arith.constant 0 : index
+! CHECK: %[[VAL_6:.*]] = arith.cmpi sgt, %[[VAL_4]], %[[VAL_5]] : index
+! CHECK: %[[VAL_7:.*]] = arith.select %[[VAL_6]], %[[VAL_4]], %[[VAL_5]] : index
+! CHECK: %[[VAL_8:.*]] = fir.alloca !fir.array<?xf32>, %[[VAL_7]] {bindc_name = "x", uniq_name = "_QFtestB1Ex"}
+! CHECK: %[[VAL_9:.*]] = fir.shape %[[VAL_7]] : (index) -> !fir.shape<1>
+! CHECK: %[[VAL_10:.*]]:2 = hlfir.declare %[[VAL_8]](%[[VAL_9]]) {uniq_name = "_QFtestB1Ex"} : (!fir.ref<!fir.array<?xf32>>, !fir.shape<1>) -> (!fir.box<!fir.array<?xf32>>, !fir.ref<!fir.array<?xf32>>)
+! CHECK: fir.call @_QPfoo(%[[VAL_10]]#1) {{.*}}: (!fir.ref<!fir.array<?xf32>>) -> ()
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you, Jean!
Would it be possible to do this earlier, something like this:
|
Not currently because this analysis does not have access to the current symbol mapping. From a library/tools perspective, I would rather avoid having the PFT tools behavior depending on the current state of the Bridge (that comes afterwards). @vdonaldson, I can move it into instantiateVar here though if I propagate some flag that instantiated variable should be skipped. Would that be better? |
Probably yes, if the propagation code is fairly simple. But I'm still inclined to think it would be better though to do this earlier if that is reasonable, which it might or might not be. One idea there is to explicitly save the incoming |
That would at likely not work with used module symbols/host associated variables whose scope may differ from the one being analyzed. I am not saying that what you are suggesting is not possible, but I would rather avoid making the PFT analysis more complex if possible. The gain seems small to me unless you have a program with thousands of host variables being used in block variable specifications. The nicest fix should be to have instantiateVariable rely on something else to propagate the IR dummy/results and always refuse to instantiate again symbols. But it is too much refactoring for what needs to be fixed here IMHO. |
A simple update to However, the So I'm ok with either the original change, or your possible alternate fix that moves the check near the beginning of Thanks for the fix. |
Thanks for the review Val! I will keep it as it is. Threading the boolean makes things a bit harder to read in instantiateVar. |
When a variable is used in a specification expression in a scope, it is added to the list of variables that must be instantiated when lowering the scope. When lowering a BLOCK, this caused instantiateVar to be called again on all the host block variables appearing in block variable specification expressions. This caused an extra declare to be emitted for dummy inside block (for non dummy, instantiateVar is a no-op if the symbol is already mapped).
Only call instantiateVar if the symbol is not mapped when lowering BLOCK variables.