
Hi, This patch implements support for the following directives : - `!DIR$ NOUNROLL_AND_JAM` to disable unrolling and jamming on a DO LOOP. - `!DIR$ NOUNROLL` to disable unrolling on a DO LOOP. - `!DIR$ NOVECTOR` to disable vectorization on a DO LOOP.
141 lines
5.0 KiB
C++
141 lines
5.0 KiB
C++
//===-- lib/Semantics/canonicalize-directives.cpp -------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "canonicalize-directives.h"
|
|
#include "flang/Parser/parse-tree-visitor.h"
|
|
#include "flang/Semantics/tools.h"
|
|
|
|
namespace Fortran::semantics {
|
|
|
|
using namespace parser::literals;
|
|
|
|
// Check that directives are associated with the correct constructs.
|
|
// Directives that need to be associated with other constructs in the execution
|
|
// part are moved to the execution part so they can be checked there.
|
|
class CanonicalizationOfDirectives {
|
|
public:
|
|
CanonicalizationOfDirectives(parser::Messages &messages)
|
|
: messages_{messages} {}
|
|
|
|
template <typename T> bool Pre(T &) { return true; }
|
|
template <typename T> void Post(T &) {}
|
|
|
|
// Move directives that must appear in the Execution part out of the
|
|
// Specification part.
|
|
void Post(parser::SpecificationPart &spec);
|
|
bool Pre(parser::ExecutionPart &x);
|
|
|
|
// Ensure that directives associated with constructs appear accompanying the
|
|
// construct.
|
|
void Post(parser::Block &block);
|
|
|
|
private:
|
|
// Ensure that loop directives appear immediately before a loop.
|
|
void CheckLoopDirective(parser::CompilerDirective &dir, parser::Block &block,
|
|
std::list<parser::ExecutionPartConstruct>::iterator it);
|
|
|
|
parser::Messages &messages_;
|
|
|
|
// Directives to be moved to the Execution part from the Specification part.
|
|
std::list<common::Indirection<parser::CompilerDirective>>
|
|
directivesToConvert_;
|
|
};
|
|
|
|
bool CanonicalizeDirectives(
|
|
parser::Messages &messages, parser::Program &program) {
|
|
CanonicalizationOfDirectives dirs{messages};
|
|
Walk(program, dirs);
|
|
return !messages.AnyFatalError();
|
|
}
|
|
|
|
static bool IsExecutionDirective(const parser::CompilerDirective &dir) {
|
|
return std::holds_alternative<parser::CompilerDirective::VectorAlways>(
|
|
dir.u) ||
|
|
std::holds_alternative<parser::CompilerDirective::Unroll>(dir.u) ||
|
|
std::holds_alternative<parser::CompilerDirective::UnrollAndJam>(dir.u) ||
|
|
std::holds_alternative<parser::CompilerDirective::NoVector>(dir.u) ||
|
|
std::holds_alternative<parser::CompilerDirective::NoUnroll>(dir.u) ||
|
|
std::holds_alternative<parser::CompilerDirective::NoUnrollAndJam>(dir.u);
|
|
}
|
|
|
|
void CanonicalizationOfDirectives::Post(parser::SpecificationPart &spec) {
|
|
auto &list{
|
|
std::get<std::list<common::Indirection<parser::CompilerDirective>>>(
|
|
spec.t)};
|
|
for (auto it{list.begin()}; it != list.end();) {
|
|
if (IsExecutionDirective(it->value())) {
|
|
directivesToConvert_.emplace_back(std::move(*it));
|
|
it = list.erase(it);
|
|
} else {
|
|
++it;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool CanonicalizationOfDirectives::Pre(parser::ExecutionPart &x) {
|
|
auto origFirst{x.v.begin()};
|
|
for (auto &dir : directivesToConvert_) {
|
|
x.v.insert(origFirst,
|
|
parser::ExecutionPartConstruct{
|
|
parser::ExecutableConstruct{std::move(dir)}});
|
|
}
|
|
|
|
directivesToConvert_.clear();
|
|
return true;
|
|
}
|
|
|
|
void CanonicalizationOfDirectives::CheckLoopDirective(
|
|
parser::CompilerDirective &dir, parser::Block &block,
|
|
std::list<parser::ExecutionPartConstruct>::iterator it) {
|
|
|
|
// Skip over this and other compiler directives
|
|
while (it != block.end() && parser::Unwrap<parser::CompilerDirective>(*it)) {
|
|
++it;
|
|
}
|
|
|
|
if (it == block.end() ||
|
|
(!parser::Unwrap<parser::DoConstruct>(*it) &&
|
|
!parser::Unwrap<parser::OpenACCLoopConstruct>(*it) &&
|
|
!parser::Unwrap<parser::OpenACCCombinedConstruct>(*it))) {
|
|
std::string s{parser::ToUpperCaseLetters(dir.source.ToString())};
|
|
s.pop_back(); // Remove trailing newline from source string
|
|
messages_.Say(
|
|
dir.source, "A DO loop must follow the %s directive"_warn_en_US, s);
|
|
}
|
|
}
|
|
|
|
void CanonicalizationOfDirectives::Post(parser::Block &block) {
|
|
for (auto it{block.begin()}; it != block.end(); ++it) {
|
|
if (auto *dir{parser::Unwrap<parser::CompilerDirective>(*it)}) {
|
|
std::visit(
|
|
common::visitors{[&](parser::CompilerDirective::VectorAlways &) {
|
|
CheckLoopDirective(*dir, block, it);
|
|
},
|
|
[&](parser::CompilerDirective::Unroll &) {
|
|
CheckLoopDirective(*dir, block, it);
|
|
},
|
|
[&](parser::CompilerDirective::UnrollAndJam &) {
|
|
CheckLoopDirective(*dir, block, it);
|
|
},
|
|
[&](parser::CompilerDirective::NoVector &) {
|
|
CheckLoopDirective(*dir, block, it);
|
|
},
|
|
[&](parser::CompilerDirective::NoUnroll &) {
|
|
CheckLoopDirective(*dir, block, it);
|
|
},
|
|
[&](parser::CompilerDirective::NoUnrollAndJam &) {
|
|
CheckLoopDirective(*dir, block, it);
|
|
},
|
|
[&](auto &) {}},
|
|
dir->u);
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace Fortran::semantics
|