SemaStmtAttr.cpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. //===--- SemaStmtAttr.cpp - Statement Attribute Handling ------------------===//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. //
  10. // This file implements stmt-related attribute processing.
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #include "clang/Sema/SemaInternal.h"
  14. #include "clang/AST/ASTContext.h"
  15. #include "clang/Basic/SourceManager.h"
  16. #include "clang/Sema/DelayedDiagnostic.h"
  17. #include "clang/Sema/Lookup.h"
  18. #include "clang/Sema/LoopHint.h"
  19. #include "clang/Sema/ScopeInfo.h"
  20. #include "llvm/ADT/StringExtras.h"
  21. #include "clang/Sema/SemaHLSL.h" // HLSL Change
  22. using namespace clang;
  23. using namespace sema;
  24. static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const AttributeList &A,
  25. SourceRange Range) {
  26. if (!isa<NullStmt>(St)) {
  27. S.Diag(A.getRange().getBegin(), diag::err_fallthrough_attr_wrong_target)
  28. << St->getLocStart();
  29. if (isa<SwitchCase>(St)) {
  30. SourceLocation L = S.getLocForEndOfToken(Range.getEnd());
  31. S.Diag(L, diag::note_fallthrough_insert_semi_fixit)
  32. << FixItHint::CreateInsertion(L, ";");
  33. }
  34. return nullptr;
  35. }
  36. if (S.getCurFunction()->SwitchStack.empty()) {
  37. S.Diag(A.getRange().getBegin(), diag::err_fallthrough_attr_outside_switch);
  38. return nullptr;
  39. }
  40. return ::new (S.Context) FallThroughAttr(A.getRange(), S.Context,
  41. A.getAttributeSpellingListIndex());
  42. }
  43. static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A,
  44. SourceRange) {
  45. IdentifierLoc *PragmaNameLoc = A.getArgAsIdent(0);
  46. IdentifierLoc *OptionLoc = A.getArgAsIdent(1);
  47. IdentifierLoc *StateLoc = A.getArgAsIdent(2);
  48. Expr *ValueExpr = A.getArgAsExpr(3);
  49. bool PragmaUnroll = PragmaNameLoc->Ident->getName() == "unroll";
  50. bool PragmaNoUnroll = PragmaNameLoc->Ident->getName() == "nounroll";
  51. if (St->getStmtClass() != Stmt::DoStmtClass &&
  52. St->getStmtClass() != Stmt::ForStmtClass &&
  53. St->getStmtClass() != Stmt::CXXForRangeStmtClass &&
  54. St->getStmtClass() != Stmt::WhileStmtClass) {
  55. const char *Pragma =
  56. llvm::StringSwitch<const char *>(PragmaNameLoc->Ident->getName())
  57. .Case("unroll", "#pragma unroll")
  58. .Case("nounroll", "#pragma nounroll")
  59. .Default("#pragma clang loop");
  60. S.Diag(St->getLocStart(), diag::err_pragma_loop_precedes_nonloop) << Pragma;
  61. return nullptr;
  62. }
  63. LoopHintAttr::OptionType Option;
  64. LoopHintAttr::Spelling Spelling;
  65. if (PragmaUnroll) {
  66. Option = ValueExpr ? LoopHintAttr::UnrollCount : LoopHintAttr::Unroll;
  67. Spelling = LoopHintAttr::Pragma_unroll;
  68. } else if (PragmaNoUnroll) {
  69. Option = LoopHintAttr::Unroll;
  70. Spelling = LoopHintAttr::Pragma_nounroll;
  71. } else {
  72. assert(OptionLoc && OptionLoc->Ident &&
  73. "Attribute must have valid option info.");
  74. IdentifierInfo *OptionInfo = OptionLoc->Ident;
  75. Option = llvm::StringSwitch<LoopHintAttr::OptionType>(OptionInfo->getName())
  76. .Case("vectorize", LoopHintAttr::Vectorize)
  77. .Case("vectorize_width", LoopHintAttr::VectorizeWidth)
  78. .Case("interleave", LoopHintAttr::Interleave)
  79. .Case("interleave_count", LoopHintAttr::InterleaveCount)
  80. .Case("unroll", LoopHintAttr::Unroll)
  81. .Case("unroll_count", LoopHintAttr::UnrollCount)
  82. .Default(LoopHintAttr::Vectorize);
  83. Spelling = LoopHintAttr::Pragma_clang_loop;
  84. }
  85. LoopHintAttr::LoopHintState State = LoopHintAttr::Default;
  86. if (PragmaNoUnroll) {
  87. State = LoopHintAttr::Disable;
  88. } else if (Option == LoopHintAttr::VectorizeWidth ||
  89. Option == LoopHintAttr::InterleaveCount ||
  90. Option == LoopHintAttr::UnrollCount) {
  91. assert(ValueExpr && "Attribute must have a valid value expression.");
  92. if (S.CheckLoopHintExpr(ValueExpr, St->getLocStart()))
  93. return nullptr;
  94. } else if (Option == LoopHintAttr::Vectorize ||
  95. Option == LoopHintAttr::Interleave ||
  96. Option == LoopHintAttr::Unroll) {
  97. // Default state is assumed if StateLoc is not specified, such as with
  98. // '#pragma unroll'.
  99. if (StateLoc && StateLoc->Ident) {
  100. if (StateLoc->Ident->isStr("disable"))
  101. State = LoopHintAttr::Disable;
  102. else if (StateLoc->Ident->isStr("assume_safety"))
  103. State = LoopHintAttr::AssumeSafety;
  104. else
  105. State = LoopHintAttr::Enable;
  106. }
  107. }
  108. return LoopHintAttr::CreateImplicit(S.Context, Spelling, Option, State,
  109. ValueExpr, A.getRange());
  110. }
  111. static void
  112. CheckForIncompatibleAttributes(Sema &S,
  113. const SmallVectorImpl<const Attr *> &Attrs) {
  114. // There are 3 categories of loop hints attributes: vectorize, interleave,
  115. // and unroll. Each comes in two variants: a state form and a numeric form.
  116. // The state form selectively defaults/enables/disables the transformation
  117. // for the loop (for unroll, default indicates full unrolling rather than
  118. // enabling the transformation). The numeric form form provides an integer
  119. // hint (for example, unroll count) to the transformer. The following array
  120. // accumulates the hints encountered while iterating through the attributes
  121. // to check for compatibility.
  122. struct {
  123. const LoopHintAttr *StateAttr;
  124. const LoopHintAttr *NumericAttr;
  125. } HintAttrs[] = {{nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}};
  126. for (const auto *I : Attrs) {
  127. const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(I);
  128. // Skip non loop hint attributes
  129. if (!LH)
  130. continue;
  131. int Option = LH->getOption();
  132. int Category;
  133. enum { Vectorize, Interleave, Unroll };
  134. switch (Option) {
  135. case LoopHintAttr::Vectorize:
  136. case LoopHintAttr::VectorizeWidth:
  137. Category = Vectorize;
  138. break;
  139. case LoopHintAttr::Interleave:
  140. case LoopHintAttr::InterleaveCount:
  141. Category = Interleave;
  142. break;
  143. case LoopHintAttr::Unroll:
  144. case LoopHintAttr::UnrollCount:
  145. Category = Unroll;
  146. break;
  147. };
  148. auto &CategoryState = HintAttrs[Category];
  149. const LoopHintAttr *PrevAttr;
  150. if (Option == LoopHintAttr::Vectorize ||
  151. Option == LoopHintAttr::Interleave || Option == LoopHintAttr::Unroll) {
  152. // Enable|Disable|AssumeSafety hint. For example, vectorize(enable).
  153. PrevAttr = CategoryState.StateAttr;
  154. CategoryState.StateAttr = LH;
  155. } else {
  156. // Numeric hint. For example, vectorize_width(8).
  157. PrevAttr = CategoryState.NumericAttr;
  158. CategoryState.NumericAttr = LH;
  159. }
  160. PrintingPolicy Policy(S.Context.getLangOpts());
  161. SourceLocation OptionLoc = LH->getRange().getBegin();
  162. if (PrevAttr)
  163. // Cannot specify same type of attribute twice.
  164. S.Diag(OptionLoc, diag::err_pragma_loop_compatibility)
  165. << /*Duplicate=*/true << PrevAttr->getDiagnosticName(Policy)
  166. << LH->getDiagnosticName(Policy);
  167. if (CategoryState.StateAttr && CategoryState.NumericAttr &&
  168. (Category == Unroll ||
  169. CategoryState.StateAttr->getState() == LoopHintAttr::Disable)) {
  170. // Disable hints are not compatible with numeric hints of the same
  171. // category. As a special case, numeric unroll hints are also not
  172. // compatible with "enable" form of the unroll pragma, unroll(full).
  173. S.Diag(OptionLoc, diag::err_pragma_loop_compatibility)
  174. << /*Duplicate=*/false
  175. << CategoryState.StateAttr->getDiagnosticName(Policy)
  176. << CategoryState.NumericAttr->getDiagnosticName(Policy);
  177. }
  178. }
  179. }
  180. static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A,
  181. SourceRange Range) {
  182. switch (A.getKind()) {
  183. case AttributeList::UnknownAttribute:
  184. S.Diag(A.getLoc(), A.isDeclspecAttribute() ?
  185. diag::warn_unhandled_ms_attribute_ignored :
  186. diag::warn_unknown_attribute_ignored) << A.getName();
  187. return nullptr;
  188. case AttributeList::AT_FallThrough:
  189. return handleFallThroughAttr(S, St, A, Range);
  190. case AttributeList::AT_LoopHint:
  191. return handleLoopHintAttr(S, St, A, Range);
  192. default:
  193. // HLSL Change Starts
  194. {
  195. bool Handled = false;
  196. Attr* hlslResult = hlsl::ProcessStmtAttributeForHLSL(S, St, A, Range, Handled);
  197. if (Handled) return hlslResult;
  198. }
  199. // HLSL Change Ends
  200. // if we're here, then we parsed a known attribute, but didn't recognize
  201. // it as a statement attribute => it is declaration attribute
  202. S.Diag(A.getRange().getBegin(), diag::err_attribute_invalid_on_stmt)
  203. << A.getName() << St->getLocStart();
  204. return nullptr;
  205. }
  206. }
  207. StmtResult Sema::ProcessStmtAttributes(Stmt *S, AttributeList *AttrList,
  208. SourceRange Range) {
  209. SmallVector<const Attr*, 8> Attrs;
  210. for (const AttributeList* l = AttrList; l; l = l->getNext()) {
  211. if (Attr *a = ProcessStmtAttribute(*this, S, *l, Range))
  212. Attrs.push_back(a);
  213. }
  214. CheckForIncompatibleAttributes(*this, Attrs);
  215. if (Attrs.empty())
  216. return S;
  217. return ActOnAttributedStmt(Range.getBegin(), Attrs, S);
  218. }