================
@@ -2474,6 +2475,133 @@ static void AppendConstructTraitsForDirective(
add(llvm::omp::TraitProperty::construct_dispatch_dispatch);
}
+namespace {
+/// Visitor that profiles a user condition for strict-subset checks. Names are
+/// identified by their ultimate symbols and literals by value and kind;
folding
+/// the whole expression would merge conditions on different variables.
+struct ConditionIdentity {
+ SemanticsContext &context;
+ llvm::FoldingSetNodeID id;
+
+ template <typename A> void AddNode() {
+ // Tag and symbol addresses are only compared within this compilation.
+ static char tag;
+ id.AddPointer(&tag);
+ }
+ template <typename T> static bool IsAbsent(const T &) { return false; }
+ template <typename T> static bool IsAbsent(const std::optional<T> &x) {
+ return !x;
+ }
+ template <typename A> bool Pre(const A &x) {
+ AddNode<A>();
+ if constexpr (std::is_enum_v<A> || std::is_integral_v<A>) {
+ id.AddInteger(static_cast<uint64_t>(x));
+ } else if constexpr (std::is_same_v<A, std::string>) {
+ id.AddString(x);
+ } else if constexpr (TupleTrait<A>) {
+ // The walk skips absent optional fields; keep the positions of the rest.
+ std::apply(
+ [&](const auto &...field) { (id.AddBoolean(IsAbsent(field)), ...); },
+ x.t);
+ }
+ return true;
+ }
+ template <typename A> void Post(const A &) { id.AddInteger(0); }
+ // CharBlocks in expression nodes carry source locations, not structure.
+ bool Pre(const parser::CharBlock &) { return false; }
+ bool Pre(const parser::SubstringInquiry &x) {
+ AddNode<parser::SubstringInquiry>();
+ // Only the source distinguishes %LEN from %KIND.
+ id.AddBoolean(x.source.back() == 'n');
+ return true;
+ }
+ bool Pre(const parser::Designator &x) {
+ AddNode<parser::Designator>();
+ // Semantics rewrites a misparsed s(i:j)%LEN or %KIND into a substring.
+ if (std::holds_alternative<parser::Substring>(x.u) && !x.source.empty()) {
+ id.AddInteger(x.source.back());
+ }
+ return true;
+ }
+ bool Pre(const parser::Name &name) {
+ AddNode<parser::Name>();
+ // Placeholders, implied-DO indices, and intrinsics can get a new symbol at
+ // each occurrence or in each scope.
+ const Symbol *symbol{name.symbol ? &name.symbol->GetUltimate() : nullptr};
+ bool isDeclaration{symbol && !symbol->has<MiscDetails>() &&
+ !symbol->attrs().test(Attr::INTRINSIC) &&
+ symbol->owner().kind() != Scope::Kind::ImpliedDos};
+ id.AddBoolean(isDeclaration);
+ if (isDeclaration) {
+ id.AddPointer(symbol);
+ } else {
+ id.AddString(symbol ? symbol->name().ToString() : name.ToString());
+ }
+ return false;
+ }
+ bool Pre(const parser::SignedIntLiteralConstant &literal) {
+ AddNode<parser::SignedIntLiteralConstant>();
+ if (auto value{evaluate::ExpressionAnalyzer{context}.Analyze(literal)}) {
+ id.AddString(value->AsFortran());
+ return false;
+ }
+ return true;
+ }
+ bool Pre(const parser::SignedRealLiteralConstant &literal) {
+ AddNode<parser::SignedRealLiteralConstant>();
+ if (auto value{evaluate::ExpressionAnalyzer{context}.Analyze(literal)}) {
+ id.AddString(value->AsFortran());
+ return false;
+ }
+ return true;
+ }
+ bool Pre(const parser::Expr &expr) {
+ AddNode<parser::Expr>();
+ if (const auto *negate{std::get_if<parser::Expr::Negate>(&expr.u)}) {
+ if (const auto *literal{
+ std::get_if<parser::LiteralConstant>(&negate->v.value().u)}) {
+ if (std::holds_alternative<parser::IntLiteralConstant>(literal->u)) {
+ // Analyze the signed literal as a whole: the magnitude of the most
+ // negative integer is not representable in its kind.
+ if (auto value{evaluate::ExpressionAnalyzer{context}.Analyze(expr)})
{
+ AddNode<parser::Expr::Negate>();
+ id.AddString(value->AsFortran());
+ return false;
+ }
+ }
+ }
+ }
+ if (const auto *literal{std::get_if<parser::LiteralConstant>(&expr.u)}) {
+ // Complex literal parts may name declarations: retain their structure.
+ if (!std::holds_alternative<parser::ComplexLiteralConstant>(literal->u))
{
+ if (auto value{evaluate::ExpressionAnalyzer{context}.Analyze(expr)}) {
+ AddNode<parser::LiteralConstant>();
+ id.AddString(value->AsFortran());
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+};
+
+llvm::StringRef GetConditionIdentity(
+ const parser::ScalarExpr &condition, SemanticsContext &context) {
+ const auto *expr{parser::Unwrap<parser::Expr>(condition)};
+ CHECK(expr);
+ // Outer parentheses are insignificant; inner ones constrain reassociation.
+ while (const auto *parens{std::get_if<parser::Expr::Parentheses>(&expr->u)})
+ expr = &parens->v.value();
+ ConditionIdentity profile{context, {}};
+ parser::Walk(*expr, profile);
----------------
MattPD wrote:
The parsed-expression profile is removed from this PR, so this case can move to
the condition-identity follow-up.
https://github.com/llvm/llvm-project/pull/231668
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits