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