================
@@ -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

Reply via email to