[flang-commits] [flang] [llvm] [flang][OpenMP] Add parsing and semantic checks for USES_ALLOCATORS (PR #213955)

Sairudra More via flang-commits flang-commits at lists.llvm.org
Mon Aug 10 23:09:01 PDT 2026


================
@@ -5388,6 +5390,393 @@ void OmpStructureChecker::Enter(const parser::OmpClause::UseDeviceAddr &x) {
   }
 }
 
+static constexpr std::string_view predefinedAllocatorNames[]{
+    "omp_default_mem_alloc", "omp_large_cap_mem_alloc", "omp_const_mem_alloc",
+    "omp_high_bw_mem_alloc", "omp_low_lat_mem_alloc", "omp_cgroup_mem_alloc",
+    "omp_pteam_mem_alloc", "omp_thread_mem_alloc"};
+
+static constexpr std::string_view predefinedMemSpaceNames[]{
+    "omp_default_mem_space", "omp_large_cap_mem_space", "omp_const_mem_space",
+    "omp_high_bw_mem_space", "omp_low_lat_mem_space"};
+
+// omp_null_allocator and omp_null_mem_space are not themselves predefined
+// handles, but [6.0:315-316] gives each its own allowance.
+static constexpr std::string_view nullAllocatorName[]{"omp_null_allocator"};
+static constexpr std::string_view nullMemSpaceName[]{"omp_null_mem_space"};
+
+// Whether the ultimate symbol is an entity of the intrinsic omp_lib module
+// shipped with the compiler, as opposed to a same-named entity of a
+// user-defined module.
+static bool IsIntrinsicOmpLibEntity(const Symbol &ultimate) {
+  const Scope &scope{ultimate.owner()};
+  if (!scope.IsModule()) {
+    return false;
+  }
+  const Symbol *module{scope.symbol()};
+  return module && module->name() == "omp_lib" &&
+      scope.parent().IsIntrinsicModules();
+}
+
+static bool IsIntrinsicOmpAlloctrait(
+    const DerivedTypeSpec &derived, SemanticsContext &context) {
+  const Scope *scope{context.GetBuiltinModule("omp_lib")};
+  const Symbol *symbol{scope ? scope->FindSymbol(SourceName{"omp_alloctrait",
+                                   std::strlen("omp_alloctrait")})
+                             : nullptr};
+  return symbol && IsIntrinsicOmpLibEntity(*symbol) &&
+      &derived.typeSymbol() == &symbol->GetUltimate();
+}
+
+// Recognition of a predefined allocator or memory space differs by version.
+//
+// [5.2:182] asks whether the allocator *is* a predefined allocator, so it
+// identifies the entity: a use-associated rename of the intrinsic omp_lib
+// entity still denotes it, while an unrelated declaration -- even one with the
+// same spelling, the same value, or in a user module named omp_lib -- does not.
+//
+// [6.0:315] instead asks whether the allocator is an identifier that *matches
+// the name of* a predefined allocator, which is a property of the identifier
+// written in the clause, not of the entity it resolves to. A local declaration
+// of a predefined spelling therefore qualifies, while a rename to some other
+// name does not, even when it denotes the intrinsic entity.
+static bool IsPredefinedHandle(const parser::Name &name,
+    llvm::ArrayRef<std::string_view> names, unsigned version) {
+  if (version >= 60) {
+    return llvm::is_contained(names, name.ToString());
+  }
+  if (const Symbol *symbol{name.symbol}) {
+    const Symbol &ultimate{symbol->GetUltimate()};
+    return IsIntrinsicOmpLibEntity(ultimate) &&
+        llvm::is_contained(names, ultimate.name().ToString());
+  }
+  return false;
+}
+
+// The integer kind of an OpenMP allocator or memory-space handle, which
+// omp_lib declares as c_intptr_t. iso_c_binding is an intrinsic module and is
+// read on demand, so the kind is available even when the source uses neither
+// module.
+static std::optional<std::int64_t> GetOmpHandleKind(SemanticsContext &context) {
+  const Scope *scope{context.GetBuiltinModule("iso_c_binding")};
+  if (!scope) {
+    return std::nullopt;
+  }
+  const Symbol *kindSymbol{
+      scope->FindSymbol(SourceName{"c_intptr_t", std::strlen("c_intptr_t")})};
+  if (!kindSymbol) {
+    return std::nullopt;
+  }
+  const auto *object{
+      kindSymbol->GetUltimate().detailsIf<ObjectEntityDetails>()};
+  const auto *init{object ? &object->init() : nullptr};
+  return init && *init ? evaluate::ToInt64(**init) : std::nullopt;
+}
+
+// Whether `symbol` has the integer kind that omp_lib gives its handles. The
+// check is skipped for a non-integer allocator, whose type is diagnosed
+// separately.
+static bool HasOmpHandleKind(
+    const Symbol &symbol, SemanticsContext &context, std::int64_t &expected) {
+  const DeclTypeSpec *type{symbol.GetUltimate().GetType()};
+  if (!type || !type->IsNumeric(TypeCategory::Integer)) {
+    return true;
+  }
+  auto want{GetOmpHandleKind(context)};
+  if (!want) {
+    return true;
+  }
+  expected = *want;
+  auto got{evaluate::ToInt64(type->numericTypeSpec().kind())};
+  return !got || *got == *want;
+}
----------------
Saieiei wrote:

Done in 1b14f92b0edd

https://github.com/llvm/llvm-project/pull/213955


More information about the flang-commits mailing list