[flang][OpenMP] Implement OpenMP stylized expressions (#165049)

Consider OpenMP stylized expression to be a template to be instantiated
with a series of types listed on the containing directive (currently
DECLARE_REDUCTION). Create a series of instantiations in the parser,
allowing OpenMP special variables to be declared separately for each
type.

---------

Co-authored-by: Tom Eccles <tom.eccles@arm.com>
This commit is contained in:
Krzysztof Parzyszek 2025-10-28 12:45:04 -05:00 committed by GitHub
parent 56c1d35bfd
commit cd40bc487a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 815 additions and 237 deletions

View File

@ -599,7 +599,7 @@ public:
NODE(parser, OmpInitClause)
NODE(OmpInitClause, Modifier)
NODE(parser, OmpInitializerClause)
NODE(parser, OmpInitializerProc)
NODE(parser, OmpInitializerExpression)
NODE(parser, OmpInReductionClause)
NODE(OmpInReductionClause, Modifier)
NODE(parser, OmpInteropPreference)
@ -677,6 +677,10 @@ public:
NODE_ENUM(OmpSeverityClause, Severity)
NODE(parser, OmpStepComplexModifier)
NODE(parser, OmpStepSimpleModifier)
NODE(parser, OmpStylizedDeclaration)
NODE(parser, OmpStylizedExpression)
NODE(parser, OmpStylizedInstance)
NODE(OmpStylizedInstance, Instance)
NODE(parser, OmpTaskDependenceType)
NODE_ENUM(OmpTaskDependenceType, Value)
NODE(parser, OmpTaskReductionClause)

View File

@ -25,6 +25,13 @@
namespace Fortran::parser::omp {
template <typename T> constexpr auto addr_if(std::optional<T> &x) {
return x ? &*x : nullptr;
}
template <typename T> constexpr auto addr_if(const std::optional<T> &x) {
return x ? &*x : nullptr;
}
namespace detail {
using D = llvm::omp::Directive;
@ -133,9 +140,24 @@ template <typename T> OmpDirectiveName GetOmpDirectiveName(const T &x) {
}
const OmpObjectList *GetOmpObjectList(const OmpClause &clause);
template <typename T>
const T *GetFirstArgument(const OmpDirectiveSpecification &spec) {
for (const OmpArgument &arg : spec.Arguments().v) {
if (auto *t{std::get_if<T>(&arg.u)}) {
return t;
}
}
return nullptr;
}
const BlockConstruct *GetFortranBlockConstruct(
const ExecutionPartConstruct &epc);
const OmpCombinerExpression *GetCombinerExpr(
const OmpReductionSpecifier &rspec);
const OmpInitializerExpression *GetInitializerExpr(const OmpClause &init);
} // namespace Fortran::parser::omp
#endif // FORTRAN_PARSER_OPENMP_UTILS_H

View File

@ -24,7 +24,9 @@
#include "provenance.h"
#include "flang/Common/idioms.h"
#include "flang/Common/indirection.h"
#include "flang/Common/reference.h"
#include "flang/Support/Fortran.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Frontend/OpenACC/ACC.h.inc"
#include "llvm/Frontend/OpenMP/OMP.h"
#include "llvm/Frontend/OpenMP/OMPConstants.h"
@ -3510,6 +3512,8 @@ struct OmpDirectiveName {
// type-name list item
struct OmpTypeName {
CharBlock source;
mutable const semantics::DeclTypeSpec *declTypeSpec{nullptr};
UNION_CLASS_BOILERPLATE(OmpTypeName);
std::variant<TypeSpec, DeclarationTypeSpec> u;
};
@ -3538,6 +3542,39 @@ struct OmpObjectList {
WRAPPER_CLASS_BOILERPLATE(OmpObjectList, std::list<OmpObject>);
};
struct OmpStylizedDeclaration {
COPY_AND_ASSIGN_BOILERPLATE(OmpStylizedDeclaration);
// Since "Reference" isn't handled by parse-tree-visitor, add EmptyTrait,
// and visit the members by hand when needed.
using EmptyTrait = std::true_type;
common::Reference<const OmpTypeName> type;
EntityDecl var;
};
struct OmpStylizedInstance {
struct Instance {
UNION_CLASS_BOILERPLATE(Instance);
std::variant<AssignmentStmt, CallStmt, common::Indirection<Expr>> u;
};
TUPLE_CLASS_BOILERPLATE(OmpStylizedInstance);
std::tuple<std::list<OmpStylizedDeclaration>, Instance> t;
};
class ParseState;
// Ref: [5.2:76], [6.0:185]
//
struct OmpStylizedExpression {
CharBlock source;
// Pointer to a temporary copy of the ParseState that is used to create
// additional parse subtrees for the stylized expression. This is only
// used internally during parsing and conveys no information to the
// consumers of the AST.
const ParseState *state{nullptr};
WRAPPER_CLASS_BOILERPLATE(
OmpStylizedExpression, std::list<OmpStylizedInstance>);
};
// Ref: [4.5:201-207], [5.0:293-299], [5.1:325-331], [5.2:124]
//
// reduction-identifier ->
@ -3555,9 +3592,22 @@ struct OmpReductionIdentifier {
// combiner-expression -> // since 4.5
// assignment-statement |
// function-reference
struct OmpCombinerExpression {
UNION_CLASS_BOILERPLATE(OmpCombinerExpression);
std::variant<AssignmentStmt, FunctionReference> u;
struct OmpCombinerExpression : public OmpStylizedExpression {
INHERITED_WRAPPER_CLASS_BOILERPLATE(
OmpCombinerExpression, OmpStylizedExpression);
static llvm::ArrayRef<CharBlock> Variables();
};
// Ref: [4.5:222:7-8], [5.0:305:28-29], [5.1:337:20-21], [5.2:127:6-8],
// [6.0:242:3-5]
//
// initializer-expression -> // since 4.5
// OMP_PRIV = expression |
// subroutine-name(argument-list)
struct OmpInitializerExpression : public OmpStylizedExpression {
INHERITED_WRAPPER_CLASS_BOILERPLATE(
OmpInitializerExpression, OmpStylizedExpression);
static llvm::ArrayRef<CharBlock> Variables();
};
inline namespace arguments {
@ -4558,16 +4608,9 @@ struct OmpInReductionClause {
std::tuple<MODIFIERS(), OmpObjectList> t;
};
// declare-reduction -> DECLARE REDUCTION (reduction-identifier : type-list
// : combiner) [initializer-clause]
struct OmpInitializerProc {
TUPLE_CLASS_BOILERPLATE(OmpInitializerProc);
std::tuple<ProcedureDesignator, std::list<ActualArgSpec>> t;
};
// Initialization for declare reduction construct
struct OmpInitializerClause {
UNION_CLASS_BOILERPLATE(OmpInitializerClause);
std::variant<OmpInitializerProc, AssignmentStmt> u;
WRAPPER_CLASS_BOILERPLATE(OmpInitializerClause, OmpInitializerExpression);
};
// Ref: [4.5:199-201], [5.0:288-290], [5.1:321-322], [5.2:115-117]

View File

@ -830,6 +830,8 @@ public:
OmpUseDevicePtr, OmpUseDeviceAddr, OmpIsDevicePtr, OmpHasDeviceAddr,
// OpenMP data-copying attribute
OmpCopyIn, OmpCopyPrivate,
// OpenMP special variables
OmpInVar, OmpOrigVar, OmpOutVar, OmpPrivVar,
// OpenMP miscellaneous flags
OmpCommonBlock, OmpReduction, OmpInReduction, OmpAligned, OmpNontemporal,
OmpAllocate, OmpDeclarativeAllocateDirective,

View File

@ -275,6 +275,13 @@ struct SpecificModifierParser {
// --- Iterator helpers -----------------------------------------------
static EntityDecl MakeEntityDecl(ObjectName &&name) {
return EntityDecl(
/*ObjectName=*/std::move(name), std::optional<ArraySpec>{},
std::optional<CoarraySpec>{}, std::optional<CharLength>{},
std::optional<Initialization>{});
}
// [5.0:47:17-18] In an iterator-specifier, if the iterator-type is not
// specified then the type of that iterator is default integer.
// [5.0:49:14] The iterator-type must be an integer type.
@ -282,11 +289,7 @@ static std::list<EntityDecl> makeEntityList(std::list<ObjectName> &&names) {
std::list<EntityDecl> entities;
for (auto iter = names.begin(), end = names.end(); iter != end; ++iter) {
EntityDecl entityDecl(
/*ObjectName=*/std::move(*iter), std::optional<ArraySpec>{},
std::optional<CoarraySpec>{}, std::optional<CharLength>{},
std::optional<Initialization>{});
entities.push_back(std::move(entityDecl));
entities.push_back(MakeEntityDecl(std::move(*iter)));
}
return entities;
}
@ -306,6 +309,217 @@ static TypeDeclarationStmt makeIterSpecDecl(std::list<ObjectName> &&names) {
makeEntityList(std::move(names)));
}
// --- Stylized expression handling -----------------------------------
// OpenMP has a concept of am "OpenMP stylized expression". Syntactially
// it looks like a typical Fortran expression (or statement), except:
// - the only variables allowed in it are OpenMP special variables, the
// exact set of these variables depends on the specific case of the
// stylized expression
// - the special OpenMP variables present may assume one or more types,
// and the expression should be semantically valid for each type.
//
// The stylized expression can be thought of as a template, which will be
// instantiated for each type provided somewhere in the context in which
// the stylized expression appears.
//
// AST nodes:
// - OmpStylizedExpression: contains the source string for the expression,
// plus the list of instances (OmpStylizedInstance).
// - OmpStylizedInstance: corresponds to the instantiation of the stylized
// expression for a specific type. The way that the type is specified is
// by creating declarations (OmpStylizedDeclaration) for the special
// variables. Together with the AST tree corresponding to the stylized
// expression the instantiation has enough information for semantic
// analysis. Each instance has its own scope, and the special variables
// have their own Symbol's (local to the scope).
// - OmpStylizedDeclaration: encapsulates the information that the visitors
// in resolve-names can use to "emulate" a declaration for a special
// variable and allow name resolution in the instantiation AST to work.
//
// Implementation specifics:
// The semantic analysis stores "evaluate::Expr" in each AST node rooted
// in parser::Expr (in the typedExpr member). The evaluate::Expr is specific
// to a given type, and so to allow different types for a given expression,
// for each type a separate copy of the parser::Expr subtree is created.
// Normally, AST nodes are non-copyable (copy-ctor is deleted), so to create
// several copies of a subtree, the same source string is parsed several
// times. The ParseState member in OmpStylizedExpression is the parser state
// immediately before the stylized expression.
//
// Initially, when OmpStylizedExpression is first created, the expression is
// parsed as if it was an actual code, but this parsing is only done to
// establish where the stylized expression ends (in the source). The source
// and the initial parser state are stored in the object, and the instance
// list is empty.
// Once the parsing of the containing OmpDirectiveSpecification completes,
// a post-processing "parser" (OmpStylizedInstanceCreator) executes. This
// post-processor examines the directive specification to see if it expects
// any stylized expressions to be contained in it, and then instantiates
// them for each such directive.
template <typename A> struct NeverParser {
using resultType = A;
std::optional<resultType> Parse(ParseState &state) const {
// Always fail, but without any messages.
return std::nullopt;
}
};
template <typename A> constexpr auto never() { return NeverParser<A>{}; }
// Parser for optional<T> which always succeeds and returns std::nullptr.
// It's only needed to produce "std::optional<CallStmt::Chevrons>" in
// CallStmt.
template <typename A, typename B = void> struct NullParser;
template <typename B> struct NullParser<std::optional<B>> {
using resultType = std::optional<B>;
std::optional<resultType> Parse(ParseState &) const {
return resultType{std::nullopt};
}
};
template <typename A> constexpr auto null() { return NullParser<A>{}; }
// OmpStylizedDeclaration and OmpStylizedInstance are helper classes, and
// don't correspond to anything in the source. Their parsers should still
// exist, but they should never be executed.
TYPE_PARSER(construct<OmpStylizedDeclaration>(never<OmpStylizedDeclaration>()))
TYPE_PARSER(construct<OmpStylizedInstance>(never<OmpStylizedInstance>()))
TYPE_PARSER( //
construct<OmpStylizedInstance::Instance>(Parser<AssignmentStmt>{}) ||
construct<OmpStylizedInstance::Instance>(
sourced(construct<CallStmt>(Parser<ProcedureDesignator>{},
null<std::optional<CallStmt::Chevrons>>(),
parenthesized(optionalList(actualArgSpec))))) ||
construct<OmpStylizedInstance::Instance>(indirect(expr)))
struct OmpStylizedExpressionParser {
using resultType = OmpStylizedExpression;
std::optional<resultType> Parse(ParseState &state) const {
auto *saved{new ParseState(state)};
auto getSource{verbatim(Parser<OmpStylizedInstance::Instance>{} >> ok)};
if (auto &&ok{getSource.Parse(state)}) {
OmpStylizedExpression result{std::list<OmpStylizedInstance>{}};
result.source = ok->source;
result.state = saved;
// result.v remains empty
return std::move(result);
}
delete saved;
return std::nullopt;
}
};
static void Instantiate(OmpStylizedExpression &ose,
llvm::ArrayRef<const OmpTypeName *> types, llvm::ArrayRef<CharBlock> vars) {
// 1. For each var in the vars list, declare it with the corresponding
// type from types.
// 2. Run the parser to get the AST for the stylized expression.
// 3. Create OmpStylizedInstance and append it to the list in ose.
assert(types.size() == vars.size() && "List size mismatch");
// A ParseState object is irreversibly modified during parsing (in
// particular, it cannot be rewound to an earlier position in the source).
// Because of that we need to create a local copy for each instantiation.
// If rewinding was possible, we could just use the current one, and we
// wouldn't need to save it in the AST node.
ParseState state{DEREF(ose.state)};
std::list<OmpStylizedDeclaration> decls;
for (auto [type, var] : llvm::zip_equal(types, vars)) {
decls.emplace_back(OmpStylizedDeclaration{
common::Reference(*type), MakeEntityDecl(Name{var})});
}
if (auto &&instance{Parser<OmpStylizedInstance::Instance>{}.Parse(state)}) {
ose.v.emplace_back(
OmpStylizedInstance{std::move(decls), std::move(*instance)});
}
}
static void InstantiateForTypes(OmpStylizedExpression &ose,
const OmpTypeNameList &typeNames, llvm::ArrayRef<CharBlock> vars) {
// For each type in the type list, declare all variables in vars with
// that type, and complete the instantiation.
for (const OmpTypeName &t : typeNames.v) {
std::vector<const OmpTypeName *> types(vars.size(), &t);
Instantiate(ose, types, vars);
}
}
static void InstantiateDeclareReduction(OmpDirectiveSpecification &spec) {
// There can be arguments/clauses that don't make sense, that analysis
// is left until semantic checks. Tolerate any unexpected stuff.
auto *rspec{GetFirstArgument<OmpReductionSpecifier>(spec)};
if (!rspec) {
return;
}
const OmpTypeNameList *typeNames{nullptr};
if (auto *cexpr{
const_cast<OmpCombinerExpression *>(GetCombinerExpr(*rspec))}) {
typeNames = &std::get<OmpTypeNameList>(rspec->t);
InstantiateForTypes(*cexpr, *typeNames, OmpCombinerExpression::Variables());
delete cexpr->state;
cexpr->state = nullptr;
} else {
// If there are no types, there is nothing else to do.
return;
}
for (const OmpClause &clause : spec.Clauses().v) {
llvm::omp::Clause id{clause.Id()};
if (id == llvm::omp::Clause::OMPC_initializer) {
if (auto *iexpr{const_cast<OmpInitializerExpression *>(
GetInitializerExpr(clause))}) {
InstantiateForTypes(
*iexpr, *typeNames, OmpInitializerExpression::Variables());
delete iexpr->state;
iexpr->state = nullptr;
}
}
}
}
static void InstantiateStylizedDirective(OmpDirectiveSpecification &spec) {
const OmpDirectiveName &dirName{spec.DirName()};
if (dirName.v == llvm::omp::Directive::OMPD_declare_reduction) {
InstantiateDeclareReduction(spec);
}
}
template <typename P,
typename = std::enable_if_t<
std::is_same_v<typename P::resultType, OmpDirectiveSpecification>>>
struct OmpStylizedInstanceCreator {
using resultType = OmpDirectiveSpecification;
constexpr OmpStylizedInstanceCreator(P p) : parser_(p) {}
std::optional<resultType> Parse(ParseState &state) const {
if (auto &&spec{parser_.Parse(state)}) {
InstantiateStylizedDirective(*spec);
return std::move(spec);
}
return std::nullopt;
}
private:
const P parser_;
};
template <typename P>
OmpStylizedInstanceCreator(P) -> OmpStylizedInstanceCreator<P>;
// --- Parsers for types ----------------------------------------------
TYPE_PARSER( //
sourced(construct<OmpTypeName>(Parser<DeclarationTypeSpec>{})) ||
sourced(construct<OmpTypeName>(Parser<TypeSpec>{})))
// --- Parsers for arguments ------------------------------------------
// At the moment these are only directive arguments. This is needed for
@ -366,10 +580,6 @@ struct OmpArgumentListParser {
}
};
TYPE_PARSER( //
construct<OmpTypeName>(Parser<DeclarationTypeSpec>{}) ||
construct<OmpTypeName>(Parser<TypeSpec>{}))
// 2.15.3.6 REDUCTION (reduction-identifier: variable-name-list)
TYPE_PARSER(construct<OmpReductionIdentifier>(Parser<DefinedOperator>{}) ||
construct<OmpReductionIdentifier>(Parser<ProcedureDesignator>{}))
@ -1065,7 +1275,8 @@ TYPE_PARSER(construct<OmpOtherwiseClause>(
TYPE_PARSER(construct<OmpWhenClause>(
maybe(nonemptyList(Parser<OmpWhenClause::Modifier>{}) / ":"),
maybe(indirect(Parser<OmpDirectiveSpecification>{}))))
maybe(indirect(
OmpStylizedInstanceCreator(Parser<OmpDirectiveSpecification>{})))))
// OMP 5.2 12.6.1 grainsize([ prescriptiveness :] scalar-integer-expression)
TYPE_PARSER(construct<OmpGrainsizeClause>(
@ -1777,12 +1988,7 @@ TYPE_PARSER(
Parser<OpenMPInteropConstruct>{})) /
endOfLine)
TYPE_PARSER(construct<OmpInitializerProc>(Parser<ProcedureDesignator>{},
parenthesized(many(maybe(","_tok) >> Parser<ActualArgSpec>{}))))
TYPE_PARSER(construct<OmpInitializerClause>(
construct<OmpInitializerClause>(assignmentStmt) ||
construct<OmpInitializerClause>(Parser<OmpInitializerProc>{})))
TYPE_PARSER(construct<OmpInitializerClause>(Parser<OmpInitializerExpression>{}))
// OpenMP 5.2: 7.5.4 Declare Variant directive
TYPE_PARSER(sourced(construct<OmpDeclareVariantDirective>(
@ -1794,7 +2000,7 @@ TYPE_PARSER(sourced(construct<OmpDeclareVariantDirective>(
TYPE_PARSER(sourced(construct<OpenMPDeclareReductionConstruct>(
predicated(Parser<OmpDirectiveName>{},
IsDirective(llvm::omp::Directive::OMPD_declare_reduction)) >=
Parser<OmpDirectiveSpecification>{})))
OmpStylizedInstanceCreator(Parser<OmpDirectiveSpecification>{}))))
// 2.10.6 Declare Target Construct
TYPE_PARSER(sourced(construct<OpenMPDeclareTargetConstruct>(
@ -1832,8 +2038,8 @@ TYPE_PARSER(sourced(construct<OpenMPDeclareMapperConstruct>(
IsDirective(llvm::omp::Directive::OMPD_declare_mapper)) >=
Parser<OmpDirectiveSpecification>{})))
TYPE_PARSER(construct<OmpCombinerExpression>(Parser<AssignmentStmt>{}) ||
construct<OmpCombinerExpression>(Parser<FunctionReference>{}))
TYPE_PARSER(construct<OmpCombinerExpression>(OmpStylizedExpressionParser{}))
TYPE_PARSER(construct<OmpInitializerExpression>(OmpStylizedExpressionParser{}))
TYPE_PARSER(sourced(construct<OpenMPCriticalConstruct>(
OmpBlockConstructParser{llvm::omp::Directive::OMPD_critical})))

View File

@ -74,4 +74,16 @@ const BlockConstruct *GetFortranBlockConstruct(
return nullptr;
}
const OmpCombinerExpression *GetCombinerExpr(
const OmpReductionSpecifier &rspec) {
return addr_if(std::get<std::optional<OmpCombinerExpression>>(rspec.t));
}
const OmpInitializerExpression *GetInitializerExpr(const OmpClause &init) {
if (auto *wrapped{std::get_if<OmpClause::Initializer>(&init.u)}) {
return &wrapped->v.v;
}
return nullptr;
}
} // namespace Fortran::parser::omp

View File

@ -11,6 +11,7 @@
#include "flang/Common/indirection.h"
#include "flang/Parser/tools.h"
#include "flang/Parser/user-state.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Frontend/OpenMP/OMP.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
@ -430,4 +431,30 @@ const OmpClauseList &OmpDirectiveSpecification::Clauses() const {
}
return empty;
}
static bool InitCharBlocksFromStrings(llvm::MutableArrayRef<CharBlock> blocks,
llvm::ArrayRef<std::string> strings) {
for (auto [i, n] : llvm::enumerate(strings)) {
blocks[i] = CharBlock(n);
}
return true;
}
// The names should have static storage duration. Keep these names
// in a sigle place.
llvm::ArrayRef<CharBlock> OmpCombinerExpression::Variables() {
static std::string names[]{"omp_in", "omp_out"};
static CharBlock vars[std::size(names)];
[[maybe_unused]] static bool init = InitCharBlocksFromStrings(vars, names);
return vars;
}
llvm::ArrayRef<CharBlock> OmpInitializerExpression::Variables() {
static std::string names[]{"omp_orig", "omp_priv"};
static CharBlock vars[std::size(names)];
[[maybe_unused]] static bool init = InitCharBlocksFromStrings(vars, names);
return vars;
}
} // namespace Fortran::parser

View File

@ -2095,15 +2095,13 @@ public:
// OpenMP Clauses & Directives
void Unparse(const OmpArgumentList &x) { Walk(x.v, ", "); }
void Unparse(const OmpTypeNameList &x) { Walk(x.v, ", "); }
void Unparse(const OmpBaseVariantNames &x) {
Walk(std::get<0>(x.t)); // OmpObject
Put(":");
Walk(std::get<1>(x.t)); // OmpObject
}
void Unparse(const OmpTypeNameList &x) { //
Walk(x.v, ",");
}
void Unparse(const OmpMapperSpecifier &x) {
const auto &mapperName{std::get<std::string>(x.t)};
if (mapperName.find(llvm::omp::OmpDefaultMapperName) == std::string::npos) {
@ -2202,6 +2200,15 @@ public:
unsigned ompVersion{langOpts_.OpenMPVersion};
Word(llvm::omp::getOpenMPDirectiveName(x.v, ompVersion));
}
void Unparse(const OmpStylizedDeclaration &x) {
// empty
}
void Unparse(const OmpStylizedExpression &x) { //
Put(x.source.ToString());
}
void Unparse(const OmpStylizedInstance &x) {
// empty
}
void Unparse(const OmpIteratorSpecifier &x) {
Walk(std::get<TypeDeclarationStmt>(x.t));
Put(" = ");
@ -2511,29 +2518,11 @@ public:
void Unparse(const OpenMPCriticalConstruct &x) {
Unparse(static_cast<const OmpBlockConstruct &>(x));
}
void Unparse(const OmpInitializerProc &x) {
Walk(std::get<ProcedureDesignator>(x.t));
Put("(");
Walk(std::get<std::list<ActualArgSpec>>(x.t));
Put(")");
}
void Unparse(const OmpInitializerClause &x) {
// Don't let the visitor go to the normal AssignmentStmt Unparse function,
// it adds an extra newline that we don't want.
if (const auto *assignment{std::get_if<AssignmentStmt>(&x.u)}) {
Walk(assignment->t, " = ");
} else {
Walk(x.u);
}
void Unparse(const OmpInitializerExpression &x) {
Unparse(static_cast<const OmpStylizedExpression &>(x));
}
void Unparse(const OmpCombinerExpression &x) {
// Don't let the visitor go to the normal AssignmentStmt Unparse function,
// it adds an extra newline that we don't want.
if (const auto *assignment{std::get_if<AssignmentStmt>(&x.u)}) {
Walk(assignment->t, " = ");
} else {
Walk(x.u);
}
Unparse(static_cast<const OmpStylizedExpression &>(x));
}
void Unparse(const OpenMPDeclareReductionConstruct &x) {
BeginOpenMP();

View File

@ -26,6 +26,8 @@
#include "flang/Semantics/symbol.h"
#include "flang/Semantics/tools.h"
#include "flang/Support/Flags.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Frontend/OpenMP/OMP.h.inc"
#include "llvm/Support/Debug.h"
#include <list>
@ -453,6 +455,21 @@ public:
return true;
}
bool Pre(const parser::OmpStylizedDeclaration &x) {
static llvm::StringMap<Symbol::Flag> map{
{"omp_in", Symbol::Flag::OmpInVar},
{"omp_orig", Symbol::Flag::OmpOrigVar},
{"omp_out", Symbol::Flag::OmpOutVar},
{"omp_priv", Symbol::Flag::OmpPrivVar},
};
if (auto &name{std::get<parser::ObjectName>(x.var.t)}; name.symbol) {
if (auto found{map.find(name.ToString())}; found != map.end()) {
ResolveOmp(name, found->second,
const_cast<Scope &>(DEREF(name.symbol).owner()));
}
}
return false;
}
bool Pre(const parser::OmpMetadirectiveDirective &x) {
PushContext(x.v.source, llvm::omp::Directive::OMPD_metadirective);
return true;

View File

@ -1605,6 +1605,12 @@ public:
Post(static_cast<const parser::OmpDirectiveSpecification &>(x));
}
void Post(const parser::OmpTypeName &);
bool Pre(const parser::OmpStylizedDeclaration &);
void Post(const parser::OmpStylizedDeclaration &);
bool Pre(const parser::OmpStylizedInstance &);
void Post(const parser::OmpStylizedInstance &);
bool Pre(const parser::OpenMPDeclareMapperConstruct &x) {
AddOmpSourceRange(x.source);
return true;
@ -1615,18 +1621,6 @@ public:
return true;
}
bool Pre(const parser::OmpInitializerProc &x) {
auto &procDes = std::get<parser::ProcedureDesignator>(x.t);
auto &name = std::get<parser::Name>(procDes.u);
auto *symbol{FindSymbol(NonDerivedTypeScope(), name)};
if (!symbol) {
context().Say(name.source,
"Implicit subroutine declaration '%s' in DECLARE REDUCTION"_err_en_US,
name.source);
}
return true;
}
bool Pre(const parser::OmpDeclareVariantDirective &x) {
AddOmpSourceRange(x.source);
return true;
@ -1772,14 +1766,6 @@ public:
messageHandler().set_currStmtSource(std::nullopt);
}
bool Pre(const parser::OmpTypeName &x) {
BeginDeclTypeSpec();
return true;
}
void Post(const parser::OmpTypeName &x) { //
EndDeclTypeSpec();
}
bool Pre(const parser::OpenMPConstruct &x) {
// Indicate that the current directive is not a declarative one.
declaratives_.push_back(nullptr);
@ -1835,6 +1821,30 @@ void OmpVisitor::Post(const parser::OmpBlockConstruct &x) {
}
}
void OmpVisitor::Post(const parser::OmpTypeName &x) {
x.declTypeSpec = GetDeclTypeSpec();
}
bool OmpVisitor::Pre(const parser::OmpStylizedDeclaration &x) {
BeginDecl();
Walk(x.type.get());
Walk(x.var);
return true;
}
void OmpVisitor::Post(const parser::OmpStylizedDeclaration &x) { //
EndDecl();
}
bool OmpVisitor::Pre(const parser::OmpStylizedInstance &x) {
PushScope(Scope::Kind::OtherConstruct, nullptr);
return true;
}
void OmpVisitor::Post(const parser::OmpStylizedInstance &x) { //
PopScope();
}
bool OmpVisitor::Pre(const parser::OmpMapClause &x) {
auto &mods{OmpGetModifiers(x)};
if (auto *mapper{OmpGetUniqueModifier<parser::OmpMapper>(mods)}) {
@ -1969,51 +1979,20 @@ void OmpVisitor::ProcessReductionSpecifier(
}
}
auto &typeList{std::get<parser::OmpTypeNameList>(spec.t)};
// Create a temporary variable declaration for the four variables
// used in the reduction specifier and initializer (omp_out, omp_in,
// omp_priv and omp_orig), with the type in the typeList.
//
// In theory it would be possible to create only variables that are
// actually used, but that requires walking the entire parse-tree of the
// expressions, and finding the relevant variables [there may well be other
// variables involved too].
//
// This allows doing semantic analysis where the type is a derived type
// e.g omp_out%x = omp_out%x + omp_in%x.
//
// These need to be temporary (in their own scope). If they are created
// as variables in the outer scope, if there's more than one type in the
// typelist, duplicate symbols will be reported.
const parser::CharBlock ompVarNames[]{
{"omp_in", 6}, {"omp_out", 7}, {"omp_priv", 8}, {"omp_orig", 8}};
for (auto &t : typeList.v) {
PushScope(Scope::Kind::OtherConstruct, nullptr);
BeginDeclTypeSpec();
// We need to walk t.u because Walk(t) does it's own BeginDeclTypeSpec.
Walk(t.u);
// Only process types we can find. There will be an error later on when
// a type isn't found.
if (const DeclTypeSpec *typeSpec{GetDeclTypeSpec()}) {
reductionDetails->AddType(*typeSpec);
for (auto &nm : ompVarNames) {
ObjectEntityDetails details{};
details.set_type(*typeSpec);
MakeSymbol(nm, Attrs{}, std::move(details));
}
}
EndDeclTypeSpec();
Walk(std::get<std::optional<parser::OmpCombinerExpression>>(spec.t));
Walk(clauses);
PopScope();
}
reductionDetails->AddDecl(declaratives_.back());
// Do not walk OmpTypeNameList. The types on the list will be visited
// during procesing of OmpCombinerExpression.
Walk(std::get<std::optional<parser::OmpCombinerExpression>>(spec.t));
Walk(clauses);
for (auto &type : std::get<parser::OmpTypeNameList>(spec.t).v) {
// The declTypeSpec can be null if there is some semantic error.
if (type.declTypeSpec) {
reductionDetails->AddType(*type.declTypeSpec);
}
}
if (!symbol) {
symbol = &MakeSymbol(mangledName, Attrs{}, std::move(*reductionDetails));
}

View File

@ -26,7 +26,8 @@ program omp_examples
type(tt) :: values(n), sum, prod, big, small
!$omp declare reduction(+:tt:omp_out%r = omp_out%r + omp_in%r) initializer(omp_priv%r = 0)
!CHECK: !$OMP DECLARE REDUCTION(+:tt: omp_out%r = omp_out%r+omp_in%r) INITIALIZER(omp_priv%r = 0_4)
!CHECK: !$OMP DECLARE REDUCTION(+:tt: omp_out%r = omp_out%r + omp_in%r) INITIALIZER(om&
!CHECK-NEXT: !$OMP&p_priv%r = 0)
!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareReductionConstruct -> OmpDirectiveSpecification
!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare reduction
@ -34,11 +35,39 @@ program omp_examples
!PARSE-TREE: | | OmpReductionIdentifier -> DefinedOperator -> IntrinsicOperator = Add
!PARSE-TREE: | | OmpTypeNameList -> OmpTypeName -> TypeSpec -> DerivedTypeSpec
!PARSE-TREE: | | | Name = 'tt'
!PARSE-TREE: | | OmpCombinerExpression -> AssignmentStmt = 'omp_out%r=omp_out%r+omp_in%r'
!PARSE-TREE: | OmpClauseList -> OmpClause -> Initializer -> OmpInitializerClause -> AssignmentStmt = 'omp_priv%r=0._4'
!PARSE-TREE: | | OmpCombinerExpression -> OmpStylizedInstance
!PARSE-TREE: | | | OmpStylizedDeclaration
!PARSE-TREE: | | | OmpStylizedDeclaration
!PARSE-TREE: | | | Instance -> AssignmentStmt = 'omp_out%r=omp_out%r+omp_in%r'
!PARSE-TREE: | | | | Variable = 'omp_out%r'
!PARSE-TREE: | | | | | Designator -> DataRef -> StructureComponent
!PARSE-TREE: | | | | | | DataRef -> Name = 'omp_out'
!PARSE-TREE: | | | | | | Name = 'r'
!PARSE-TREE: | | | | Expr = 'omp_out%r+omp_in%r'
!PARSE-TREE: | | | | | Add
!PARSE-TREE: | | | | | | Expr = 'omp_out%r'
!PARSE-TREE: | | | | | | | Designator -> DataRef -> StructureComponent
!PARSE-TREE: | | | | | | | | DataRef -> Name = 'omp_out'
!PARSE-TREE: | | | | | | | | Name = 'r'
!PARSE-TREE: | | | | | | Expr = 'omp_in%r'
!PARSE-TREE: | | | | | | | Designator -> DataRef -> StructureComponent
!PARSE-TREE: | | | | | | | | DataRef -> Name = 'omp_in'
!PARSE-TREE: | | | | | | | | Name = 'r'
!PARSE-TREE: | OmpClauseList -> OmpClause -> Initializer -> OmpInitializerClause -> OmpInitializerExpression -> OmpStylizedInstance
!PARSE-TREE: | | OmpStylizedDeclaration
!PARSE-TREE: | | OmpStylizedDeclaration
!PARSE-TREE: | | Instance -> AssignmentStmt = 'omp_priv%r=0._4'
!PARSE-TREE: | | | Variable = 'omp_priv%r'
!PARSE-TREE: | | | | Designator -> DataRef -> StructureComponent
!PARSE-TREE: | | | | | DataRef -> Name = 'omp_priv'
!PARSE-TREE: | | | | | Name = 'r'
!PARSE-TREE: | | | Expr = '0_4'
!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '0'
!PARSE-TREE: | Flags = None
!$omp declare reduction(*:tt:omp_out%r = omp_out%r * omp_in%r) initializer(omp_priv%r = 1)
!CHECK-NEXT: !$OMP DECLARE REDUCTION(*:tt: omp_out%r = omp_out%r*omp_in%r) INITIALIZER(omp_priv%r = 1_4)
!CHECK-NEXT: !$OMP DECLARE REDUCTION(*:tt: omp_out%r = omp_out%r * omp_in%r) INITIALIZER(om&
!CHECK-NEXT: !$OMP&p_priv%r = 1)
!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareReductionConstruct -> OmpDirectiveSpecification
!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare reduction
@ -46,11 +75,39 @@ program omp_examples
!PARSE-TREE: | | OmpReductionIdentifier -> DefinedOperator -> IntrinsicOperator = Multiply
!PARSE-TREE: | | OmpTypeNameList -> OmpTypeName -> TypeSpec -> DerivedTypeSpec
!PARSE-TREE: | | | Name = 'tt'
!PARSE-TREE: | | OmpCombinerExpression -> AssignmentStmt = 'omp_out%r=omp_out%r*omp_in%r'
!PARSE-TREE: | OmpClauseList -> OmpClause -> Initializer -> OmpInitializerClause -> AssignmentStmt = 'omp_priv%r=1._4'
!PARSE-TREE: | | OmpCombinerExpression -> OmpStylizedInstance
!PARSE-TREE: | | | OmpStylizedDeclaration
!PARSE-TREE: | | | OmpStylizedDeclaration
!PARSE-TREE: | | | Instance -> AssignmentStmt = 'omp_out%r=omp_out%r*omp_in%r'
!PARSE-TREE: | | | | Variable = 'omp_out%r'
!PARSE-TREE: | | | | | Designator -> DataRef -> StructureComponent
!PARSE-TREE: | | | | | | DataRef -> Name = 'omp_out'
!PARSE-TREE: | | | | | | Name = 'r'
!PARSE-TREE: | | | | Expr = 'omp_out%r*omp_in%r'
!PARSE-TREE: | | | | | Multiply
!PARSE-TREE: | | | | | | Expr = 'omp_out%r'
!PARSE-TREE: | | | | | | | Designator -> DataRef -> StructureComponent
!PARSE-TREE: | | | | | | | | DataRef -> Name = 'omp_out'
!PARSE-TREE: | | | | | | | | Name = 'r'
!PARSE-TREE: | | | | | | Expr = 'omp_in%r'
!PARSE-TREE: | | | | | | | Designator -> DataRef -> StructureComponent
!PARSE-TREE: | | | | | | | | DataRef -> Name = 'omp_in'
!PARSE-TREE: | | | | | | | | Name = 'r'
!PARSE-TREE: | OmpClauseList -> OmpClause -> Initializer -> OmpInitializerClause -> OmpInitializerExpression -> OmpStylizedInstance
!PARSE-TREE: | | OmpStylizedDeclaration
!PARSE-TREE: | | OmpStylizedDeclaration
!PARSE-TREE: | | Instance -> AssignmentStmt = 'omp_priv%r=1._4'
!PARSE-TREE: | | | Variable = 'omp_priv%r'
!PARSE-TREE: | | | | Designator -> DataRef -> StructureComponent
!PARSE-TREE: | | | | | DataRef -> Name = 'omp_priv'
!PARSE-TREE: | | | | | Name = 'r'
!PARSE-TREE: | | | Expr = '1_4'
!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '1'
!PARSE-TREE: | Flags = None
!$omp declare reduction(max:tt:omp_out = mymax(omp_out, omp_in)) initializer(omp_priv%r = 0)
!CHECK-NEXT: !$OMP DECLARE REDUCTION(max:tt: omp_out = mymax(omp_out,omp_in)) INITIALIZER(omp_priv%r = 0_4)
!CHECK-NEXT: !$OMP DECLARE REDUCTION(max:tt: omp_out = mymax(omp_out, omp_in)) INITIALIZER(&
!CHECK-NEXT: !$OMP&omp_priv%r = 0)
!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareReductionConstruct -> OmpDirectiveSpecification
!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare reduction
@ -58,11 +115,36 @@ program omp_examples
!PARSE-TREE: | | OmpReductionIdentifier -> ProcedureDesignator -> Name = 'max'
!PARSE-TREE: | | OmpTypeNameList -> OmpTypeName -> TypeSpec -> DerivedTypeSpec
!PARSE-TREE: | | | Name = 'tt'
!PARSE-TREE: | | OmpCombinerExpression -> AssignmentStmt = 'omp_out=mymax(omp_out,omp_in)'
!PARSE-TREE: | OmpClauseList -> OmpClause -> Initializer -> OmpInitializerClause -> AssignmentStmt = 'omp_priv%r=0._4'
!PARSE-TREE: | | OmpCombinerExpression -> OmpStylizedInstance
!PARSE-TREE: | | | OmpStylizedDeclaration
!PARSE-TREE: | | | OmpStylizedDeclaration
!PARSE-TREE: | | | Instance -> AssignmentStmt = 'omp_out=mymax(omp_out,omp_in)'
!PARSE-TREE: | | | | Variable = 'omp_out'
!PARSE-TREE: | | | | | Designator -> DataRef -> Name = 'omp_out'
!PARSE-TREE: | | | | Expr = 'mymax(omp_out,omp_in)'
!PARSE-TREE: | | | | | FunctionReference -> Call
!PARSE-TREE: | | | | | | ProcedureDesignator -> Name = 'mymax'
!PARSE-TREE: | | | | | | ActualArgSpec
!PARSE-TREE: | | | | | | | ActualArg -> Expr = 'omp_out'
!PARSE-TREE: | | | | | | | | Designator -> DataRef -> Name = 'omp_out'
!PARSE-TREE: | | | | | | ActualArgSpec
!PARSE-TREE: | | | | | | | ActualArg -> Expr = 'omp_in'
!PARSE-TREE: | | | | | | | | Designator -> DataRef -> Name = 'omp_in'
!PARSE-TREE: | OmpClauseList -> OmpClause -> Initializer -> OmpInitializerClause -> OmpInitializerExpression -> OmpStylizedInstance
!PARSE-TREE: | | OmpStylizedDeclaration
!PARSE-TREE: | | OmpStylizedDeclaration
!PARSE-TREE: | | Instance -> AssignmentStmt = 'omp_priv%r=0._4'
!PARSE-TREE: | | | Variable = 'omp_priv%r'
!PARSE-TREE: | | | | Designator -> DataRef -> StructureComponent
!PARSE-TREE: | | | | | DataRef -> Name = 'omp_priv'
!PARSE-TREE: | | | | | Name = 'r'
!PARSE-TREE: | | | Expr = '0_4'
!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '0'
!PARSE-TREE: | Flags = None
!$omp declare reduction(min:tt:omp_out%r = min(omp_out%r, omp_in%r)) initializer(omp_priv%r = 1)
!CHECK-NEXT: !$OMP DECLARE REDUCTION(min:tt: omp_out%r = min(omp_out%r,omp_in%r)) INITIALIZER(omp_priv%r = 1_4)
!CHECK-NEXT: !$OMP DECLARE REDUCTION(min:tt: omp_out%r = min(omp_out%r, omp_in%r)) INITIALI&
!CHECK-NEXT: !$OMP&ZER(omp_priv%r = 1)
!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareReductionConstruct -> OmpDirectiveSpecification
!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare reduction
@ -70,8 +152,38 @@ program omp_examples
!PARSE-TREE: | | OmpReductionIdentifier -> ProcedureDesignator -> Name = 'min'
!PARSE-TREE: | | OmpTypeNameList -> OmpTypeName -> TypeSpec -> DerivedTypeSpec
!PARSE-TREE: | | | Name = 'tt'
!PARSE-TREE: | | OmpCombinerExpression -> AssignmentStmt = 'omp_out%r=min(omp_out%r,omp_in%r)'
!PARSE-TREE: | OmpClauseList -> OmpClause -> Initializer -> OmpInitializerClause -> AssignmentStmt = 'omp_priv%r=1._4'
!PARSE-TREE: | | OmpCombinerExpression -> OmpStylizedInstance
!PARSE-TREE: | | | OmpStylizedDeclaration
!PARSE-TREE: | | | OmpStylizedDeclaration
!PARSE-TREE: | | | Instance -> AssignmentStmt = 'omp_out%r=min(omp_out%r,omp_in%r)'
!PARSE-TREE: | | | | Variable = 'omp_out%r'
!PARSE-TREE: | | | | | Designator -> DataRef -> StructureComponent
!PARSE-TREE: | | | | | | DataRef -> Name = 'omp_out'
!PARSE-TREE: | | | | | | Name = 'r'
!PARSE-TREE: | | | | Expr = 'min(omp_out%r,omp_in%r)'
!PARSE-TREE: | | | | | FunctionReference -> Call
!PARSE-TREE: | | | | | | ProcedureDesignator -> Name = 'min'
!PARSE-TREE: | | | | | | ActualArgSpec
!PARSE-TREE: | | | | | | | ActualArg -> Expr = 'omp_out%r'
!PARSE-TREE: | | | | | | | | Designator -> DataRef -> StructureComponent
!PARSE-TREE: | | | | | | | | | DataRef -> Name = 'omp_out'
!PARSE-TREE: | | | | | | | | | Name = 'r'
!PARSE-TREE: | | | | | | ActualArgSpec
!PARSE-TREE: | | | | | | | ActualArg -> Expr = 'omp_in%r'
!PARSE-TREE: | | | | | | | | Designator -> DataRef -> StructureComponent
!PARSE-TREE: | | | | | | | | | DataRef -> Name = 'omp_in'
!PARSE-TREE: | | | | | | | | | Name = 'r'
!PARSE-TREE: | OmpClauseList -> OmpClause -> Initializer -> OmpInitializerClause -> OmpInitializerExpression -> OmpStylizedInstance
!PARSE-TREE: | | OmpStylizedDeclaration
!PARSE-TREE: | | OmpStylizedDeclaration
!PARSE-TREE: | | Instance -> AssignmentStmt = 'omp_priv%r=1._4'
!PARSE-TREE: | | | Variable = 'omp_priv%r'
!PARSE-TREE: | | | | Designator -> DataRef -> StructureComponent
!PARSE-TREE: | | | | | DataRef -> Name = 'omp_priv'
!PARSE-TREE: | | | | | Name = 'r'
!PARSE-TREE: | | | Expr = '1_4'
!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '1'
!PARSE-TREE: | Flags = None
call random_number(values%r)

View File

@ -16,7 +16,8 @@ subroutine reduce_1 ( n, tts )
type(tt) :: tts(n)
type(tt2) :: tts2(n)
!CHECK: !$OMP DECLARE REDUCTION(+:tt: omp_out = tt(x=omp_out%x-omp_in%x,y=omp_out%y-omp_in%y)) INITIALIZER(omp_priv = tt(x=0_4,y=0_4))
!CHECK: !$OMP DECLARE REDUCTION(+:tt: omp_out = tt(omp_out%x - omp_in%x , omp_out%y - &
!CHECK: !$OMP&omp_in%y)) INITIALIZER(omp_priv = tt(0,0))
!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareReductionConstruct -> OmpDirectiveSpecification
!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare reduction
@ -24,13 +25,60 @@ subroutine reduce_1 ( n, tts )
!PARSE-TREE: | | OmpReductionIdentifier -> DefinedOperator -> IntrinsicOperator = Add
!PARSE-TREE: | | OmpTypeNameList -> OmpTypeName -> TypeSpec -> DerivedTypeSpec
!PARSE-TREE: | | | Name = 'tt'
!PARSE-TREE: | | OmpCombinerExpression -> AssignmentStmt = 'omp_out=tt(x=omp_out%x-omp_in%x,y=omp_out%y-omp_in%y)'
!PARSE-TREE: | OmpClauseList -> OmpClause -> Initializer -> OmpInitializerClause -> AssignmentStmt = 'omp_priv=tt(x=0_4,y=0_4)'
!PARSE-TREE: | | OmpCombinerExpression -> OmpStylizedInstance
!PARSE-TREE: | | | OmpStylizedDeclaration
!PARSE-TREE: | | | OmpStylizedDeclaration
!PARSE-TREE: | | | Instance -> AssignmentStmt = 'omp_out=tt(x=omp_out%x-omp_in%x,y=omp_out%y-omp_in%y)'
!PARSE-TREE: | | | | Variable = 'omp_out'
!PARSE-TREE: | | | | | Designator -> DataRef -> Name = 'omp_out'
!PARSE-TREE: | | | | Expr = 'tt(x=omp_out%x-omp_in%x,y=omp_out%y-omp_in%y)'
!PARSE-TREE: | | | | | StructureConstructor
!PARSE-TREE: | | | | | | DerivedTypeSpec
!PARSE-TREE: | | | | | | | Name = 'tt'
!PARSE-TREE: | | | | | | ComponentSpec
!PARSE-TREE: | | | | | | | ComponentDataSource -> Expr = 'omp_out%x-omp_in%x'
!PARSE-TREE: | | | | | | | | Subtract
!PARSE-TREE: | | | | | | | | | Expr = 'omp_out%x'
!PARSE-TREE: | | | | | | | | | | Designator -> DataRef -> StructureComponent
!PARSE-TREE: | | | | | | | | | | | DataRef -> Name = 'omp_out'
!PARSE-TREE: | | | | | | | | | | | Name = 'x'
!PARSE-TREE: | | | | | | | | | Expr = 'omp_in%x'
!PARSE-TREE: | | | | | | | | | | Designator -> DataRef -> StructureComponent
!PARSE-TREE: | | | | | | | | | | | DataRef -> Name = 'omp_in'
!PARSE-TREE: | | | | | | | | | | | Name = 'x'
!PARSE-TREE: | | | | | | ComponentSpec
!PARSE-TREE: | | | | | | | ComponentDataSource -> Expr = 'omp_out%y-omp_in%y'
!PARSE-TREE: | | | | | | | | Subtract
!PARSE-TREE: | | | | | | | | | Expr = 'omp_out%y'
!PARSE-TREE: | | | | | | | | | | Designator -> DataRef -> StructureComponent
!PARSE-TREE: | | | | | | | | | | | DataRef -> Name = 'omp_out'
!PARSE-TREE: | | | | | | | | | | | Name = 'y'
!PARSE-TREE: | | | | | | | | | Expr = 'omp_in%y'
!PARSE-TREE: | | | | | | | | | | Designator -> DataRef -> StructureComponent
!PARSE-TREE: | | | | | | | | | | | DataRef -> Name = 'omp_in'
!PARSE-TREE: | | | | | | | | | | | Name = 'y'
!PARSE-TREE: | OmpClauseList -> OmpClause -> Initializer -> OmpInitializerClause -> OmpInitializerExpression -> OmpStylizedInstance
!PARSE-TREE: | | OmpStylizedDeclaration
!PARSE-TREE: | | OmpStylizedDeclaration
!PARSE-TREE: | | Instance -> AssignmentStmt = 'omp_priv=tt(x=0_4,y=0_4)'
!PARSE-TREE: | | | Variable = 'omp_priv'
!PARSE-TREE: | | | | Designator -> DataRef -> Name = 'omp_priv'
!PARSE-TREE: | | | Expr = 'tt(x=0_4,y=0_4)'
!PARSE-TREE: | | | | StructureConstructor
!PARSE-TREE: | | | | | DerivedTypeSpec
!PARSE-TREE: | | | | | | Name = 'tt'
!PARSE-TREE: | | | | | ComponentSpec
!PARSE-TREE: | | | | | | ComponentDataSource -> Expr = '0_4'
!PARSE-TREE: | | | | | | | LiteralConstant -> IntLiteralConstant = '0'
!PARSE-TREE: | | | | | ComponentSpec
!PARSE-TREE: | | | | | | ComponentDataSource -> Expr = '0_4'
!PARSE-TREE: | | | | | | | LiteralConstant -> IntLiteralConstant = '0'
!PARSE-TREE: | Flags = None
!$omp declare reduction(+ : tt : omp_out = tt(omp_out%x - omp_in%x , omp_out%y - omp_in%y)) initializer(omp_priv = tt(0,0))
!CHECK: !$OMP DECLARE REDUCTION(+:tt2: omp_out = tt2(x=omp_out%x-omp_in%x,y=omp_out%y-omp_in%y)) INITIALIZER(omp_priv = tt2(x=0._8,y=0._8)
!CHECK: !$OMP DECLARE REDUCTION(+:tt2: omp_out = tt2(omp_out%x - omp_in%x , omp_out%y &
!CHECK: !$OMP&- omp_in%y)) INITIALIZER(omp_priv = tt2(0,0))
!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareReductionConstruct -> OmpDirectiveSpecification
!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare reduction
@ -38,9 +86,55 @@ subroutine reduce_1 ( n, tts )
!PARSE-TREE: | | OmpReductionIdentifier -> DefinedOperator -> IntrinsicOperator = Add
!PARSE-TREE: | | OmpTypeNameList -> OmpTypeName -> TypeSpec -> DerivedTypeSpec
!PARSE-TREE: | | | Name = 'tt2'
!PARSE-TREE: | | OmpCombinerExpression -> AssignmentStmt = 'omp_out=tt2(x=omp_out%x-omp_in%x,y=omp_out%y-omp_in%y)'
!PARSE-TREE: | OmpClauseList -> OmpClause -> Initializer -> OmpInitializerClause -> AssignmentStmt = 'omp_priv=tt2(x=0._8,y=0._8)'
!PARSE-TREE: | | OmpCombinerExpression -> OmpStylizedInstance
!PARSE-TREE: | | | OmpStylizedDeclaration
!PARSE-TREE: | | | OmpStylizedDeclaration
!PARSE-TREE: | | | Instance -> AssignmentStmt = 'omp_out=tt2(x=omp_out%x-omp_in%x,y=omp_out%y-omp_in%y)'
!PARSE-TREE: | | | | Variable = 'omp_out'
!PARSE-TREE: | | | | | Designator -> DataRef -> Name = 'omp_out'
!PARSE-TREE: | | | | Expr = 'tt2(x=omp_out%x-omp_in%x,y=omp_out%y-omp_in%y)'
!PARSE-TREE: | | | | | StructureConstructor
!PARSE-TREE: | | | | | | DerivedTypeSpec
!PARSE-TREE: | | | | | | | Name = 'tt2'
!PARSE-TREE: | | | | | | ComponentSpec
!PARSE-TREE: | | | | | | | ComponentDataSource -> Expr = 'omp_out%x-omp_in%x'
!PARSE-TREE: | | | | | | | | Subtract
!PARSE-TREE: | | | | | | | | | Expr = 'omp_out%x'
!PARSE-TREE: | | | | | | | | | | Designator -> DataRef -> StructureComponent
!PARSE-TREE: | | | | | | | | | | | DataRef -> Name = 'omp_out'
!PARSE-TREE: | | | | | | | | | | | Name = 'x'
!PARSE-TREE: | | | | | | | | | Expr = 'omp_in%x'
!PARSE-TREE: | | | | | | | | | | Designator -> DataRef -> StructureComponent
!PARSE-TREE: | | | | | | | | | | | DataRef -> Name = 'omp_in'
!PARSE-TREE: | | | | | | | | | | | Name = 'x'
!PARSE-TREE: | | | | | | ComponentSpec
!PARSE-TREE: | | | | | | | ComponentDataSource -> Expr = 'omp_out%y-omp_in%y'
!PARSE-TREE: | | | | | | | | Subtract
!PARSE-TREE: | | | | | | | | | Expr = 'omp_out%y'
!PARSE-TREE: | | | | | | | | | | Designator -> DataRef -> StructureComponent
!PARSE-TREE: | | | | | | | | | | | DataRef -> Name = 'omp_out'
!PARSE-TREE: | | | | | | | | | | | Name = 'y'
!PARSE-TREE: | | | | | | | | | Expr = 'omp_in%y'
!PARSE-TREE: | | | | | | | | | | Designator -> DataRef -> StructureComponent
!PARSE-TREE: | | | | | | | | | | | DataRef -> Name = 'omp_in'
!PARSE-TREE: | | | | | | | | | | | Name = 'y'
!PARSE-TREE: | OmpClauseList -> OmpClause -> Initializer -> OmpInitializerClause -> OmpInitializerExpression -> OmpStylizedInstance
!PARSE-TREE: | | OmpStylizedDeclaration
!PARSE-TREE: | | OmpStylizedDeclaration
!PARSE-TREE: | | Instance -> AssignmentStmt = 'omp_priv=tt2(x=0._8,y=0._8)'
!PARSE-TREE: | | | Variable = 'omp_priv'
!PARSE-TREE: | | | | Designator -> DataRef -> Name = 'omp_priv'
!PARSE-TREE: | | | Expr = 'tt2(x=0._8,y=0._8)'
!PARSE-TREE: | | | | StructureConstructor
!PARSE-TREE: | | | | | DerivedTypeSpec
!PARSE-TREE: | | | | | | Name = 'tt2'
!PARSE-TREE: | | | | | ComponentSpec
!PARSE-TREE: | | | | | | ComponentDataSource -> Expr = '0_4'
!PARSE-TREE: | | | | | | | LiteralConstant -> IntLiteralConstant = '0'
!PARSE-TREE: | | | | | ComponentSpec
!PARSE-TREE: | | | | | | ComponentDataSource -> Expr = '0_4'
!PARSE-TREE: | | | | | | | LiteralConstant -> IntLiteralConstant = '0'
!PARSE-TREE: | Flags = None
!$omp declare reduction(+ :tt2 : omp_out = tt2(omp_out%x - omp_in%x , omp_out%y - omp_in%y)) initializer(omp_priv = tt2(0,0))
type(tt) :: diffp = tt( 0, 0 )

View File

@ -8,6 +8,6 @@ end
!CHECK: !DEF: /f00 (Subroutine) Subprogram
!CHECK: subroutine f00
!CHECK: !$omp declare reduction(fred:integer,real: omp_out = omp_in+omp_out)
!CHECK: !$omp declare reduction(fred:integer, real: omp_out = omp_in + omp_out)
!CHECK: end subroutine

View File

@ -19,7 +19,8 @@ function func(x, n, init)
end subroutine initme
end interface
!$omp declare reduction(red_add:integer(4):omp_out=omp_out+omp_in) initializer(initme(omp_priv,0))
!CHECK: !$OMP DECLARE REDUCTION(red_add:INTEGER(KIND=4_4): omp_out = omp_out+omp_in) INITIALIZER(initme(omp_priv, 0_4))
!CHECK: !$OMP DECLARE REDUCTION(red_add:INTEGER(KIND=4_4): omp_out=omp_out+omp_in) INITIA&
!CHECKL !$OMP&LIZER(initme(omp_priv,0))
!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareReductionConstruct -> OmpDirectiveSpecification
!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare reduction
@ -27,9 +28,31 @@ function func(x, n, init)
!PARSE-TREE: | | OmpReductionIdentifier -> ProcedureDesignator -> Name = 'red_add'
!PARSE-TREE: | | OmpTypeNameList -> OmpTypeName -> DeclarationTypeSpec -> IntrinsicTypeSpec -> IntegerTypeSpec -> KindSelector -> Scalar -> Integer -> Constant -> Expr = '4_4'
!PARSE-TREE: | | | LiteralConstant -> IntLiteralConstant = '4'
!PARSE-TREE: | | OmpCombinerExpression -> AssignmentStmt = 'omp_out=omp_out+omp_in'
!PARSE-TREE: | OmpClauseList -> OmpClause -> Initializer -> OmpInitializerClause -> OmpInitializerProc
!PARSE-TREE: | | ProcedureDesignator -> Name = 'initme'
!PARSE-TREE: | | OmpCombinerExpression -> OmpStylizedInstance
!PARSE-TREE: | | | OmpStylizedDeclaration
!PARSE-TREE: | | | OmpStylizedDeclaration
!PARSE-TREE: | | | Instance -> AssignmentStmt = 'omp_out=omp_out+omp_in'
!PARSE-TREE: | | | | Variable = 'omp_out'
!PARSE-TREE: | | | | | Designator -> DataRef -> Name = 'omp_out'
!PARSE-TREE: | | | | Expr = 'omp_out+omp_in'
!PARSE-TREE: | | | | | Add
!PARSE-TREE: | | | | | | Expr = 'omp_out'
!PARSE-TREE: | | | | | | | Designator -> DataRef -> Name = 'omp_out'
!PARSE-TREE: | | | | | | Expr = 'omp_in'
!PARSE-TREE: | | | | | | | Designator -> DataRef -> Name = 'omp_in'
!PARSE-TREE: | OmpClauseList -> OmpClause -> Initializer -> OmpInitializerClause -> OmpInitializerExpression -> OmpStylizedInstance
!PARSE-TREE: | | OmpStylizedDeclaration
!PARSE-TREE: | | OmpStylizedDeclaration
!PARSE-TREE: | | Instance -> CallStmt = 'CALL initme(omp_priv,0_4)'
!PARSE-TREE: | | | Call
!PARSE-TREE: | | | | ProcedureDesignator -> Name = 'initme'
!PARSE-TREE: | | | | ActualArgSpec
!PARSE-TREE: | | | | | ActualArg -> Expr = 'omp_priv'
!PARSE-TREE: | | | | | | Designator -> DataRef -> Name = 'omp_priv'
!PARSE-TREE: | | | | ActualArgSpec
!PARSE-TREE: | | | | | ActualArg -> Expr = '0_4'
!PARSE-TREE: | | | | | | LiteralConstant -> IntLiteralConstant = '0'
!PARSE-TREE: | Flags = None
res=init
!$omp simd reduction(red_add:res)
@ -59,7 +82,8 @@ end function func
!CHECK-LABEL: program main
program main
integer :: my_var
!CHECK: !$OMP DECLARE REDUCTION(my_add_red:INTEGER: omp_out = omp_out+omp_in) INITIALIZER(omp_priv = 0_4)
!CHECK: !$OMP DECLARE REDUCTION(my_add_red:INTEGER: omp_out = omp_out + omp_in) INITIA&
!CHECK: !$OMP&LIZER(omp_priv=0)
!$omp declare reduction (my_add_red : integer : omp_out = omp_out + omp_in) initializer (omp_priv=0)
my_var = 0
@ -74,5 +98,24 @@ end program main
!PARSE-TREE: | OmpArgumentList -> OmpArgument -> OmpReductionSpecifier
!PARSE-TREE: | | OmpReductionIdentifier -> ProcedureDesignator -> Name = 'my_add_red'
!PARSE-TREE: | | OmpTypeNameList -> OmpTypeName -> DeclarationTypeSpec -> IntrinsicTypeSpec -> IntegerTypeSpec ->
!PARSE-TREE: | | OmpCombinerExpression -> AssignmentStmt = 'omp_out=omp_out+omp_in'
!PARSE-TREE: | OmpClauseList -> OmpClause -> Initializer -> OmpInitializerClause -> AssignmentStmt = 'omp_priv=0_4'
!PARSE-TREE: | | OmpCombinerExpression -> OmpStylizedInstance
!PARSE-TREE: | | | OmpStylizedDeclaration
!PARSE-TREE: | | | OmpStylizedDeclaration
!PARSE-TREE: | | | Instance -> AssignmentStmt = 'omp_out=omp_out+omp_in'
!PARSE-TREE: | | | | Variable = 'omp_out'
!PARSE-TREE: | | | | | Designator -> DataRef -> Name = 'omp_out'
!PARSE-TREE: | | | | Expr = 'omp_out+omp_in'
!PARSE-TREE: | | | | | Add
!PARSE-TREE: | | | | | | Expr = 'omp_out'
!PARSE-TREE: | | | | | | | Designator -> DataRef -> Name = 'omp_out'
!PARSE-TREE: | | | | | | Expr = 'omp_in'
!PARSE-TREE: | | | | | | | Designator -> DataRef -> Name = 'omp_in'
!PARSE-TREE: | OmpClauseList -> OmpClause -> Initializer -> OmpInitializerClause -> OmpInitializerExpression -> OmpStylizedInstance
!PARSE-TREE: | | OmpStylizedDeclaration
!PARSE-TREE: | | OmpStylizedDeclaration
!PARSE-TREE: | | Instance -> AssignmentStmt = 'omp_priv=0_4'
!PARSE-TREE: | | | Variable = 'omp_priv'
!PARSE-TREE: | | | | Designator -> DataRef -> Name = 'omp_priv'
!PARSE-TREE: | | | Expr = '0_4'
!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '0'
!PARSE-TREE: | Flags = None

View File

@ -105,8 +105,8 @@ end
!UNPARSE: TYPE :: tt2
!UNPARSE: REAL :: x
!UNPARSE: END TYPE
!UNPARSE: !$OMP METADIRECTIVE WHEN(USER={CONDITION(.true._4)}: DECLARE REDUCTION(+:tt1,tt2: omp_out%x = omp_in%x+omp_out%x)&
!UNPARSE: !$OMP&)
!UNPARSE: !$OMP METADIRECTIVE WHEN(USER={CONDITION(.true._4)}: DECLARE REDUCTION(+:tt1, tt2: omp&
!UNPARSE: !$OMP&_out%x = omp_in%x + omp_out%x))
!UNPARSE: END SUBROUTINE
!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpMetadirectiveDirective
@ -127,21 +127,44 @@ end
!PARSE-TREE: | | | | | Name = 'tt1'
!PARSE-TREE: | | | | OmpTypeName -> TypeSpec -> DerivedTypeSpec
!PARSE-TREE: | | | | | Name = 'tt2'
!PARSE-TREE: | | | | OmpCombinerExpression -> AssignmentStmt = 'omp_out%x=omp_in%x+omp_out%x'
!PARSE-TREE: | | | | | | Designator -> DataRef -> StructureComponent
!PARSE-TREE: | | | | | | | DataRef -> Name = 'omp_out'
!PARSE-TREE: | | | | | | | Name = 'x'
!PARSE-TREE: | | | | | Expr = 'omp_in%x+omp_out%x'
!PARSE-TREE: | | | | | | Add
!PARSE-TREE: | | | | | | | Expr = 'omp_in%x'
!PARSE-TREE: | | | | | | | | Designator -> DataRef -> StructureComponent
!PARSE-TREE: | | | | | | | | | DataRef -> Name = 'omp_in'
!PARSE-TREE: | | | | | | | | | Name = 'x'
!PARSE-TREE: | | | | | | | Expr = 'omp_out%x'
!PARSE-TREE: | | | | | | | | Designator -> DataRef -> StructureComponent
!PARSE-TREE: | | | | | | | | | DataRef -> Name = 'omp_out'
!PARSE-TREE: | | | | | | | | | Name = 'x'
!PARSE-TREE: | | | | OmpCombinerExpression -> OmpStylizedInstance
!PARSE-TREE: | | | | | OmpStylizedDeclaration
!PARSE-TREE: | | | | | OmpStylizedDeclaration
!PARSE-TREE: | | | | | Instance -> AssignmentStmt = 'omp_out%x=omp_in%x+omp_out%x'
!PARSE-TREE: | | | | | | Variable = 'omp_out%x'
!PARSE-TREE: | | | | | | | Designator -> DataRef -> StructureComponent
!PARSE-TREE: | | | | | | | | DataRef -> Name = 'omp_out'
!PARSE-TREE: | | | | | | | | Name = 'x'
!PARSE-TREE: | | | | | | Expr = 'omp_in%x+omp_out%x'
!PARSE-TREE: | | | | | | | Add
!PARSE-TREE: | | | | | | | | Expr = 'omp_in%x'
!PARSE-TREE: | | | | | | | | | Designator -> DataRef -> StructureComponent
!PARSE-TREE: | | | | | | | | | | DataRef -> Name = 'omp_in'
!PARSE-TREE: | | | | | | | | | | Name = 'x'
!PARSE-TREE: | | | | | | | | Expr = 'omp_out%x'
!PARSE-TREE: | | | | | | | | | Designator -> DataRef -> StructureComponent
!PARSE-TREE: | | | | | | | | | | DataRef -> Name = 'omp_out'
!PARSE-TREE: | | | | | | | | | | Name = 'x'
!PARSE-TREE: | | | | OmpStylizedInstance
!PARSE-TREE: | | | | | OmpStylizedDeclaration
!PARSE-TREE: | | | | | OmpStylizedDeclaration
!PARSE-TREE: | | | | | Instance -> AssignmentStmt = 'omp_out%x=omp_in%x+omp_out%x'
!PARSE-TREE: | | | | | | Variable = 'omp_out%x'
!PARSE-TREE: | | | | | | | Designator -> DataRef -> StructureComponent
!PARSE-TREE: | | | | | | | | DataRef -> Name = 'omp_out'
!PARSE-TREE: | | | | | | | | Name = 'x'
!PARSE-TREE: | | | | | | Expr = 'omp_in%x+omp_out%x'
!PARSE-TREE: | | | | | | | Add
!PARSE-TREE: | | | | | | | | Expr = 'omp_in%x'
!PARSE-TREE: | | | | | | | | | Designator -> DataRef -> StructureComponent
!PARSE-TREE: | | | | | | | | | | DataRef -> Name = 'omp_in'
!PARSE-TREE: | | | | | | | | | | Name = 'x'
!PARSE-TREE: | | | | | | | | Expr = 'omp_out%x'
!PARSE-TREE: | | | | | | | | | Designator -> DataRef -> StructureComponent
!PARSE-TREE: | | | | | | | | | | DataRef -> Name = 'omp_out'
!PARSE-TREE: | | | | | | | | | | Name = 'x'
!PARSE-TREE: | | | OmpClauseList ->
!PARSE-TREE: | | | Flags = None
subroutine f04
!$omp metadirective when(user={condition(.true.)}: &

View File

@ -79,7 +79,7 @@ end
!UNPARSE: TYPE :: t
!UNPARSE: INTEGER :: x
!UNPARSE: END TYPE
!UNPARSE: !$OMP DECLARE_REDUCTION(+:t: omp_out%x = omp_out%x+omp_in%x)
!UNPARSE: !$OMP DECLARE_REDUCTION(+:t: omp_out%x = omp_out%x + omp_in%x)
!UNPARSE: END SUBROUTINE
!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareReductionConstruct -> OmpDirectiveSpecification
@ -88,21 +88,24 @@ end
!PARSE-TREE: | | OmpReductionIdentifier -> DefinedOperator -> IntrinsicOperator = Add
!PARSE-TREE: | | OmpTypeNameList -> OmpTypeName -> TypeSpec -> DerivedTypeSpec
!PARSE-TREE: | | | Name = 't'
!PARSE-TREE: | | OmpCombinerExpression -> AssignmentStmt = 'omp_out%x=omp_out%x+omp_in%x'
!PARSE-TREE: | | | Variable = 'omp_out%x'
!PARSE-TREE: | | | | Designator -> DataRef -> StructureComponent
!PARSE-TREE: | | | | | DataRef -> Name = 'omp_out'
!PARSE-TREE: | | | | | Name = 'x'
!PARSE-TREE: | | | Expr = 'omp_out%x+omp_in%x'
!PARSE-TREE: | | | | Add
!PARSE-TREE: | | | | | Expr = 'omp_out%x'
!PARSE-TREE: | | | | | | Designator -> DataRef -> StructureComponent
!PARSE-TREE: | | | | | | | DataRef -> Name = 'omp_out'
!PARSE-TREE: | | | | | | | Name = 'x'
!PARSE-TREE: | | | | | Expr = 'omp_in%x'
!PARSE-TREE: | | | | | | Designator -> DataRef -> StructureComponent
!PARSE-TREE: | | | | | | | DataRef -> Name = 'omp_in'
!PARSE-TREE: | | | | | | | Name = 'x'
!PARSE-TREE: | | OmpCombinerExpression -> OmpStylizedInstance
!PARSE-TREE: | | | OmpStylizedDeclaration
!PARSE-TREE: | | | OmpStylizedDeclaration
!PARSE-TREE: | | | Instance -> AssignmentStmt = 'omp_out%x=omp_out%x+omp_in%x'
!PARSE-TREE: | | | | Variable = 'omp_out%x'
!PARSE-TREE: | | | | | Designator -> DataRef -> StructureComponent
!PARSE-TREE: | | | | | | DataRef -> Name = 'omp_out'
!PARSE-TREE: | | | | | | Name = 'x'
!PARSE-TREE: | | | | Expr = 'omp_out%x+omp_in%x'
!PARSE-TREE: | | | | | Add
!PARSE-TREE: | | | | | | Expr = 'omp_out%x'
!PARSE-TREE: | | | | | | | Designator -> DataRef -> StructureComponent
!PARSE-TREE: | | | | | | | | DataRef -> Name = 'omp_out'
!PARSE-TREE: | | | | | | | | Name = 'x'
!PARSE-TREE: | | | | | | Expr = 'omp_in%x'
!PARSE-TREE: | | | | | | | Designator -> DataRef -> StructureComponent
!PARSE-TREE: | | | | | | | | DataRef -> Name = 'omp_in'
!PARSE-TREE: | | | | | | | | Name = 'x'
!PARSE-TREE: | OmpClauseList ->
!PARSE-TREE: | Flags = None

View File

@ -1,11 +0,0 @@
! RUN: not %flang_fc1 -emit-obj -fopenmp -fopenmp-version=50 %s 2>&1 | FileCheck %s
subroutine initme(x,n)
integer x,n
x=n
end subroutine initme
subroutine subr
!$omp declare reduction(red_add:integer(4):omp_out=omp_out+omp_in) initializer(initme(omp_priv,0))
!CHECK: error: Implicit subroutine declaration 'initme' in DECLARE REDUCTION
end subroutine subr

View File

@ -57,9 +57,10 @@ contains
!CHECK: adder: UserReductionDetails TYPE(two)
!CHECK OtherConstruct scope
!CHECK: omp_in size=8 offset=0: ObjectEntity type: TYPE(two)
!CHECK: omp_orig size=8 offset=8: ObjectEntity type: TYPE(two)
!CHECK: omp_out size=8 offset=16: ObjectEntity type: TYPE(two)
!CHECK: omp_priv size=8 offset=24: ObjectEntity type: TYPE(two)
!CHECK: omp_out size=8 offset=8: ObjectEntity type: TYPE(two)
!CHECK OtherConstruct scope
!CHECK: omp_orig size=8 offset=0: ObjectEntity type: TYPE(two)
!CHECK: omp_priv size=8 offset=8: ObjectEntity type: TYPE(two)
!$omp simd reduction(adder:res)
@ -101,14 +102,16 @@ contains
!CHECK: adder: UserReductionDetails TYPE(two) TYPE(three)
!CHECK OtherConstruct scope
!CHECK: omp_in size=8 offset=0: ObjectEntity type: TYPE(two)
!CHECK: omp_orig size=8 offset=8: ObjectEntity type: TYPE(two)
!CHECK: omp_out size=8 offset=16: ObjectEntity type: TYPE(two)
!CHECK: omp_priv size=8 offset=24: ObjectEntity type: TYPE(two)
!CHECK: omp_out size=8 offset=8: ObjectEntity type: TYPE(two)
!CHECK OtherConstruct scope
!CHECK: omp_orig size=8 offset=0: ObjectEntity type: TYPE(two)
!CHECK: omp_priv size=8 offset=8: ObjectEntity type: TYPE(two)
!CHECK OtherConstruct scope
!CHECK: omp_in size=24 offset=0: ObjectEntity type: TYPE(three)
!CHECK: omp_orig size=24 offset=24: ObjectEntity type: TYPE(three)
!CHECK: omp_out size=24 offset=48: ObjectEntity type: TYPE(three)
!CHECK: omp_priv size=24 offset=72: ObjectEntity type: TYPE(three)
!CHECK: omp_out size=24 offset=24: ObjectEntity type: TYPE(three)
!CHECK OtherConstruct scope
!CHECK: omp_orig size=24 offset=0: ObjectEntity type: TYPE(three)
!CHECK: omp_priv size=24 offset=24: ObjectEntity type: TYPE(three)
!$omp simd reduction(adder:res3)
do i=1,n
@ -135,9 +138,10 @@ contains
!CHECK: op.+: UserReductionDetails TYPE(two)
!CHECK OtherConstruct scope
!CHECK: omp_in size=8 offset=0: ObjectEntity type: TYPE(two)
!CHECK: omp_orig size=8 offset=8: ObjectEntity type: TYPE(two)
!CHECK: omp_out size=8 offset=16: ObjectEntity type: TYPE(two)
!CHECK: omp_priv size=8 offset=24: ObjectEntity type: TYPE(two)
!CHECK: omp_out size=8 offset=8: ObjectEntity type: TYPE(two)
!CHECK OtherConstruct scope
!CHECK: omp_orig size=8 offset=0: ObjectEntity type: TYPE(two)
!CHECK: omp_priv size=8 offset=8: ObjectEntity type: TYPE(two)
!$omp simd reduction(+:res)
@ -163,14 +167,16 @@ contains
!CHECK: op.+: UserReductionDetails TYPE(two) TYPE(three)
!CHECK OtherConstruct scope
!CHECK: omp_in size=8 offset=0: ObjectEntity type: TYPE(two)
!CHECK: omp_orig size=8 offset=8: ObjectEntity type: TYPE(two)
!CHECK: omp_out size=8 offset=16: ObjectEntity type: TYPE(two)
!CHECK: omp_priv size=8 offset=24: ObjectEntity type: TYPE(two)
!CHECK: omp_out size=8 offset=8: ObjectEntity type: TYPE(two)
!CHECK OtherConstruct scope
!CHECK: omp_orig size=8 offset=0: ObjectEntity type: TYPE(two)
!CHECK: omp_priv size=8 offset=8: ObjectEntity type: TYPE(two)
!CHECK: OtherConstruct scope
!CHECK: omp_in size=24 offset=0: ObjectEntity type: TYPE(three)
!CHECK: omp_orig size=24 offset=24: ObjectEntity type: TYPE(three)
!CHECK: omp_out size=24 offset=48: ObjectEntity type: TYPE(three)
!CHECK: omp_priv size=24 offset=72: ObjectEntity type: TYPE(three)
!CHECK: omp_out size=24 offset=24: ObjectEntity type: TYPE(three)
!CHECK OtherConstruct scope
!CHECK: omp_orig size=24 offset=0: ObjectEntity type: TYPE(three)
!CHECK: omp_priv size=24 offset=24: ObjectEntity type: TYPE(three)
!$omp simd reduction(+:res3)
do i=1,n
@ -183,6 +189,7 @@ contains
enddo
res%t2 = res2
res%t3 = res3
funcBtwothree = res
end function funcBtwothree
!! This is checking a special case, where a reduction is declared inside a
@ -191,11 +198,12 @@ contains
pure logical function reduction()
!CHECK: reduction size=4 offset=0: ObjectEntity funcResult type: LOGICAL(4)
!CHECK: rr: UserReductionDetails INTEGER(4)
!CHECK: OtherConstruct scope: size=16 alignment=4 sourceRange=0 bytes
!CHECK: OtherConstruct scope: size=8 alignment=4 sourceRange=0 bytes
!CHECK: omp_in size=4 offset=0: ObjectEntity type: INTEGER(4)
!CHECK: omp_orig size=4 offset=4: ObjectEntity type: INTEGER(4)
!CHECK: omp_out size=4 offset=8: ObjectEntity type: INTEGER(4)
!CHECK: omp_priv size=4 offset=12: ObjectEntity type: INTEGER(4)
!CHECK: omp_out size=4 offset=4: ObjectEntity type: INTEGER(4)
!CHECK: OtherConstruct scope: size=8 alignment=4 sourceRange=0 bytes
!CHECK: omp_orig size=4 offset=0: ObjectEntity type: INTEGER(4)
!CHECK: omp_priv size=4 offset=4: ObjectEntity type: INTEGER(4)
!$omp declare reduction (rr : integer : omp_out = omp_out + omp_in) initializer (omp_priv = 0)
reduction = .false.
end function reduction

View File

@ -18,9 +18,10 @@ contains
!CHECK: op.AND: UserReductionDetails TYPE(logicalwrapper)
!CHECK OtherConstruct scope
!CHECK: omp_in size=4 offset=0: ObjectEntity type: TYPE(logicalwrapper)
!CHECK: omp_orig size=4 offset=4: ObjectEntity type: TYPE(logicalwrapper)
!CHECK: omp_out size=4 offset=8: ObjectEntity type: TYPE(logicalwrapper)
!CHECK: omp_priv size=4 offset=12: ObjectEntity type: TYPE(logicalwrapper)
!CHECK: omp_out size=4 offset=4: ObjectEntity type: TYPE(logicalwrapper)
!CHECK OtherConstruct scope
!CHECK: omp_orig size=4 offset=0: ObjectEntity type: TYPE(logicalwrapper)
!CHECK: omp_priv size=4 offset=4: ObjectEntity type: TYPE(logicalwrapper)
!$omp simd reduction(.AND.:res)
do i=1,n

View File

@ -6,13 +6,13 @@
!type::t1
!integer(4)::val
!endtype
!!$OMP DECLARE REDUCTION(*:t1:omp_out=omp_out*omp_in)INITIALIZER(omp_priv=&
!!$OMP&t1(1))
!!$OMP DECLARE REDUCTION(*:t1: omp_out=omp_out*omp_in) INITIALIZER(omp_priv=t1(&
!!$OMP&1))
!!$OMP METADIRECTIVE OTHERWISE(DECLARE REDUCTION(+:INTEGER))
!!$OMP DECLARE REDUCTION(.fluffy.:t1:omp_out=omp_out.fluffy.omp_in)INITIALI&
!!$OMP&ZER(omp_priv=t1(0))
!!$OMP DECLARE REDUCTION(.mul.:t1:omp_out=omp_out.mul.omp_in)INITIALIZER(om&
!!$OMP&p_priv=t1(1))
!!$OMP DECLARE REDUCTION(.fluffy.:t1: omp_out=omp_out.fluffy.omp_in) INITIALIZE&
!!$OMP&R(omp_priv=t1(0))
!!$OMP DECLARE REDUCTION(.mul.:t1: omp_out=omp_out.mul.omp_in) INITIALIZER(omp_&
!!$OMP&priv=t1(1))
!interface operator(.mul.)
!procedure::mul
!end interface

View File

@ -11,11 +11,9 @@ module m1
!$omp declare reduction(.fluffy.:t1:omp_out=omp_out.fluffy.omp_in)
!CHECK: op.fluffy., PUBLIC: UserReductionDetails TYPE(t1)
!CHECK: t1, PUBLIC: DerivedType components: val
!CHECK: OtherConstruct scope: size=16 alignment=4 sourceRange=0 bytes
!CHECK: OtherConstruct scope: size=8 alignment=4 sourceRange=0 bytes
!CHECK: omp_in size=4 offset=0: ObjectEntity type: TYPE(t1)
!CHECK: omp_orig size=4 offset=4: ObjectEntity type: TYPE(t1)
!CHECK: omp_out size=4 offset=8: ObjectEntity type: TYPE(t1)
!CHECK: omp_priv size=4 offset=12: ObjectEntity type: TYPE(t1)
!CHECK: omp_out size=4 offset=4: ObjectEntity type: TYPE(t1)
contains
function my_mul(x, y)
type (t1), intent (in) :: x, y

View File

@ -64,9 +64,10 @@ program test_vector
!CHECK: OtherConstruct scope:
!CHECK: omp_in size=12 offset=0: ObjectEntity type: TYPE(vector)
!CHECK: omp_orig size=12 offset=12: ObjectEntity type: TYPE(vector)
!CHECK: omp_out size=12 offset=24: ObjectEntity type: TYPE(vector)
!CHECK: omp_priv size=12 offset=36: ObjectEntity type: TYPE(vector)
!CHECK: omp_out size=12 offset=12: ObjectEntity type: TYPE(vector)
!CHECK: OtherConstruct scope:
!CHECK: omp_orig size=12 offset=0: ObjectEntity type: TYPE(vector)
!CHECK: omp_priv size=12 offset=12: ObjectEntity type: TYPE(vector)
v2 = Vector(0.0, 0.0, 0.0)
v1 = Vector(1.0, 2.0, 3.0)

View File

@ -33,11 +33,12 @@ program test_omp_reduction
!$omp declare reduction (.modmul. : t1 : omp_out = omp_out .modmul. omp_in) initializer(omp_priv = t1(1.0))
!CHECK: op.modmul.: UserReductionDetails TYPE(t1)
!CHECK: t1: Use from t1 in module1
!CHECK: OtherConstruct scope: size=16 alignment=4 sourceRange=0 bytes
!CHECK: OtherConstruct scope: size=8 alignment=4 sourceRange=0 bytes
!CHECK: omp_in size=4 offset=0: ObjectEntity type: TYPE(t1)
!CHECK: omp_orig size=4 offset=4: ObjectEntity type: TYPE(t1)
!CHECK: omp_out size=4 offset=8: ObjectEntity type: TYPE(t1)
!CHECK: omp_priv size=4 offset=12: ObjectEntity type: TYPE(t1)
!CHECK: omp_out size=4 offset=4: ObjectEntity type: TYPE(t1)
!CHECK: OtherConstruct scope: size=8 alignment=4 sourceRange=0 bytes
!CHECK: omp_orig size=4 offset=0: ObjectEntity type: TYPE(t1)
!CHECK: omp_priv size=4 offset=4: ObjectEntity type: TYPE(t1)
result = t1(1.0)
!$omp parallel do reduction(.modmul.:result)
do i = 1, 10

View File

@ -19,10 +19,12 @@ function func(x, n, init)
!$omp declare reduction(red_add:integer(4):omp_out=omp_out+omp_in) initializer(initme(omp_priv,0))
!CHECK: red_add: UserReductionDetails
!CHECK: Subprogram scope: initme
!CHECK: OtherConstruct scope:
!CHECK: omp_in size=4 offset=0: ObjectEntity type: INTEGER(4)
!CHECK: omp_orig size=4 offset=4: ObjectEntity type: INTEGER(4)
!CHECK: omp_out size=4 offset=8: ObjectEntity type: INTEGER(4)
!CHECK: omp_priv size=4 offset=12: ObjectEntity type: INTEGER(4)
!CHECK: omp_out size=4 offset=4: ObjectEntity type: INTEGER(4)
!CHECK: OtherConstruct scope:
!CHECK: omp_orig size=4 offset=0: ObjectEntity type: INTEGER(4)
!CHECK: omp_priv size=4 offset=4: ObjectEntity type: INTEGER(4)
!$omp simd reduction(red_add:res)
do i=1,n
res=res+x(i)
@ -36,9 +38,11 @@ program main
!$omp declare reduction (my_add_red : integer : omp_out = omp_out + omp_in) initializer (omp_priv=0)
!CHECK: my_add_red: UserReductionDetails
!CHECK: OtherConstruct scope:
!CHECK: omp_in size=4 offset=0: ObjectEntity type: INTEGER(4)
!CHECK: omp_orig size=4 offset=4: ObjectEntity type: INTEGER(4)
!CHECK: omp_out size=4 offset=8: ObjectEntity type: INTEGER(4)
!CHECK: omp_priv size=4 offset=12: ObjectEntity type: INTEGER(4)
!CHECK: omp_out size=4 offset=4: ObjectEntity type: INTEGER(4)
!CHECK: OtherConstruct scope:
!CHECK: omp_orig size=4 offset=0: ObjectEntity type: INTEGER(4)
!CHECK: omp_priv size=4 offset=4: ObjectEntity type: INTEGER(4)
end program main