| 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: 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, Helper: nullptr, Policy); |
| 46 | else if (state == FixedWidth || state == ScalableWidth) { |
| 47 | if (value) { |
| 48 | value->printPretty(OS, Helper: 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: 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(Val: getBranchState()); |
| 90 | if (auto *E = getSimdlen()) { |
| 91 | OS << " simdlen(" ; |
| 92 | E->printPretty(OS, Helper: 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, Helper: 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, Helper: nullptr, Policy); |
| 109 | if (*NI) { |
| 110 | OS << ": " ; |
| 111 | (*NI)->printPretty(OS, Helper: 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(Kind: llvm::omp::Clause::OMPC_linear, Type: *MI) |
| 122 | << "(" ; |
| 123 | E->printPretty(OS, Helper: nullptr, Policy); |
| 124 | if (*MI != OMPC_LINEAR_unknown) |
| 125 | OS << ")" ; |
| 126 | if (*I) { |
| 127 | OS << ": " ; |
| 128 | (*I)->printPretty(OS, Helper: 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(Val: getDevType()) << ")" ; |
| 141 | if (getMapType() != MT_To && getMapType() != MT_Enter) |
| 142 | OS << ' ' << ConvertMapTypeTyToStr(Val: getMapType()); |
| 143 | if (Expr *E = getIndirectExpr()) { |
| 144 | OS << " indirect(" ; |
| 145 | E->printPretty(OS, Helper: 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(Range: VD->redecls(), P: [](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, Helper: 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, Helper: 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 | if (adjustArgsNeedDeviceAddr_size()) { |
| 228 | OS << " adjust_args(need_device_addr:" ; |
| 229 | PrintExprs(adjustArgsNeedDeviceAddr_begin(), |
| 230 | adjustArgsNeedDeviceAddr_end()); |
| 231 | OS << ")" ; |
| 232 | } |
| 233 | |
| 234 | auto PrintInteropInfo = [&OS](OMPInteropInfo *Begin, OMPInteropInfo *End) { |
| 235 | for (OMPInteropInfo *I = Begin; I != End; ++I) { |
| 236 | if (I != Begin) |
| 237 | OS << ", " ; |
| 238 | OS << "interop(" ; |
| 239 | OS << getInteropTypeString(I); |
| 240 | OS << ")" ; |
| 241 | } |
| 242 | }; |
| 243 | if (appendArgs_size()) { |
| 244 | OS << " append_args(" ; |
| 245 | PrintInteropInfo(appendArgs_begin(), appendArgs_end()); |
| 246 | OS << ")" ; |
| 247 | } |
| 248 | } |
| 249 | |
| 250 | unsigned AlignedAttr::getAlignment(ASTContext &Ctx) const { |
| 251 | assert(!isAlignmentDependent()); |
| 252 | if (getCachedAlignmentValue()) |
| 253 | return *getCachedAlignmentValue(); |
| 254 | |
| 255 | // Handle alignmentType case. |
| 256 | if (!isAlignmentExpr()) { |
| 257 | QualType T = getAlignmentType()->getType(); |
| 258 | |
| 259 | // C++ [expr.alignof]p3: |
| 260 | // When alignof is applied to a reference type, the result is the |
| 261 | // alignment of the referenced type. |
| 262 | T = T.getNonReferenceType(); |
| 263 | |
| 264 | if (T.getQualifiers().hasUnaligned()) |
| 265 | return Ctx.getCharWidth(); |
| 266 | |
| 267 | return Ctx.getTypeAlignInChars(T: T.getTypePtr()).getQuantity() * |
| 268 | Ctx.getCharWidth(); |
| 269 | } |
| 270 | |
| 271 | // Handle alignmentExpr case. |
| 272 | if (alignmentExpr) |
| 273 | return alignmentExpr->EvaluateKnownConstInt(Ctx).getZExtValue() * |
| 274 | Ctx.getCharWidth(); |
| 275 | |
| 276 | return Ctx.getTargetDefaultAlignForAttributeAligned(); |
| 277 | } |
| 278 | |
| 279 | StringLiteral *FormatMatchesAttr::getFormatString() const { |
| 280 | return cast<StringLiteral>(Val: getExpectedFormat()); |
| 281 | } |
| 282 | |
| 283 | #include "clang/AST/AttrImpl.inc" |
| 284 | |