1 //===--- AttrImpl.cpp - Classes for representing attributes -----*- C++ -*-===// 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 file contains out-of-line methods for Attr classes. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "clang/AST/ASTContext.h" 14 #include "clang/AST/Attr.h" 15 #include "clang/AST/Expr.h" 16 #include "clang/AST/Type.h" 17 #include <optional> 18 using namespace clang; 19 20 void LoopHintAttr::printPrettyPragma(raw_ostream &OS, 21 const PrintingPolicy &Policy) const { 22 unsigned SpellingIndex = getAttributeSpellingListIndex(); 23 // For "#pragma unroll" and "#pragma nounroll" the string "unroll" or 24 // "nounroll" is already emitted as the pragma name. 25 if (SpellingIndex == Pragma_nounroll || 26 SpellingIndex == Pragma_nounroll_and_jam) 27 return; 28 else if (SpellingIndex == Pragma_unroll || 29 SpellingIndex == Pragma_unroll_and_jam) { 30 OS << ' ' << getValueString(Policy); 31 return; 32 } 33 34 assert(SpellingIndex == Pragma_clang_loop && "Unexpected spelling"); 35 OS << ' ' << getOptionName(option) << getValueString(Policy); 36 } 37 38 // Return a string containing the loop hint argument including the 39 // enclosing parentheses. 40 std::string LoopHintAttr::getValueString(const PrintingPolicy &Policy) const { 41 std::string ValueName; 42 llvm::raw_string_ostream OS(ValueName); 43 OS << "("; 44 if (state == Numeric) 45 value->printPretty(OS, nullptr, Policy); 46 else if (state == FixedWidth || state == ScalableWidth) { 47 if (value) { 48 value->printPretty(OS, nullptr, Policy); 49 if (state == ScalableWidth) 50 OS << ", scalable"; 51 } else if (state == ScalableWidth) 52 OS << "scalable"; 53 else 54 OS << "fixed"; 55 } else if (state == Enable) 56 OS << "enable"; 57 else if (state == Full) 58 OS << "full"; 59 else if (state == AssumeSafety) 60 OS << "assume_safety"; 61 else 62 OS << "disable"; 63 OS << ")"; 64 return ValueName; 65 } 66 67 // Return a string suitable for identifying this attribute in diagnostics. 68 std::string 69 LoopHintAttr::getDiagnosticName(const PrintingPolicy &Policy) const { 70 unsigned SpellingIndex = getAttributeSpellingListIndex(); 71 if (SpellingIndex == Pragma_nounroll) 72 return "#pragma nounroll"; 73 else if (SpellingIndex == Pragma_unroll) 74 return "#pragma unroll" + 75 (option == UnrollCount ? getValueString(Policy) : ""); 76 else if (SpellingIndex == Pragma_nounroll_and_jam) 77 return "#pragma nounroll_and_jam"; 78 else if (SpellingIndex == Pragma_unroll_and_jam) 79 return "#pragma unroll_and_jam" + 80 (option == UnrollAndJamCount ? getValueString(Policy) : ""); 81 82 assert(SpellingIndex == Pragma_clang_loop && "Unexpected spelling"); 83 return getOptionName(option) + getValueString(Policy); 84 } 85 86 void OMPDeclareSimdDeclAttr::printPrettyPragma( 87 raw_ostream &OS, const PrintingPolicy &Policy) const { 88 if (getBranchState() != BS_Undefined) 89 OS << ' ' << ConvertBranchStateTyToStr(getBranchState()); 90 if (auto *E = getSimdlen()) { 91 OS << " simdlen("; 92 E->printPretty(OS, nullptr, Policy); 93 OS << ")"; 94 } 95 if (uniforms_size() > 0) { 96 OS << " uniform"; 97 StringRef Sep = "("; 98 for (auto *E : uniforms()) { 99 OS << Sep; 100 E->printPretty(OS, nullptr, Policy); 101 Sep = ", "; 102 } 103 OS << ")"; 104 } 105 alignments_iterator NI = alignments_begin(); 106 for (auto *E : aligneds()) { 107 OS << " aligned("; 108 E->printPretty(OS, nullptr, Policy); 109 if (*NI) { 110 OS << ": "; 111 (*NI)->printPretty(OS, nullptr, Policy); 112 } 113 OS << ")"; 114 ++NI; 115 } 116 steps_iterator I = steps_begin(); 117 modifiers_iterator MI = modifiers_begin(); 118 for (auto *E : linears()) { 119 OS << " linear("; 120 if (*MI != OMPC_LINEAR_unknown) 121 OS << getOpenMPSimpleClauseTypeName(llvm::omp::Clause::OMPC_linear, *MI) 122 << "("; 123 E->printPretty(OS, nullptr, Policy); 124 if (*MI != OMPC_LINEAR_unknown) 125 OS << ")"; 126 if (*I) { 127 OS << ": "; 128 (*I)->printPretty(OS, nullptr, Policy); 129 } 130 OS << ")"; 131 ++I; 132 ++MI; 133 } 134 } 135 136 void OMPDeclareTargetDeclAttr::printPrettyPragma( 137 raw_ostream &OS, const PrintingPolicy &Policy) const { 138 // Use fake syntax because it is for testing and debugging purpose only. 139 if (getDevType() != DT_Any) 140 OS << " device_type(" << ConvertDevTypeTyToStr(getDevType()) << ")"; 141 if (getMapType() != MT_To && getMapType() != MT_Enter) 142 OS << ' ' << ConvertMapTypeTyToStr(getMapType()); 143 if (Expr *E = getIndirectExpr()) { 144 OS << " indirect("; 145 E->printPretty(OS, nullptr, Policy); 146 OS << ")"; 147 } else if (getIndirect()) { 148 OS << " indirect"; 149 } 150 } 151 152 std::optional<OMPDeclareTargetDeclAttr *> 153 OMPDeclareTargetDeclAttr::getActiveAttr(const ValueDecl *VD) { 154 if (llvm::all_of(VD->redecls(), [](const Decl *D) { return !D->hasAttrs(); })) 155 return std::nullopt; 156 unsigned Level = 0; 157 OMPDeclareTargetDeclAttr *FoundAttr = nullptr; 158 for (const Decl *D : VD->redecls()) { 159 for (auto *Attr : D->specific_attrs<OMPDeclareTargetDeclAttr>()) { 160 if (Level <= Attr->getLevel()) { 161 Level = Attr->getLevel(); 162 FoundAttr = Attr; 163 } 164 } 165 } 166 if (FoundAttr) 167 return FoundAttr; 168 return std::nullopt; 169 } 170 171 std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> 172 OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(const ValueDecl *VD) { 173 std::optional<OMPDeclareTargetDeclAttr *> ActiveAttr = getActiveAttr(VD); 174 if (ActiveAttr) 175 return (*ActiveAttr)->getMapType(); 176 return std::nullopt; 177 } 178 179 std::optional<OMPDeclareTargetDeclAttr::DevTypeTy> 180 OMPDeclareTargetDeclAttr::getDeviceType(const ValueDecl *VD) { 181 std::optional<OMPDeclareTargetDeclAttr *> ActiveAttr = getActiveAttr(VD); 182 if (ActiveAttr) 183 return (*ActiveAttr)->getDevType(); 184 return std::nullopt; 185 } 186 187 std::optional<SourceLocation> 188 OMPDeclareTargetDeclAttr::getLocation(const ValueDecl *VD) { 189 std::optional<OMPDeclareTargetDeclAttr *> ActiveAttr = getActiveAttr(VD); 190 if (ActiveAttr) 191 return (*ActiveAttr)->getRange().getBegin(); 192 return std::nullopt; 193 } 194 195 namespace clang { 196 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const OMPTraitInfo &TI); 197 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const OMPTraitInfo *TI); 198 } 199 200 void OMPDeclareVariantAttr::printPrettyPragma( 201 raw_ostream &OS, const PrintingPolicy &Policy) const { 202 if (const Expr *E = getVariantFuncRef()) { 203 OS << "("; 204 E->printPretty(OS, nullptr, Policy); 205 OS << ")"; 206 } 207 OS << " match(" << traitInfos << ")"; 208 209 auto PrintExprs = [&OS, &Policy](Expr **Begin, Expr **End) { 210 for (Expr **I = Begin; I != End; ++I) { 211 assert(*I && "Expected non-null Stmt"); 212 if (I != Begin) 213 OS << ","; 214 (*I)->printPretty(OS, nullptr, Policy); 215 } 216 }; 217 if (adjustArgsNothing_size()) { 218 OS << " adjust_args(nothing:"; 219 PrintExprs(adjustArgsNothing_begin(), adjustArgsNothing_end()); 220 OS << ")"; 221 } 222 if (adjustArgsNeedDevicePtr_size()) { 223 OS << " adjust_args(need_device_ptr:"; 224 PrintExprs(adjustArgsNeedDevicePtr_begin(), adjustArgsNeedDevicePtr_end()); 225 OS << ")"; 226 } 227 228 auto PrintInteropInfo = [&OS](OMPInteropInfo *Begin, OMPInteropInfo *End) { 229 for (OMPInteropInfo *I = Begin; I != End; ++I) { 230 if (I != Begin) 231 OS << ", "; 232 OS << "interop("; 233 OS << getInteropTypeString(I); 234 OS << ")"; 235 } 236 }; 237 if (appendArgs_size()) { 238 OS << " append_args("; 239 PrintInteropInfo(appendArgs_begin(), appendArgs_end()); 240 OS << ")"; 241 } 242 } 243 244 unsigned AlignedAttr::getAlignment(ASTContext &Ctx) const { 245 assert(!isAlignmentDependent()); 246 if (getCachedAlignmentValue()) 247 return *getCachedAlignmentValue(); 248 249 // Handle alignmentType case. 250 if (!isAlignmentExpr()) { 251 QualType T = getAlignmentType()->getType(); 252 253 // C++ [expr.alignof]p3: 254 // When alignof is applied to a reference type, the result is the 255 // alignment of the referenced type. 256 T = T.getNonReferenceType(); 257 258 if (T.getQualifiers().hasUnaligned()) 259 return Ctx.getCharWidth(); 260 261 return Ctx.getTypeAlignInChars(T.getTypePtr()).getQuantity() * 262 Ctx.getCharWidth(); 263 } 264 265 // Handle alignmentExpr case. 266 if (alignmentExpr) 267 return alignmentExpr->EvaluateKnownConstInt(Ctx).getZExtValue() * 268 Ctx.getCharWidth(); 269 270 return Ctx.getTargetDefaultAlignForAttributeAligned(); 271 } 272 273 #include "clang/AST/AttrImpl.inc" 274