clang  19.0.0git
CGSYCLRuntime.cpp
Go to the documentation of this file.
1 //===----- CGSYCLRuntime.cpp - Interface to SYCL Runtimes -----------------===//
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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This provides custom clang code generation for SYCL.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "CGSYCLRuntime.h"
14 #include "CodeGenFunction.h"
15 #include "clang/AST/Attr.h"
16 #include "clang/AST/Decl.h"
18 #include "llvm/Analysis/OptimizationRemarkEmitter.h"
19 #include "llvm/IR/Instructions.h"
20 #include <assert.h>
21 
22 using namespace clang;
23 using namespace CodeGen;
24 
25 namespace {
26 
27 /// Various utilities.
28 /// TODO partially duplicates functionality from SemaSYCL.cpp, can be shared.
29 class Util {
30 public:
31  using DeclContextDesc = std::pair<clang::Decl::Kind, StringRef>;
32 
33  /// Checks whether given clang type is declared in the given hierarchy of
34  /// declaration contexts.
35  /// \param RecTy the clang type being checked
36  /// \param Scopes the declaration scopes leading from the type to the
37  /// translation unit (excluding the latter)
38  static bool matchQualifiedTypeName(const CXXRecordDecl *RecTy,
40 };
41 
42 static bool isPFWI(const FunctionDecl &FD) {
43  const auto *MD = dyn_cast<CXXMethodDecl>(&FD);
44  if (!MD)
45  return false;
46  static std::array<Util::DeclContextDesc, 3> Scopes = {
47  Util::DeclContextDesc{clang::Decl::Kind::Namespace, "sycl"},
48  Util::DeclContextDesc{clang::Decl::Kind::Namespace, "_V1"},
49  Util::DeclContextDesc{Decl::Kind::ClassTemplateSpecialization, "group"}};
50  if (!Util::matchQualifiedTypeName(MD->getParent(), Scopes))
51  return false;
52  return FD.getName() == "parallel_for_work_item";
53 }
54 
55 constexpr char WG_SCOPE_MD_ID[] = "work_group_scope";
56 constexpr char WI_SCOPE_MD_ID[] = "work_item_scope";
57 constexpr char PFWI_MD_ID[] = "parallel_for_work_item";
58 constexpr char ATTR_GENX_VOLATILE[] = "genx_volatile";
59 constexpr char ATTR_GENX_BYTE_OFFSET[] = "genx_byte_offset";
60 
61 } // anonymous namespace
62 
64  llvm::Function &F) {
65  // Populate "sycl_explicit_simd" attribute if any.
66  if (FD.hasAttr<SYCLSimdAttr>())
67  F.setMetadata("sycl_explicit_simd", llvm::MDNode::get(F.getContext(), {}));
68 
69  // Set the function attribute expected by the vector backend compiler.
70  if (const auto *A = FD.getAttr<SYCLIntelESimdVectorizeAttr>())
71  if (const auto *DeclExpr = cast<ConstantExpr>(A->getValue())) {
72  SmallString<2> Str;
73  DeclExpr->getResultAsAPSInt().toString(Str);
74  F.addFnAttr("CMGenxSIMT", Str);
75  }
76 
77  SYCLScopeAttr *Scope = FD.getAttr<SYCLScopeAttr>();
78  if (!Scope)
79  return false;
80  switch (Scope->getLevel()) {
81  case SYCLScopeAttr::Level::WorkGroup:
82  F.setMetadata(WG_SCOPE_MD_ID, llvm::MDNode::get(F.getContext(), {}));
83  return true;
84  case SYCLScopeAttr::Level::WorkItem:
85  F.setMetadata(WI_SCOPE_MD_ID, llvm::MDNode::get(F.getContext(), {}));
86  if (isPFWI(FD))
87  // also emit specific marker for parallel_for_work_item, as it needs to
88  // be handled specially in the SYCL lowering pass
89  F.setMetadata(PFWI_MD_ID, llvm::MDNode::get(F.getContext(), {}));
90  return true;
91  }
92  llvm_unreachable("unknown sycl scope");
93 }
94 
96  const VarDecl &D) {
97 #ifndef NDEBUG
98  SYCLScopeAttr *Scope = D.getAttr<SYCLScopeAttr>();
99  assert(Scope && Scope->isWorkGroup() && "work group scope expected");
100 #endif // NDEBUG
101  // generate global variable in the address space selected by the clang CodeGen
102  // (should be local)
103  CGF.EmitStaticVarDecl(D, llvm::GlobalValue::InternalLinkage);
104 }
105 
107  llvm::Value *Addr) {
108  SYCLScopeAttr *Scope = D.getAttr<SYCLScopeAttr>();
109  if (!Scope)
110  return false;
111  assert(Scope->isWorkItem() && "auto var must be of work item scope");
112  auto *AI = dyn_cast<llvm::AllocaInst>(Addr);
113  assert(AI && "AllocaInst expected as local var address");
114  AI->setMetadata(WI_SCOPE_MD_ID, llvm::MDNode::get(AI->getContext(), {}));
115  return true;
116 }
117 
119  llvm::Value *Addr) {
120  SYCLRegisterNumAttr *RegAttr = D.getAttr<SYCLRegisterNumAttr>();
121  if (!RegAttr)
122  return false;
123  auto *GlobVar = cast<llvm::GlobalVariable>(Addr);
124  GlobVar->addAttribute(ATTR_GENX_VOLATILE);
125  GlobVar->addAttribute(ATTR_GENX_BYTE_OFFSET,
126  Twine(RegAttr->getNumber()).str());
127  // TODO consider reversing the error/success return values
128  return true;
129 }
130 
131 bool Util::matchQualifiedTypeName(const CXXRecordDecl *RecTy,
133  // The idea: check the declaration context chain starting from the type
134  // itself. At each step check the context is of expected kind
135  // (namespace) and name.
136  if (!RecTy)
137  return false; // only classes/structs supported
138  const auto *Ctx = cast<DeclContext>(RecTy);
139  StringRef Name = "";
140 
141  for (const auto &Scope : llvm::reverse(Scopes)) {
142  clang::Decl::Kind DK = Ctx->getDeclKind();
143 
144  if (DK != Scope.first)
145  return false;
146 
147  switch (DK) {
148  case clang::Decl::Kind::ClassTemplateSpecialization:
149  // ClassTemplateSpecializationDecl inherits from CXXRecordDecl
150  case clang::Decl::Kind::CXXRecord:
151  Name = cast<CXXRecordDecl>(Ctx)->getName();
152  break;
153  case clang::Decl::Kind::Namespace:
154  Name = cast<NamespaceDecl>(Ctx)->getName();
155  break;
156  default:
157  llvm_unreachable("matchQualifiedTypeName: decl kind not supported");
158  }
159  if (Name != Scope.second)
160  return false;
161  Ctx = Ctx->getParent();
162  }
163  return Ctx->isTranslationUnit();
164 }
Defines the clang::SourceLocation class and associated facilities.
Represents a C++ struct/union/class.
Definition: DeclCXX.h:258
bool actOnFunctionStart(const FunctionDecl &FD, llvm::Function &F)
void emitWorkGroupLocalVarDecl(CodeGenFunction &CGF, const VarDecl &D)
bool actOnGlobalVarEmit(CodeGenModule &CGM, const VarDecl &D, llvm::Value *Addr)
bool actOnAutoVarEmit(CodeGenFunction &CGF, const VarDecl &D, llvm::Value *Addr)
CodeGenFunction - This class organizes the per-function state that is used while generating LLVM code...
void EmitStaticVarDecl(const VarDecl &D, llvm::GlobalValue::LinkageTypes Linkage)
Definition: CGDecl.cpp:445
This class organizes the cross-function state that is used while generating LLVM code.
Kind
Lists the kind of concrete classes of Decl.
Definition: DeclBase.h:89
bool hasAttr() const
Definition: DeclBase.h:583
T * getAttr() const
Definition: DeclBase.h:579
Represents a function declaration or definition.
Definition: Decl.h:1972
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition: Decl.h:276
Scope - A scope is a transient data structure that is used while parsing the program.
Definition: Scope.h:41
Represents a variable declaration or definition.
Definition: Decl.h:919
The JSON file list parser is used to communicate input to InstallAPI.