forked from OSchip/llvm-project
[flang] canonicalize DO constructs
Fix a bug with BLOCK DATA name matching Add tests and finish up DO loop canonicalization Original-commit: flang-compiler/f18@2d93b2819c Reviewed-on: https://github.com/flang-compiler/f18/pull/193 Tree-same-pre-rewrite: false
This commit is contained in:
parent
507ba5c3a1
commit
4972485598
|
@ -15,6 +15,7 @@
|
|||
|
||||
add_library(FortranSemantics
|
||||
attr.cc
|
||||
canonicalize-do.cc
|
||||
expression.cc
|
||||
mod-file.cc
|
||||
resolve-labels.cc
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
// Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "canonicalize-do.h"
|
||||
#include "../parser/parse-tree-visitor.h"
|
||||
|
||||
namespace Fortran::semantics {
|
||||
|
||||
class CanonicalizationOfDoLoops {
|
||||
public:
|
||||
CanonicalizationOfDoLoops() = default;
|
||||
|
||||
template<typename T> bool Pre(T &) { return true; }
|
||||
template<typename T> void Post(T &) {}
|
||||
bool Pre(parser::ExecutionPart &executionPart) {
|
||||
const auto &endIter{executionPart.v.end()};
|
||||
currentList_ = &executionPart.v;
|
||||
for (auto iter{executionPart.v.begin()}; iter != endIter; ++iter) {
|
||||
iter = CheckStatement(iter);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
template<typename T> bool Pre(parser::Statement<T> &statement) {
|
||||
if (!labels_.empty() && statement.label.has_value() &&
|
||||
labels_.back() == *statement.label) {
|
||||
auto currentLabel{labels_.back()};
|
||||
do {
|
||||
currentIter_ = MakeCanonicalForm(labelDoIters_.back(), currentIter_);
|
||||
labelDoIters_.pop_back();
|
||||
labels_.pop_back();
|
||||
} while (!labels_.empty() && labels_.back() == currentLabel);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
parser::Block SpliceBlock(
|
||||
parser::Block::iterator beginLoop, parser::Block::iterator endLoop) {
|
||||
parser::Block block;
|
||||
block.splice(block.begin(), *currentList_, ++beginLoop, ++endLoop);
|
||||
return block;
|
||||
}
|
||||
std::optional<parser::LoopControl> CreateLoopControl(
|
||||
std::optional<parser::LoopControl> &loopControlOpt) {
|
||||
if (loopControlOpt.has_value()) {
|
||||
return std::optional<parser::LoopControl>(
|
||||
parser::LoopControl{loopControlOpt->u});
|
||||
}
|
||||
return std::optional<parser::LoopControl>{};
|
||||
}
|
||||
std::optional<parser::LoopControl> ExtractLoopControl(
|
||||
const parser::Block::iterator &startLoop) {
|
||||
return CreateLoopControl(std::get<std::optional<parser::LoopControl>>(
|
||||
std::get<parser::Statement<common::Indirection<parser::LabelDoStmt>>>(
|
||||
std::get<parser::ExecutableConstruct>(startLoop->u).u)
|
||||
.statement->t));
|
||||
}
|
||||
parser::Block::iterator MakeCanonicalForm(
|
||||
const parser::Block::iterator &startLoop,
|
||||
const parser::Block::iterator &endLoop) {
|
||||
std::get<parser::ExecutableConstruct>(startLoop->u).u =
|
||||
common::Indirection<parser::DoConstruct>{std::make_tuple(
|
||||
parser::Statement<parser::NonLabelDoStmt>{
|
||||
std::optional<parser::Label>{},
|
||||
parser::NonLabelDoStmt{
|
||||
std::make_tuple(std::optional<parser::Name>{},
|
||||
ExtractLoopControl(startLoop))}},
|
||||
SpliceBlock(startLoop, endLoop),
|
||||
parser::Statement<parser::EndDoStmt>{std::optional<parser::Label>{},
|
||||
parser::EndDoStmt{std::optional<parser::Name>{}}})};
|
||||
return startLoop;
|
||||
}
|
||||
parser::Block::iterator CheckStatement(const parser::Block::iterator &iter) {
|
||||
currentIter_ = iter;
|
||||
parser::ExecutionPartConstruct &executionPartConstruct{*iter};
|
||||
if (auto *executableConstruct = std::get_if<parser::ExecutableConstruct>(
|
||||
&executionPartConstruct.u)) {
|
||||
if (auto *labelDoLoop = std::get_if<
|
||||
parser::Statement<common::Indirection<parser::LabelDoStmt>>>(
|
||||
&executableConstruct->u)) {
|
||||
labelDoIters_.push_back(iter);
|
||||
labels_.push_back(std::get<parser::Label>(labelDoLoop->statement->t));
|
||||
} else if (!labels_.empty()) {
|
||||
parser::Walk(executableConstruct->u, *this);
|
||||
}
|
||||
}
|
||||
return currentIter_;
|
||||
}
|
||||
|
||||
std::vector<parser::Block::iterator> labelDoIters_;
|
||||
std::vector<parser::Label> labels_;
|
||||
parser::Block::iterator currentIter_;
|
||||
parser::Block *currentList_;
|
||||
};
|
||||
|
||||
void CanonicalizeDo(parser::Program &program) {
|
||||
CanonicalizationOfDoLoops canonicalizationOfDoLoops;
|
||||
parser::Walk(program, canonicalizationOfDoLoops);
|
||||
}
|
||||
|
||||
} // namespace Fortran::semantics
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef FORTRAN_SEMANTICS_CANONICALIZE_DO_H_
|
||||
#define FORTRAN_SEMANTICS_CANONICALIZE_DO_H_
|
||||
|
||||
namespace Fortran::parser {
|
||||
struct Program;
|
||||
} // namespace Fortran::parser
|
||||
|
||||
namespace Fortran::semantics {
|
||||
void CanonicalizeDo(parser::Program &program);
|
||||
} // namespace Fortran::semantics
|
||||
#endif // FORTRAN_SEMANTICS_CANONICALIZE_DO_H_
|
|
@ -13,6 +13,7 @@
|
|||
// limitations under the License.
|
||||
|
||||
#include "semantics.h"
|
||||
#include "canonicalize-do.h"
|
||||
#include "mod-file.h"
|
||||
#include "resolve-labels.h"
|
||||
#include "resolve-names.h"
|
||||
|
@ -52,6 +53,7 @@ bool Semantics::Perform(parser::Program &program) {
|
|||
if (AnyFatalError()) {
|
||||
return false;
|
||||
}
|
||||
CanonicalizeDo(program);
|
||||
ModFileWriter writer;
|
||||
writer.set_directory(moduleDirectory_);
|
||||
if (!writer.WriteAll(globalScope_)) {
|
||||
|
|
|
@ -91,6 +91,10 @@ set(LABEL_TESTS
|
|||
label*.[Ff]90
|
||||
)
|
||||
|
||||
set(CANONDO_TESTS
|
||||
canondo*.[Ff]90
|
||||
)
|
||||
|
||||
foreach(test ${ERROR_TESTS})
|
||||
add_test(NAME ${test} COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/test_errors.sh ${test})
|
||||
endforeach()
|
||||
|
@ -106,3 +110,7 @@ endforeach()
|
|||
foreach(test ${LABEL_TESTS})
|
||||
add_test(NAME ${test} COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/test_any.sh ${test})
|
||||
endforeach()
|
||||
|
||||
foreach(test ${CANONDO_TESTS})
|
||||
add_test(NAME ${test} COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/test_any.sh ${test})
|
||||
endforeach()
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
! Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
|
||||
!
|
||||
! Licensed under the Apache License, Version 2.0 (the "License");
|
||||
! you may not use this file except in compliance with the License.
|
||||
! You may obtain a copy of the License at
|
||||
!
|
||||
! http://www.apache.org/licenses/LICENSE-2.0
|
||||
!
|
||||
! Unless required by applicable law or agreed to in writing, software
|
||||
! distributed under the License is distributed on an "AS IS" BASIS,
|
||||
! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
! See the License for the specific language governing permissions and
|
||||
! limitations under the License.
|
||||
|
||||
! negative test -- invalid labels, out of range
|
||||
|
||||
! RUN: ${F18} -funparse-with-symbols %s 2>&1 | ${FileCheck} %s
|
||||
! CHECK: end do
|
||||
|
||||
SUBROUTINE sub00(a,b,n,m)
|
||||
INTEGER n,m
|
||||
REAL a(n,m), b(n,m)
|
||||
|
||||
DO 10 j = 1,m
|
||||
DO 10 i = 1,n
|
||||
g = a(i,j) - b(i,j)
|
||||
10 PRINT *, g
|
||||
END SUBROUTINE sub00
|
|
@ -0,0 +1,28 @@
|
|||
! Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
|
||||
!
|
||||
! Licensed under the Apache License, Version 2.0 (the "License");
|
||||
! you may not use this file except in compliance with the License.
|
||||
! You may obtain a copy of the License at
|
||||
!
|
||||
! http://www.apache.org/licenses/LICENSE-2.0
|
||||
!
|
||||
! Unless required by applicable law or agreed to in writing, software
|
||||
! distributed under the License is distributed on an "AS IS" BASIS,
|
||||
! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
! See the License for the specific language governing permissions and
|
||||
! limitations under the License.
|
||||
|
||||
! negative test -- invalid labels, out of range
|
||||
|
||||
! RUN: ${F18} -funparse-with-symbols %s 2>&1 | ${FileCheck} %s
|
||||
! CHECK: end do
|
||||
|
||||
SUBROUTINE sub00(a,b,n,m)
|
||||
INTEGER n,m
|
||||
REAL a(n,m), b(n,m)
|
||||
|
||||
i = n-1
|
||||
DO 10 j = 1,m
|
||||
g = a(i,j) - b(i,j)
|
||||
10 PRINT *, g
|
||||
END SUBROUTINE sub00
|
Loading…
Reference in New Issue