Path: blob/main/contrib/llvm-project/llvm/lib/Frontend/OpenMP/OMP.cpp
35271 views
//===- OMP.cpp ------ Collection of helpers for OpenMP --------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "llvm/Frontend/OpenMP/OMP.h"910#include "llvm/ADT/ArrayRef.h"11#include "llvm/ADT/STLExtras.h"12#include "llvm/ADT/SmallVector.h"13#include "llvm/ADT/StringRef.h"14#include "llvm/ADT/StringSwitch.h"15#include "llvm/Support/ErrorHandling.h"1617#include <algorithm>18#include <iterator>19#include <type_traits>2021using namespace llvm;22using namespace llvm::omp;2324#define GEN_DIRECTIVES_IMPL25#include "llvm/Frontend/OpenMP/OMP.inc"2627static iterator_range<ArrayRef<Directive>::iterator>28getFirstCompositeRange(iterator_range<ArrayRef<Directive>::iterator> Leafs) {29// OpenMP Spec 5.2: [17.3, 8-9]30// If directive-name-A and directive-name-B both correspond to loop-31// associated constructs then directive-name is a composite construct32// otherwise directive-name is a combined construct.33//34// In the list of leaf constructs, find the first loop-associated construct,35// this is the beginning of the returned range. Then, starting from the36// immediately following leaf construct, find the first sequence of adjacent37// loop-associated constructs. The last of those is the last one of the38// range, that is, the end of the range is one past that element.39// If such a sequence of adjacent loop-associated directives does not exist,40// return an empty range.41//42// The end of the returned range (including empty range) is intended to be43// a point from which the search for the next range could resume.44//45// Consequently, this function can't return a range with a single leaf46// construct in it.4748auto firstLoopAssociated =49[](iterator_range<ArrayRef<Directive>::iterator> List) {50for (auto It = List.begin(), End = List.end(); It != End; ++It) {51if (getDirectiveAssociation(*It) == Association::Loop)52return It;53}54return List.end();55};5657auto Empty = llvm::make_range(Leafs.end(), Leafs.end());5859auto Begin = firstLoopAssociated(Leafs);60if (Begin == Leafs.end())61return Empty;6263auto End =64firstLoopAssociated(llvm::make_range(std::next(Begin), Leafs.end()));65if (End == Leafs.end())66return Empty;6768for (; End != Leafs.end(); ++End) {69if (getDirectiveAssociation(*End) != Association::Loop)70break;71}72return llvm::make_range(Begin, End);73}7475namespace llvm::omp {76ArrayRef<Directive> getLeafConstructs(Directive D) {77auto Idx = static_cast<std::size_t>(D);78if (Idx >= Directive_enumSize)79return std::nullopt;80const auto *Row = LeafConstructTable[LeafConstructTableOrdering[Idx]];81return ArrayRef(&Row[2], static_cast<int>(Row[1]));82}8384ArrayRef<Directive> getLeafConstructsOrSelf(Directive D) {85if (auto Leafs = getLeafConstructs(D); !Leafs.empty())86return Leafs;87auto Idx = static_cast<size_t>(D);88assert(Idx < Directive_enumSize && "Invalid directive");89const auto *Row = LeafConstructTable[LeafConstructTableOrdering[Idx]];90// The first entry in the row is the directive itself.91return ArrayRef(&Row[0], &Row[0] + 1);92}9394ArrayRef<Directive>95getLeafOrCompositeConstructs(Directive D, SmallVectorImpl<Directive> &Output) {96using ArrayTy = ArrayRef<Directive>;97using IteratorTy = ArrayTy::iterator;98ArrayRef<Directive> Leafs = getLeafConstructsOrSelf(D);99100IteratorTy Iter = Leafs.begin();101do {102auto Range = getFirstCompositeRange(llvm::make_range(Iter, Leafs.end()));103// All directives before the range are leaf constructs.104for (; Iter != Range.begin(); ++Iter)105Output.push_back(*Iter);106if (!Range.empty()) {107Directive Comp =108getCompoundConstruct(ArrayTy(Range.begin(), Range.end()));109assert(Comp != OMPD_unknown);110Output.push_back(Comp);111Iter = Range.end();112// As of now, a composite construct must contain all constituent leaf113// constructs from some point until the end of all constituent leaf114// constructs.115assert(Iter == Leafs.end() && "Malformed directive");116}117} while (Iter != Leafs.end());118119return Output;120}121122Directive getCompoundConstruct(ArrayRef<Directive> Parts) {123if (Parts.empty())124return OMPD_unknown;125126// Parts don't have to be leafs, so expand them into leafs first.127// Store the expanded leafs in the same format as rows in the leaf128// table (generated by tablegen).129SmallVector<Directive> RawLeafs(2);130for (Directive P : Parts) {131ArrayRef<Directive> Ls = getLeafConstructs(P);132if (!Ls.empty())133RawLeafs.append(Ls.begin(), Ls.end());134else135RawLeafs.push_back(P);136}137138// RawLeafs will be used as key in the binary search. The search doesn't139// guarantee that the exact same entry will be found (since RawLeafs may140// not correspond to any compound directive). Because of that, we will141// need to compare the search result with the given set of leafs.142// Also, if there is only one leaf in the list, it corresponds to itself,143// no search is necessary.144auto GivenLeafs{ArrayRef<Directive>(RawLeafs).drop_front(2)};145if (GivenLeafs.size() == 1)146return GivenLeafs.front();147RawLeafs[1] = static_cast<Directive>(GivenLeafs.size());148149auto Iter = std::lower_bound(150LeafConstructTable, LeafConstructTableEndDirective,151static_cast<std::decay_t<decltype(*LeafConstructTable)>>(RawLeafs.data()),152[](const llvm::omp::Directive *RowA, const llvm::omp::Directive *RowB) {153const auto *BeginA = &RowA[2];154const auto *EndA = BeginA + static_cast<int>(RowA[1]);155const auto *BeginB = &RowB[2];156const auto *EndB = BeginB + static_cast<int>(RowB[1]);157if (BeginA == EndA && BeginB == EndB)158return static_cast<int>(RowA[0]) < static_cast<int>(RowB[0]);159return std::lexicographical_compare(BeginA, EndA, BeginB, EndB);160});161162if (Iter == std::end(LeafConstructTable))163return OMPD_unknown;164165// Verify that we got a match.166Directive Found = (*Iter)[0];167ArrayRef<Directive> FoundLeafs = getLeafConstructs(Found);168if (FoundLeafs == GivenLeafs)169return Found;170return OMPD_unknown;171}172173bool isLeafConstruct(Directive D) { return getLeafConstructs(D).empty(); }174175bool isCompositeConstruct(Directive D) {176ArrayRef<Directive> Leafs = getLeafConstructsOrSelf(D);177if (Leafs.size() <= 1)178return false;179auto Range = getFirstCompositeRange(Leafs);180return Range.begin() == Leafs.begin() && Range.end() == Leafs.end();181}182183bool isCombinedConstruct(Directive D) {184// OpenMP Spec 5.2: [17.3, 9-10]185// Otherwise directive-name is a combined construct.186return !getLeafConstructs(D).empty() && !isCompositeConstruct(D);187}188} // namespace llvm::omp189190191