brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.0 KiB · 5aef245 Raw
230 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8/// \file9/// This file implements conversions from the ACC.td from the backend to10/// determine appertainment, required/etc.11///12//===----------------------------------------------------------------------===//13 14#include "clang/Basic/DiagnosticSema.h"15#include "clang/Sema/SemaOpenACC.h"16 17#include "llvm/ADT/STLExtras.h"18#include "llvm/ADT/bit.h"19 20using namespace clang;21 22namespace {23// Implements a simple 'enum-set' which stores enum values in a single 64 bit24// value. Flang has `EnumSet` which is pretty sizable/has a lot of dependencies,25// so likely not worth bringing in for this use.26class AccClauseSet {27  // We're just using a uint64_t as our underlying rep, so if this size ever28  // gets bigger than 64, we probably need a pair of uint64_ts.29  static_assert(static_cast<unsigned>(OpenACCClauseKind::Invalid) < 64);30  uint64_t Data;31 32  void setBit(OpenACCClauseKind C) {33    Data |= static_cast<uint64_t>(1) << static_cast<uint64_t>(C);34  }35 36public:37  constexpr AccClauseSet(std::initializer_list<OpenACCClauseKind> Clauses)38      : Data(0) {39    for (OpenACCClauseKind C : Clauses)40      setBit(C);41  }42 43  constexpr bool isSet(OpenACCClauseKind C) const {44    return ((Data >> static_cast<uint64_t>(C)) & 1) != 0;45  }46 47  void clearBit(OpenACCClauseKind C) {48    Data &= ~(static_cast<uint64_t>(1) << static_cast<uint64_t>(C));49  }50 51  constexpr bool isEmpty() const { return Data == 0; }52 53  unsigned popcount() const { return llvm::popcount<uint64_t>(Data); }54};55 56struct LLVMClauseLists {57  AccClauseSet Allowed;58  AccClauseSet AllowedOnce;59  AccClauseSet AllowedExclusive;60  AccClauseSet Required;61};62struct LLVMDirectiveClauseRelationships {63  OpenACCDirectiveKind DirKind;64  LLVMClauseLists Lists;65};66 67} // namespace68 69// This introduces these in a llvm::acc namespace, so make sure this stays in70// the global namespace.71#define GEN_CLANG_DIRECTIVE_CLAUSE_SETS72#include "llvm/Frontend/OpenACC/ACC.inc"73 74namespace {75LLVMDirectiveClauseRelationships Relations[] =76#define GEN_CLANG_DIRECTIVE_CLAUSE_MAP77#include "llvm/Frontend/OpenACC/ACC.inc"78    ;79 80const LLVMClauseLists &getListsForDirective(OpenACCDirectiveKind DK) {81 82  auto Res = llvm::find_if(Relations,83                           [=](const LLVMDirectiveClauseRelationships &Rel) {84                             return Rel.DirKind == DK;85                           });86  assert(Res != std::end(Relations) && "Unknown directive kind?");87 88  return Res->Lists;89}90 91std::string getListOfClauses(AccClauseSet Set) {92  // We could probably come up with a better way to do this smuggling, but this93  // is good enough for now.94  std::string Output;95  llvm::raw_string_ostream OS{Output};96 97  for (unsigned I = 0; I < static_cast<unsigned>(OpenACCClauseKind::Invalid);98       ++I) {99    OpenACCClauseKind CurClause = static_cast<OpenACCClauseKind>(I);100    if (!Set.isSet(CurClause))101      continue;102 103    OS << '\'' << CurClause << '\'';104 105    Set.clearBit(CurClause);106 107    if (Set.isEmpty()) {108      OS.flush();109      return OS.str();110    }111 112    OS << ", ";113 114    if (Set.popcount() == 1)115      OS << "or ";116  }117  OS.flush();118  return OS.str();119}120 121OpenACCClauseKind dealiasClauseKind(OpenACCClauseKind CK) {122  switch (CK) {123  default:124    return CK;125#define VISIT_CLAUSE(NAME)126#define CLAUSE_ALIAS(ALIAS, NAME, DEPRECATED)                                  \127  case OpenACCClauseKind::ALIAS:                                               \128    return OpenACCClauseKind::NAME;129#include "clang/Basic/OpenACCClauses.def"130  }131 132  return CK;133}134} // namespace135 136// Diagnoses if `Clauses` list doesn't have at least one of the required137// clauses.138bool SemaOpenACC::DiagnoseRequiredClauses(139    OpenACCDirectiveKind DK, SourceLocation DirectiveLoc,140    ArrayRef<const OpenACCClause *> Clauses) {141  if (DK == OpenACCDirectiveKind::Invalid)142    return false;143 144  const LLVMClauseLists &Lists = getListsForDirective(DK);145 146  if (Lists.Required.isEmpty())147    return false;148 149  for (auto *C : Clauses) {150    if (Lists.Required.isSet(dealiasClauseKind(C->getClauseKind())))151      return false;152  }153 154  return Diag(DirectiveLoc, diag::err_acc_construct_one_clause_of)155         << DK << getListOfClauses(Lists.Required);156  return true;157}158 159// Diagnoses a 'CK' on a 'DK' present more than once in a clause-list when it160// isn't allowed.161bool SemaOpenACC::DiagnoseAllowedOnceClauses(162    OpenACCDirectiveKind DK, OpenACCClauseKind CK, SourceLocation ClauseLoc,163    ArrayRef<const OpenACCClause *> Clauses) {164  if (DK == OpenACCDirectiveKind::Invalid || CK == OpenACCClauseKind::Invalid)165    return false;166 167  OpenACCClauseKind Dealiased = dealiasClauseKind(CK);168 169  const LLVMClauseLists &Lists = getListsForDirective(DK);170  if (!Lists.AllowedOnce.isSet(CK))171    return false;172 173  auto Res = llvm::find_if(Clauses, [=](const OpenACCClause *C) {174    return dealiasClauseKind(C->getClauseKind()) == Dealiased;175  });176 177  if (Res == Clauses.end())178    return false;179 180  Diag(ClauseLoc, diag::err_acc_duplicate_clause_disallowed) << DK << CK;181  Diag((*Res)->getBeginLoc(), diag::note_acc_previous_clause_here) << CK;182  return true;183}184 185// Diagnoses a 'CK' on a 'DK' being added that isn't allowed to, because another186// clause in 'Clauses' already exists.187bool SemaOpenACC::DiagnoseExclusiveClauses(188    OpenACCDirectiveKind DK, OpenACCClauseKind CK, SourceLocation ClauseLoc,189    ArrayRef<const OpenACCClause *> Clauses) {190  if (DK == OpenACCDirectiveKind::Invalid || CK == OpenACCClauseKind::Invalid)191    return false;192 193  const LLVMClauseLists &Lists = getListsForDirective(DK);194  OpenACCClauseKind Dealiased = dealiasClauseKind(CK);195 196  // If this isn't on the list, this is fine.197  if (!Lists.AllowedExclusive.isSet(Dealiased))198    return false;199 200  for (const OpenACCClause *C : Clauses) {201    if (Lists.AllowedExclusive.isSet(dealiasClauseKind(C->getClauseKind()))) {202      Diag(ClauseLoc, diag::err_acc_clause_cannot_combine)203          << CK << C->getClauseKind() << DK;204      Diag(C->getBeginLoc(), diag::note_acc_previous_clause_here)205          << C->getClauseKind();206 207      return true;208    }209  }210 211  return false;212}213 214// Diagnoses if 'CK' is not allowed on a directive of 'DK'.215bool SemaOpenACC::DiagnoseAllowedClauses(OpenACCDirectiveKind DK,216                                         OpenACCClauseKind CK,217                                         SourceLocation ClauseLoc) {218  if (DK == OpenACCDirectiveKind::Invalid || CK == OpenACCClauseKind::Invalid)219    return false;220  const LLVMClauseLists &Lists = getListsForDirective(DK);221  OpenACCClauseKind Dealiased = dealiasClauseKind(CK);222 223  if (!Lists.Allowed.isSet(Dealiased) && !Lists.AllowedOnce.isSet(Dealiased) &&224      !Lists.AllowedExclusive.isSet(Dealiased) &&225      !Lists.Required.isSet(Dealiased))226    return Diag(ClauseLoc, diag::err_acc_clause_appertainment) << DK << CK;227 228  return false;229}230