Tyker updated this revision to Diff 193284.

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D59467/new/

https://reviews.llvm.org/D59467

Files:
  clang/include/clang/AST/Stmt.h
  clang/include/clang/AST/StmtCXX.h
  clang/include/clang/AST/TextNodeDumper.h
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/AttrDocs.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/Scope.h
  clang/include/clang/Sema/Sema.h
  clang/lib/AST/ASTImporter.cpp
  clang/lib/AST/Stmt.cpp
  clang/lib/AST/StmtCXX.cpp
  clang/lib/AST/TextNodeDumper.cpp
  clang/lib/Analysis/CFG.cpp
  clang/lib/CodeGen/CGStmt.cpp
  clang/lib/CodeGen/CodeGenFunction.cpp
  clang/lib/CodeGen/CodeGenFunction.h
  clang/lib/Parse/ParseStmt.cpp
  clang/lib/Sema/Scope.cpp
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/lib/Sema/SemaStmt.cpp
  clang/lib/Sema/SemaStmtAttr.cpp
  clang/lib/Sema/TreeTransform.h
  clang/lib/Serialization/ASTReaderStmt.cpp
  clang/lib/Serialization/ASTWriterStmt.cpp
  clang/test/CodeGenCXX/cxx2a-likelihood-attr.cpp
  clang/test/PCH/cxx2a-likelihood-attr.cpp
  clang/test/SemaCXX/cxx17-compat.cpp
  clang/test/SemaCXX/cxx2a-likelihood-attr.cpp

Index: clang/test/SemaCXX/cxx2a-likelihood-attr.cpp
===================================================================
--- /dev/null
+++ clang/test/SemaCXX/cxx2a-likelihood-attr.cpp
@@ -0,0 +1,66 @@
+// RUN: %clang_cc1 -fsyntax-only %s -verify -std=c++2a
+
+// formating this file will break the test
+// clang-format off
+
+int f(int i) {
+  if (i == 1)
+    [[unlikely]] { f(i); }
+  else if (i == 2)
+    [[likely]] return f(i);
+  else
+    [[unlikely]] { return f(i + 1); }
+  return i;
+}
+
+[[likely]] typedef int n1;
+// expected-error@-1 {{'likely' attribute cannot be applied to a declaration}}
+typedef int [[likely]] n2;
+// expected-error@-1 {{'likely' attribute cannot be applied to types}}
+typedef int n3 [[likely]];
+// expected-error@-1 {{'likely' attribute cannot be applied to a declaration}}
+
+enum [[likely]] E{One};
+// expected-error@-1 {{'likely' attribute cannot be applied to a declaration}}
+
+[[likely]]
+// expected-error@-1 {{'likely' attribute cannot be applied to a declaration}}
+
+void test(int i) {
+  [[likely]]
+  // expected-warning@-1 {{attribute 'likely' is not associated with a branch and is ignored}}
+  if (f(i)) [[likely, likely]] {
+    // expected-error@-1 {{likely attribute cannot be repeated}}
+    // expected-note@-2 {{previous attribute is here}}
+    [[unlikely]] return;
+    // expected-warning@-1 {{attribute 'unlikely' is not associated with a branch and is ignored}}
+  }
+  else [[unlikely]] if (f(i)) {
+    while (f(i))
+      [[likely]] {
+        switch (i) {
+          [[likely]] case 1 : default : [[likely]];
+          // expected-warning@-1 {{attribute 'likely' is not associated with a branch and is ignored}}
+          [[unlikely]] case 3 : f(i);
+          [[fallthrough]];
+        case 4:
+          return;
+        }
+      }
+    for (;;)
+      [[likely, unlikely]]
+      // expected-error@-1 {{unlikely and likely attributes are not compatible}}
+      // expected-note@-2 {{previous attribute is here}}
+      [[likely]] return;
+    // expected-error@-1 {{likely attribute cannot be repeated}}
+    // expected-note@-5 {{previous attribute is here}}
+  }
+  try { // expected-error {{cannot use 'try' with exceptions disabled}}
+    [[likely]];
+    // expected-warning@-1 {{attribute 'likely' is not associated with a branch and is ignored}}
+  } catch (int) {
+    [[likely]] test :
+        // expected-error@-1 {{'likely' attribute cannot be applied to a declaration}}
+        [[unlikely]] return;
+  }
+}
Index: clang/test/SemaCXX/cxx17-compat.cpp
===================================================================
--- clang/test/SemaCXX/cxx17-compat.cpp
+++ clang/test/SemaCXX/cxx17-compat.cpp
@@ -63,3 +63,23 @@
     // expected-warning@-4 {{range-based for loop initialization statements are incompatible with C++ standards before C++2a}}
 #endif
 }
+
+//clang-format off
+
+int f(int i) {
+  if (i == 1)
+    [[unlikely]]
+#if __cplusplus <= 201703L
+// expected-warning@-2 {{use of the 'unlikely' attribute is a C++2a extension}}
+#endif
+    {
+      f(i);
+    }
+  else if (i == 2)
+    [[likely]]
+#if __cplusplus <= 201703L
+// expected-warning@-2 {{use of the 'likely' attribute is a C++2a extension}}
+#endif
+    return f(i);
+  return i;
+}
Index: clang/test/PCH/cxx2a-likelihood-attr.cpp
===================================================================
--- /dev/null
+++ clang/test/PCH/cxx2a-likelihood-attr.cpp
@@ -0,0 +1,57 @@
+// Test this without pch.
+// RUN: %clang_cc1 -std=c++2a -fsyntax-only -verify %s -ast-dump | FileCheck %s
+
+// Test with pch. Use '-ast-dump' to force deserialization of function bodies.
+// RUN: %clang_cc1 -x c++-header -std=c++2a -emit-pch -o %t %s
+// RUN: %clang_cc1 -std=c++2a -include-pch %t -fsyntax-only -verify %s
+// -ast-dump-all | FileCheck %s
+
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+void test(int i) {
+  if (i)
+    [[likely]] { return; }
+  else
+    [[unlikely]] if (i) {
+      while (i)
+        [[likely]] {}
+      do {
+        for (; i;)
+          [[likely]] {}
+        [[unlikely]];
+      } while (i);
+    }
+}
+
+#endif
+
+// CHECK:       IfStmt {{.*}} likely
+
+// CHECK:       AttributedStmt
+// CHECK-NEXT:  LikelihoodAttr {{.*}} likely
+
+// CHECK:       AttributedStmt
+// CHECK-NEXT:  LikelihoodAttr {{.*}} unlikely
+// CHECK-NEXT:  IfStmt
+
+// CHECK:       WhileStmt {{.*}} likely
+
+// CHECK:  AttributedStmt
+// CHECK-NEXT:  LikelihoodAttr {{.*}} likely
+
+// CHECk-NEXT:  CompoundStmt
+
+// CHECK:       DoStmt {{.*}} unlikely
+
+// CHECk-NEXT:  CompoundStmt
+
+// CHECk-NEXT:  ForStmt {{.*}} likely
+
+// CHECK:  AttributedStmt
+// CHECK-NEXT:  LikelihoodAttr {{.*}} likely
+
+// CHECK:  AttributedStmt
+// CHECK-NEXT:  LikelihoodAttr {{.*}} unlikely
\ No newline at end of file
Index: clang/test/CodeGenCXX/cxx2a-likelihood-attr.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGenCXX/cxx2a-likelihood-attr.cpp
@@ -0,0 +1,25 @@
+// clang-format off
+// RUN: %clang_cc1 -std=c++2a -cc1 -emit-llvm -disable-llvm-passes -O3 %s -o - -triple %itanium_abi_triple | FileCheck %s
+
+int test(int i) {
+  if (i == 0) {
+    // CHECK:       %expval = call i1 @llvm.expect.i1(i1 %cmp, i1 false)
+    // CHECK-NEXT:  br i1 %expval
+    i = i + 1;
+  } else
+    [[likely]] return 1;
+  while (i == 1)
+    [[unlikely]] { return 2; }
+  // CHECK:       %[[expval:.*]] = call i1 @llvm.expect.i1(i1 %[[cmp:.*]], i1
+  // false) CHECK-NEXT:  br i1 %expval
+  for (; i == 4;)
+    [[unlikely]] { return 2; }
+  // CHECK:       %[[expval:.*]] = call i1 @llvm.expect.i1(i1 %[[cmp:.*]], i1 false)
+  // CHECK-NEXT:  br i1 %expval
+  do
+    [[likely]] { return 2; }
+  while (i == 3);
+  // CHECK:       %[[expval:.*]] = call i1 @llvm.expect.i1(i1 %[[cmp:.*]], i1 true)
+  // CHECK-NEXT:  br i1 %expval
+  return 0;
+}
\ No newline at end of file
Index: clang/lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- clang/lib/Serialization/ASTWriterStmt.cpp
+++ clang/lib/Serialization/ASTWriterStmt.cpp
@@ -140,6 +140,7 @@
   Record.push_back(HasElse);
   Record.push_back(HasVar);
   Record.push_back(HasInit);
+  Record.push_back(static_cast<uint64_t>(S->getBranchHint()));
 
   Record.AddStmt(S->getCond());
   Record.AddStmt(S->getThen());
@@ -186,6 +187,7 @@
 
   bool HasVar = S->getConditionVariableDeclStmt() != nullptr;
   Record.push_back(HasVar);
+  Record.push_back(static_cast<uint64_t>(S->getBranchHint()));
 
   Record.AddStmt(S->getCond());
   Record.AddStmt(S->getBody());
@@ -203,6 +205,7 @@
   Record.AddSourceLocation(S->getDoLoc());
   Record.AddSourceLocation(S->getWhileLoc());
   Record.AddSourceLocation(S->getRParenLoc());
+  Record.push_back(static_cast<uint64_t>(S->getBranchHint()));
   Code = serialization::STMT_DO;
 }
 
@@ -216,6 +219,7 @@
   Record.AddSourceLocation(S->getForLoc());
   Record.AddSourceLocation(S->getLParenLoc());
   Record.AddSourceLocation(S->getRParenLoc());
+  Record.push_back(static_cast<uint64_t>(S->getBranchHint()));
   Code = serialization::STMT_FOR;
 }
 
@@ -1287,6 +1291,7 @@
 
 void ASTStmtWriter::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
   VisitStmt(S);
+  Record.push_back(static_cast<uint64_t>(S->getBranchHint()));
   Record.AddSourceLocation(S->getForLoc());
   Record.AddSourceLocation(S->getCoawaitLoc());
   Record.AddSourceLocation(S->getColonLoc());
Index: clang/lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- clang/lib/Serialization/ASTReaderStmt.cpp
+++ clang/lib/Serialization/ASTReaderStmt.cpp
@@ -223,6 +223,7 @@
   bool HasElse = Record.readInt();
   bool HasVar = Record.readInt();
   bool HasInit = Record.readInt();
+  S->setBranchHint(static_cast<BranchHint>(Record.readInt()));
 
   S->setCond(Record.readSubExpr());
   S->setThen(Record.readSubStmt());
@@ -272,6 +273,7 @@
   VisitStmt(S);
 
   bool HasVar = Record.readInt();
+  S->setBranchHint(static_cast<BranchHint>(Record.readInt()));
 
   S->setCond(Record.readSubExpr());
   S->setBody(Record.readSubStmt());
@@ -288,6 +290,7 @@
   S->setDoLoc(ReadSourceLocation());
   S->setWhileLoc(ReadSourceLocation());
   S->setRParenLoc(ReadSourceLocation());
+  S->setBranchHint(static_cast<BranchHint>(Record.readInt()));
 }
 
 void ASTStmtReader::VisitForStmt(ForStmt *S) {
@@ -300,6 +303,7 @@
   S->setForLoc(ReadSourceLocation());
   S->setLParenLoc(ReadSourceLocation());
   S->setRParenLoc(ReadSourceLocation());
+  S->setBranchHint(static_cast<BranchHint>(Record.readInt()));
 }
 
 void ASTStmtReader::VisitGotoStmt(GotoStmt *S) {
@@ -1324,6 +1328,7 @@
 
 void ASTStmtReader::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
   VisitStmt(S);
+  S->setBranchHint(static_cast<BranchHint>(Record.readInt()));
   S->ForLoc = ReadSourceLocation();
   S->CoawaitLoc = ReadSourceLocation();
   S->ColonLoc = ReadSourceLocation();
Index: clang/lib/Sema/TreeTransform.h
===================================================================
--- clang/lib/Sema/TreeTransform.h
+++ clang/lib/Sema/TreeTransform.h
@@ -1264,9 +1264,10 @@
   /// Subclasses may override this routine to provide different behavior.
   StmtResult RebuildIfStmt(SourceLocation IfLoc, bool IsConstexpr,
                            Sema::ConditionResult Cond, Stmt *Init, Stmt *Then,
-                           SourceLocation ElseLoc, Stmt *Else) {
-    return getSema().ActOnIfStmt(IfLoc, IsConstexpr, Init, Cond, Then,
-                                 ElseLoc, Else);
+                           SourceLocation ElseLoc, Stmt *Else,
+                           BranchHint Hint) {
+    return getSema().ActOnIfStmt(IfLoc, IsConstexpr, Init, Cond, Then, ElseLoc,
+                                 Else, Hint);
   }
 
   /// Start building a new switch statement.
@@ -1292,8 +1293,9 @@
   /// By default, performs semantic analysis to build the new statement.
   /// Subclasses may override this routine to provide different behavior.
   StmtResult RebuildWhileStmt(SourceLocation WhileLoc,
-                              Sema::ConditionResult Cond, Stmt *Body) {
-    return getSema().ActOnWhileStmt(WhileLoc, Cond, Body);
+                              Sema::ConditionResult Cond, Stmt *Body,
+                              BranchHint Hint) {
+    return getSema().ActOnWhileStmt(WhileLoc, Cond, Body, Hint);
   }
 
   /// Build a new do-while statement.
@@ -1302,9 +1304,10 @@
   /// Subclasses may override this routine to provide different behavior.
   StmtResult RebuildDoStmt(SourceLocation DoLoc, Stmt *Body,
                            SourceLocation WhileLoc, SourceLocation LParenLoc,
-                           Expr *Cond, SourceLocation RParenLoc) {
-    return getSema().ActOnDoStmt(DoLoc, Body, WhileLoc, LParenLoc,
-                                 Cond, RParenLoc);
+                           Expr *Cond, SourceLocation RParenLoc,
+                           BranchHint Hint) {
+    return getSema().ActOnDoStmt(DoLoc, Body, WhileLoc, LParenLoc, Cond,
+                                 RParenLoc, Hint);
   }
 
   /// Build a new for statement.
@@ -1314,9 +1317,9 @@
   StmtResult RebuildForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
                             Stmt *Init, Sema::ConditionResult Cond,
                             Sema::FullExprArg Inc, SourceLocation RParenLoc,
-                            Stmt *Body) {
-    return getSema().ActOnForStmt(ForLoc, LParenLoc, Init, Cond,
-                                  Inc, RParenLoc, Body);
+                            Stmt *Body, BranchHint Hint) {
+    return getSema().ActOnForStmt(ForLoc, LParenLoc, Init, Cond, Inc, RParenLoc,
+                                  Body, Hint);
   }
 
   /// Build a new goto statement.
@@ -2102,8 +2105,9 @@
   ///
   /// By default, performs semantic analysis to finish the new statement.
   /// Subclasses may override this routine to provide different behavior.
-  StmtResult FinishCXXForRangeStmt(Stmt *ForRange, Stmt *Body) {
-    return getSema().FinishCXXForRangeStmt(ForRange, Body);
+  StmtResult FinishCXXForRangeStmt(Stmt *ForRange, Stmt *Body,
+                                   BranchHint Hint) {
+    return getSema().FinishCXXForRangeStmt(ForRange, Body, Hint);
   }
 
   StmtResult RebuildSEHTryStmt(bool IsCXXTry, SourceLocation TryLoc,
@@ -6755,7 +6759,7 @@
 
   return getDerived().RebuildIfStmt(S->getIfLoc(), S->isConstexpr(), Cond,
                                     Init.get(), Then.get(), S->getElseLoc(),
-                                    Else.get());
+                                    Else.get(), S->getBranchHint());
 }
 
 template<typename Derived>
@@ -6809,7 +6813,8 @@
       Body.get() == S->getBody())
     return Owned(S);
 
-  return getDerived().RebuildWhileStmt(S->getWhileLoc(), Cond, Body.get());
+  return getDerived().RebuildWhileStmt(S->getWhileLoc(), Cond, Body.get(),
+                                       S->getBranchHint());
 }
 
 template<typename Derived>
@@ -6831,8 +6836,8 @@
     return S;
 
   return getDerived().RebuildDoStmt(S->getDoLoc(), Body.get(), S->getWhileLoc(),
-                                    /*FIXME:*/S->getWhileLoc(), Cond.get(),
-                                    S->getRParenLoc());
+                                    /*FIXME:*/ S->getWhileLoc(), Cond.get(),
+                                    S->getRParenLoc(), S->getBranchHint());
 }
 
 template<typename Derived>
@@ -6879,9 +6884,9 @@
       Body.get() == S->getBody())
     return S;
 
-  return getDerived().RebuildForStmt(S->getForLoc(), S->getLParenLoc(),
-                                     Init.get(), Cond, FullInc,
-                                     S->getRParenLoc(), Body.get());
+  return getDerived().RebuildForStmt(
+      S->getForLoc(), S->getLParenLoc(), Init.get(), Cond, FullInc,
+      S->getRParenLoc(), Body.get(), S->getBranchHint());
 }
 
 template<typename Derived>
@@ -7567,7 +7572,7 @@
   if (NewStmt.get() == S)
     return S;
 
-  return FinishCXXForRangeStmt(NewStmt.get(), Body.get());
+  return FinishCXXForRangeStmt(NewStmt.get(), Body.get(), S->getBranchHint());
 }
 
 template<typename Derived>
Index: clang/lib/Sema/SemaStmtAttr.cpp
===================================================================
--- clang/lib/Sema/SemaStmtAttr.cpp
+++ clang/lib/Sema/SemaStmtAttr.cpp
@@ -51,6 +51,58 @@
   return ::new (S.Context) auto(Attr);
 }
 
+static Attr *handleLikelihoodAttr(Sema &S, Stmt *St, const ParsedAttr &A,
+                                  SourceRange Range) {
+  LikelihoodAttr *Attr = ::new (S.Context) LikelihoodAttr(
+      A.getRange(), S.Context, A.getAttributeSpellingListIndex());
+
+  if (!S.getLangOpts().CPlusPlus2a && A.isCXX11Attribute())
+    S.Diag(A.getLoc(), diag::ext_cxx2a_attr) << A.getName();
+
+  // Handle attribute on case/default statement.
+  if (isa<CaseStmt>(St) || isa<DefaultStmt>(St)) {
+    FunctionScopeInfo *FnScope = S.getCurFunction();
+    if (FnScope->SwitchStack.empty()) {
+      S.Diag(A.getLoc(), diag::warn_likelihood_on_case_outside_switch)
+          << Attr->getSpelling() << (isa<CaseStmt>(St) ? "case" : "default");
+    }
+    return Attr;
+  }
+
+  // Handle attribute on If/For/while/Do/Catch statements.
+  Scope *CurScope = S.getCurScope();
+  if (CurScope) {
+    Scope *ControlScope = CurScope->getParent();
+    if (!ControlScope ||
+        !(ControlScope->getFlags() & Scope::ControlScope ||
+          ControlScope->getFlags() & Scope::BreakScope) ||
+        ControlScope->getFlags() & Scope::SwitchScope ||
+        ControlScope->getFlags() & Scope::SEHExceptScope ||
+        ControlScope->getFlags() & Scope::SEHTryScope ||
+        ControlScope->getFlags() & Scope::TryScope ||
+        ControlScope->getFlags() & Scope::FnTryCatchScope) {
+      S.Diag(A.getLoc(), diag::warn_no_likelihood_attr_associated_branch)
+          << A.getName();
+      return Attr;
+    }
+
+    if (ControlScope->getBranchLikelihoodAttr()) {
+      if (ControlScope->getBranchLikelihoodAttr()->getSpelling()[0] ==
+          Attr->getSpelling()[0])
+        S.Diag(Attr->getLocation(), diag::err_repeat_attribute)
+            << Attr->getSpelling();
+      else
+        S.Diag(Attr->getLocation(), diag::err_attributes_are_not_compatible)
+            << Attr->getSpelling()
+            << ControlScope->getBranchLikelihoodAttr()->getSpelling();
+      S.Diag(ControlScope->getBranchLikelihoodAttr()->getLocation(),
+             diag::note_previous_attribute);
+    } else
+      ControlScope->setBranchLikelihoodAttr(Attr);
+  }
+  return Attr;
+}
+
 static Attr *handleSuppressAttr(Sema &S, Stmt *St, const ParsedAttr &A,
                                 SourceRange Range) {
   if (A.getNumArgs() < 1) {
@@ -336,6 +388,8 @@
     return nullptr;
   case ParsedAttr::AT_FallThrough:
     return handleFallThroughAttr(S, St, A, Range);
+  case ParsedAttr::AT_Likelihood:
+    return handleLikelihoodAttr(S, St, A, Range);
   case ParsedAttr::AT_LoopHint:
     return handleLoopHintAttr(S, St, A, Range);
   case ParsedAttr::AT_OpenCLUnrollHint:
Index: clang/lib/Sema/SemaStmt.cpp
===================================================================
--- clang/lib/Sema/SemaStmt.cpp
+++ clang/lib/Sema/SemaStmt.cpp
@@ -519,13 +519,31 @@
     EvaluatedExprVisitor<CommaVisitor>::VisitBinaryOperator(E);
   }
 };
+} // namespace
+
+BranchHint Sema::HandleIfStmtHint(LikelihoodAttr *ThenLikelihoodAttr,
+                                  LikelihoodAttr *ElseLikelihoodAttr) {
+  if (ThenLikelihoodAttr) {
+    if (ElseLikelihoodAttr && ThenLikelihoodAttr->isEqual(ElseLikelihoodAttr)) {
+      Diag(ElseLikelihoodAttr->getLocation(),
+           diag::warn_conflicting_likelihood_attrs)
+          << ElseLikelihoodAttr->getSpelling()
+          << ThenLikelihoodAttr->getSpelling();
+      Diag(ThenLikelihoodAttr->getLocation(), diag::note_conflicting_attribute);
+    } else
+      return (ThenLikelihoodAttr->isLikely() ? BranchHint::BH_Taken
+                                             : BranchHint::BH_NotTaken);
+  } else if (ElseLikelihoodAttr) {
+    return (ElseLikelihoodAttr->isUnlikely() ? BranchHint::BH_Taken
+                                             : BranchHint::BH_NotTaken);
+  }
+  return BranchHint::BH_NoHint;
 }
 
-StmtResult
-Sema::ActOnIfStmt(SourceLocation IfLoc, bool IsConstexpr, Stmt *InitStmt,
-                  ConditionResult Cond,
-                  Stmt *thenStmt, SourceLocation ElseLoc,
-                  Stmt *elseStmt) {
+StmtResult Sema::ActOnIfStmt(SourceLocation IfLoc, bool IsConstexpr,
+                             Stmt *InitStmt, ConditionResult Cond,
+                             Stmt *thenStmt, SourceLocation ElseLoc,
+                             Stmt *elseStmt, BranchHint Hint) {
   if (Cond.isInvalid())
     Cond = ConditionResult(
         *this, nullptr,
@@ -545,13 +563,13 @@
                           diag::warn_empty_if_body);
 
   return BuildIfStmt(IfLoc, IsConstexpr, InitStmt, Cond, thenStmt, ElseLoc,
-                     elseStmt);
+                     elseStmt, Hint);
 }
 
 StmtResult Sema::BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr,
                              Stmt *InitStmt, ConditionResult Cond,
                              Stmt *thenStmt, SourceLocation ElseLoc,
-                             Stmt *elseStmt) {
+                             Stmt *elseStmt, BranchHint Hint) {
   if (Cond.isInvalid())
     return StmtError();
 
@@ -559,7 +577,7 @@
     setFunctionHasBranchProtectedScope();
 
   return IfStmt::Create(Context, IfLoc, IsConstexpr, InitStmt, Cond.get().first,
-                        Cond.get().second, thenStmt, ElseLoc, elseStmt);
+                        Cond.get().second, thenStmt, ElseLoc, elseStmt, Hint);
 }
 
 namespace {
@@ -1274,7 +1292,7 @@
 }
 
 StmtResult Sema::ActOnWhileStmt(SourceLocation WhileLoc, ConditionResult Cond,
-                                Stmt *Body) {
+                                Stmt *Body, BranchHint Hint) {
   if (Cond.isInvalid())
     return StmtError();
 
@@ -1289,13 +1307,13 @@
     getCurCompoundScope().setHasEmptyLoopBodies();
 
   return WhileStmt::Create(Context, CondVal.first, CondVal.second, Body,
-                           WhileLoc);
+                           WhileLoc, Hint);
 }
 
-StmtResult
-Sema::ActOnDoStmt(SourceLocation DoLoc, Stmt *Body,
-                  SourceLocation WhileLoc, SourceLocation CondLParen,
-                  Expr *Cond, SourceLocation CondRParen) {
+StmtResult Sema::ActOnDoStmt(SourceLocation DoLoc, Stmt *Body,
+                             SourceLocation WhileLoc, SourceLocation CondLParen,
+                             Expr *Cond, SourceLocation CondRParen,
+                             BranchHint Hint) {
   assert(Cond && "ActOnDoStmt(): missing expression");
 
   CheckBreakContinueBinding(Cond);
@@ -1314,7 +1332,7 @@
       !Diags.isIgnored(diag::warn_comma_operator, Cond->getExprLoc()))
     CommaVisitor(*this).Visit(Cond);
 
-  return new (Context) DoStmt(Body, Cond, DoLoc, WhileLoc, CondRParen);
+  return new (Context) DoStmt(Body, Cond, DoLoc, WhileLoc, CondRParen, Hint);
 }
 
 namespace {
@@ -1723,7 +1741,7 @@
 StmtResult Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
                               Stmt *First, ConditionResult Second,
                               FullExprArg third, SourceLocation RParenLoc,
-                              Stmt *Body) {
+                              Stmt *Body, BranchHint Hint) {
   if (Second.isInvalid())
     return StmtError();
 
@@ -1763,7 +1781,7 @@
 
   return new (Context)
       ForStmt(Context, First, Second.get().second, Second.get().first, Third,
-              Body, ForLoc, LParenLoc, RParenLoc);
+              Body, ForLoc, LParenLoc, RParenLoc, Hint);
 }
 
 /// In an Objective C collection iteration statement:
@@ -2632,8 +2650,8 @@
   return new (Context) CXXForRangeStmt(
       InitStmt, RangeDS, cast_or_null<DeclStmt>(BeginDeclStmt.get()),
       cast_or_null<DeclStmt>(EndDeclStmt.get()), NotEqExpr.get(),
-      IncrExpr.get(), LoopVarDS, /*Body=*/nullptr, ForLoc, CoawaitLoc,
-      ColonLoc, RParenLoc);
+      IncrExpr.get(), LoopVarDS, /*Body=*/nullptr, ForLoc, CoawaitLoc, ColonLoc,
+      RParenLoc, BranchHint::BH_NoHint);
 }
 
 /// FinishObjCForCollectionStmt - Attach the body to a objective-C foreach
@@ -2805,7 +2823,7 @@
 /// This is a separate step from ActOnCXXForRangeStmt because analysis of the
 /// body cannot be performed until after the type of the range variable is
 /// determined.
-StmtResult Sema::FinishCXXForRangeStmt(Stmt *S, Stmt *B) {
+StmtResult Sema::FinishCXXForRangeStmt(Stmt *S, Stmt *B, BranchHint Hint) {
   if (!S || !B)
     return StmtError();
 
@@ -2814,6 +2832,7 @@
 
   CXXForRangeStmt *ForStmt = cast<CXXForRangeStmt>(S);
   ForStmt->setBody(B);
+  ForStmt->setBranchHint(Hint);
 
   DiagnoseEmptyStmtBody(ForStmt->getRParenLoc(), B,
                         diag::warn_empty_range_based_for_body);
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -11821,13 +11821,15 @@
   return S.ActOnForStmt(
       Loc, Loc, InitStmt,
       S.ActOnCondition(nullptr, Loc, Comparison, Sema::ConditionKind::Boolean),
-      S.MakeFullDiscardedValueExpr(Increment), Loc, Copy.get());
+      S.MakeFullDiscardedValueExpr(Increment), Loc, Copy.get(),
+      BranchHint::BH_NoHint);
 }
 
-static StmtResult
-buildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
-                      const ExprBuilder &To, const ExprBuilder &From,
-                      bool CopyingBaseSubobject, bool Copying) {
+static StmtResult buildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
+                                        const ExprBuilder &To,
+                                        const ExprBuilder &From,
+                                        bool CopyingBaseSubobject,
+                                        bool Copying) {
   // Maybe we should use a memcpy?
   if (T->isArrayType() && !T.isConstQualified() && !T.isVolatileQualified() &&
       T.isTriviallyCopyableType(S.Context))
Index: clang/lib/Sema/Scope.cpp
===================================================================
--- clang/lib/Sema/Scope.cpp
+++ clang/lib/Sema/Scope.cpp
@@ -87,6 +87,7 @@
 void Scope::Init(Scope *parent, unsigned flags) {
   setFlags(parent, flags);
 
+  BranchLikelihoodAttr = nullptr;
   DeclsInScope.clear();
   UsingDirectives.clear();
   Entity = nullptr;
Index: clang/lib/Parse/ParseStmt.cpp
===================================================================
--- clang/lib/Parse/ParseStmt.cpp
+++ clang/lib/Parse/ParseStmt.cpp
@@ -1259,6 +1259,9 @@
   // Pop the 'if' scope if needed.
   InnerScope.Exit();
 
+  LikelihoodAttr *ThenLikelihoodAttr = getCurScope()->getBranchLikelihoodAttr();
+  getCurScope()->setBranchLikelihoodAttr(nullptr);
+
   // If it has an else, parse it.
   SourceLocation ElseLoc;
   SourceLocation ElseStmtLoc;
@@ -1298,6 +1301,7 @@
   } else if (InnerStatementTrailingElseLoc.isValid()) {
     Diag(InnerStatementTrailingElseLoc, diag::warn_dangling_else);
   }
+  LikelihoodAttr *ElseLikelihoodAttr = getCurScope()->getBranchLikelihoodAttr();
 
   IfScope.Exit();
 
@@ -1317,8 +1321,10 @@
   if (ElseStmt.isInvalid())
     ElseStmt = Actions.ActOnNullStmt(ElseStmtLoc);
 
-  return Actions.ActOnIfStmt(IfLoc, IsConstexpr, InitStmt.get(), Cond,
-                             ThenStmt.get(), ElseLoc, ElseStmt.get());
+  return Actions.ActOnIfStmt(
+      IfLoc, IsConstexpr, InitStmt.get(), Cond, ThenStmt.get(), ElseLoc,
+      ElseStmt.get(),
+      Actions.HandleIfStmtHint(ThenLikelihoodAttr, ElseLikelihoodAttr));
 }
 
 /// ParseSwitchStatement
@@ -1406,6 +1412,15 @@
   return Actions.ActOnFinishSwitchStmt(SwitchLoc, Switch.get(), Body.get());
 }
 
+/// Converts a potentially null Likelihood attribute in a BranchHint.
+static BranchHint
+getHintFromLikelihoodAttr(LikelihoodAttr *BranchLikelihoodAttr) {
+  if (BranchLikelihoodAttr)
+    return (BranchLikelihoodAttr->isLikely() ? BranchHint::BH_Taken
+                                             : BranchHint::BH_NotTaken);
+  return BranchHint::BH_NoHint;
+}
+
 /// ParseWhileStatement
 ///       while-statement: [C99 6.8.5.1]
 ///         'while' '(' expression ')' statement
@@ -1467,12 +1482,16 @@
 
   // Pop the body scope if needed.
   InnerScope.Exit();
+  LikelihoodAttr *BranchLikelihoodAttr =
+      getCurScope()->getBranchLikelihoodAttr();
   WhileScope.Exit();
 
   if (Cond.isInvalid() || Body.isInvalid())
     return StmtError();
 
-  return Actions.ActOnWhileStmt(WhileLoc, Cond, Body.get());
+  return Actions.ActOnWhileStmt(
+      WhileLoc, Cond, Body.get(),
+      getHintFromLikelihoodAttr(BranchLikelihoodAttr));
 }
 
 /// ParseDoStatement
@@ -1538,13 +1557,16 @@
   if (Cond.isUsable())
     Cond = Actions.CorrectDelayedTyposInExpr(Cond);
   T.consumeClose();
+  LikelihoodAttr *BranchLikelihoodAttr =
+      getCurScope()->getBranchLikelihoodAttr();
   DoScope.Exit();
 
   if (Cond.isInvalid() || Body.isInvalid())
     return StmtError();
 
   return Actions.ActOnDoStmt(DoLoc, Body.get(), WhileLoc, T.getOpenLocation(),
-                             Cond.get(), T.getCloseLocation());
+                             Cond.get(), T.getCloseLocation(),
+                             getHintFromLikelihoodAttr(BranchLikelihoodAttr));
 }
 
 bool Parser::isForRangeIdentifier() {
@@ -1902,6 +1924,8 @@
   // Pop the body scope if needed.
   InnerScope.Exit();
 
+  LikelihoodAttr *BranchLikelihoodAttr =
+      getCurScope()->getBranchLikelihoodAttr();
   // Leave the for-scope.
   ForScope.Exit();
 
@@ -1913,11 +1937,14 @@
                                               Body.get());
 
   if (ForRangeInfo.ParsedForRangeDecl())
-    return Actions.FinishCXXForRangeStmt(ForRangeStmt.get(), Body.get());
+    return Actions.FinishCXXForRangeStmt(
+        ForRangeStmt.get(), Body.get(),
+        getHintFromLikelihoodAttr(BranchLikelihoodAttr));
 
   return Actions.ActOnForStmt(ForLoc, T.getOpenLocation(), FirstPart.get(),
                               SecondPart, ThirdPart, T.getCloseLocation(),
-                              Body.get());
+                              Body.get(),
+                              getHintFromLikelihoodAttr(BranchLikelihoodAttr));
 }
 
 /// ParseGotoStatement
Index: clang/lib/CodeGen/CodeGenFunction.h
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.h
+++ clang/lib/CodeGen/CodeGenFunction.h
@@ -2847,10 +2847,12 @@
 
   Address EmitCompoundStmt(const CompoundStmt &S, bool GetLast = false,
                            AggValueSlot AVS = AggValueSlot::ignored());
-  Address EmitCompoundStmtWithoutScope(const CompoundStmt &S,
-                                       bool GetLast = false,
-                                       AggValueSlot AVS =
-                                                AggValueSlot::ignored());
+  Address
+  EmitCompoundStmtWithoutScope(const CompoundStmt &S, bool GetLast = false,
+                               AggValueSlot AVS = AggValueSlot::ignored());
+
+  /// MaybeEmitLikelihoodHint - Emit and llvm.expect if a hint is present.
+  llvm::Value *MaybeEmitLikelihoodHint(llvm::Value *CondV, BranchHint Hint);
 
   /// EmitLabel - Emit the block for the given label. It is legal to call this
   /// function even if there is no current insertion point.
@@ -4037,7 +4039,8 @@
   /// TrueCount should be the number of times we expect the condition to
   /// evaluate to true based on PGO data.
   void EmitBranchOnBoolExpr(const Expr *Cond, llvm::BasicBlock *TrueBlock,
-                            llvm::BasicBlock *FalseBlock, uint64_t TrueCount);
+                            llvm::BasicBlock *FalseBlock, uint64_t TrueCount,
+                            BranchHint hint = BranchHint::BH_NoHint);
 
   /// Given an assignment `*LHS = RHS`, emit a test that checks if \p RHS is
   /// nonnull, if \p LHS is marked _Nonnull.
Index: clang/lib/CodeGen/CodeGenFunction.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.cpp
+++ clang/lib/CodeGen/CodeGenFunction.cpp
@@ -1531,7 +1531,8 @@
 void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond,
                                            llvm::BasicBlock *TrueBlock,
                                            llvm::BasicBlock *FalseBlock,
-                                           uint64_t TrueCount) {
+                                           uint64_t TrueCount,
+                                           BranchHint Hint) {
   Cond = Cond->IgnoreParens();
 
   if (const BinaryOperator *CondBOp = dyn_cast<BinaryOperator>(Cond)) {
@@ -1720,6 +1721,16 @@
     ApplyDebugLocation DL(*this, Cond);
     CondV = EvaluateExprAsBool(Cond);
   }
+
+  if (Hint != BranchHint::BH_NoHint &&
+      CGM.getCodeGenOpts().OptimizationLevel != 0) {
+    llvm::Constant *ExpectedValue =
+        llvm::ConstantInt::get(llvm::Type::getInt1Ty(this->getLLVMContext()),
+                               Hint == BranchHint::BH_Taken);
+    llvm::Function *FnExpect =
+        CGM.getIntrinsic(llvm::Intrinsic::expect, CondV->getType());
+    CondV = Builder.CreateCall(FnExpect, {CondV, ExpectedValue}, "expval");
+  }
   Builder.CreateCondBr(CondV, TrueBlock, FalseBlock, Weights, Unpredictable);
 }
 
Index: clang/lib/CodeGen/CGStmt.cpp
===================================================================
--- clang/lib/CodeGen/CGStmt.cpp
+++ clang/lib/CodeGen/CGStmt.cpp
@@ -658,7 +658,7 @@
     ElseBlock = createBasicBlock("if.else");
 
   EmitBranchOnBoolExpr(S.getCond(), ThenBlock, ElseBlock,
-                       getProfileCount(S.getThen()));
+                       getProfileCount(S.getThen()), S.getBranchHint());
 
   // Emit the 'then' code.
   EmitBlock(ThenBlock);
@@ -691,6 +691,20 @@
   EmitBlock(ContBlock, true);
 }
 
+llvm::Value *CodeGenFunction::MaybeEmitLikelihoodHint(llvm::Value *CondV,
+                                                      BranchHint Hint) {
+  if (Hint != BranchHint::BH_NoHint &&
+      CGM.getCodeGenOpts().OptimizationLevel != 0) {
+    llvm::Constant *ExpectedValue =
+        llvm::ConstantInt::get(llvm::Type::getInt1Ty(this->getLLVMContext()),
+                               Hint == BranchHint::BH_Taken);
+    llvm::Function *FnExpect =
+        CGM.getIntrinsic(llvm::Intrinsic::expect, CondV->getType());
+    return Builder.CreateCall(FnExpect, {CondV, ExpectedValue}, "expval");
+  }
+  return CondV;
+}
+
 void CodeGenFunction::EmitWhileStmt(const WhileStmt &S,
                                     ArrayRef<const Attr *> WhileAttrs) {
   // Emit the header for the loop, which will also become
@@ -740,6 +754,7 @@
     llvm::BasicBlock *ExitBlock = LoopExit.getBlock();
     if (ConditionScope.requiresCleanups())
       ExitBlock = createBasicBlock("while.exit");
+    BoolCondVal = MaybeEmitLikelihoodHint(BoolCondVal, S.getBranchHint());
     Builder.CreateCondBr(
         BoolCondVal, LoopBody, ExitBlock,
         createProfileWeightsForLoop(S.getCond(), getProfileCount(S.getBody())));
@@ -825,6 +840,7 @@
   // As long as the condition is true, iterate the loop.
   if (EmitBoolCondBranch) {
     uint64_t BackedgeCount = getProfileCount(S.getBody()) - ParentCount;
+    BoolCondVal = MaybeEmitLikelihoodHint(BoolCondVal, S.getBranchHint());
     Builder.CreateCondBr(
         BoolCondVal, LoopBody, LoopExit.getBlock(),
         createProfileWeightsForLoop(S.getCond(), BackedgeCount));
@@ -895,6 +911,7 @@
     // C99 6.8.5p2/p4: The first substatement is executed if the expression
     // compares unequal to 0.  The condition must be a scalar type.
     llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
+    BoolCondVal = MaybeEmitLikelihoodHint(BoolCondVal, S.getBranchHint());
     Builder.CreateCondBr(
         BoolCondVal, ForBody, ExitBlock,
         createProfileWeightsForLoop(S.getCond(), getProfileCount(S.getBody())));
@@ -976,6 +993,7 @@
   // The body is executed if the expression, contextually converted
   // to bool, is true.
   llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
+  MaybeEmitLikelihoodHint(BoolCondVal, S.getBranchHint());
   Builder.CreateCondBr(
       BoolCondVal, ForBody, ExitBlock,
       createProfileWeightsForLoop(S.getCond(), getProfileCount(S.getBody())));
Index: clang/lib/Analysis/CFG.cpp
===================================================================
--- clang/lib/Analysis/CFG.cpp
+++ clang/lib/Analysis/CFG.cpp
@@ -584,6 +584,7 @@
   CFGBlock *VisitWhileStmt(WhileStmt *W);
 
   CFGBlock *Visit(Stmt *S, AddStmtChoice asc = AddStmtChoice::NotAlwaysAdd);
+  CFGBlock *VisitAttributedStmt(AttributedStmt *S, AddStmtChoice asc);
   CFGBlock *VisitStmt(Stmt *S, AddStmtChoice asc);
   CFGBlock *VisitChildren(Stmt *S);
   CFGBlock *VisitNoRecurse(Expr *E, AddStmtChoice asc);
@@ -2186,6 +2187,9 @@
     case Stmt::StmtExprClass:
       return VisitStmtExpr(cast<StmtExpr>(S), asc);
 
+    case Stmt::AttributedStmtClass:
+      return VisitAttributedStmt(cast<AttributedStmt>(S), asc);
+
     case Stmt::SwitchStmtClass:
       return VisitSwitchStmt(cast<SwitchStmt>(S));
 
@@ -2197,6 +2201,15 @@
   }
 }
 
+CFGBlock *CFGBuilder::VisitAttributedStmt(AttributedStmt *S,
+                                          AddStmtChoice asc) {
+  if (asc.alwaysAdd(*this, S) && isa<NullStmt>(S->getSubStmt())) {
+    autoCreateBlock();
+    appendStmt(Block, S);
+  }
+  return Visit(S->getSubStmt());
+}
+
 CFGBlock *CFGBuilder::VisitStmt(Stmt *S, AddStmtChoice asc) {
   if (asc.alwaysAdd(*this, S)) {
     autoCreateBlock();
Index: clang/lib/AST/TextNodeDumper.cpp
===================================================================
--- clang/lib/AST/TextNodeDumper.cpp
+++ clang/lib/AST/TextNodeDumper.cpp
@@ -658,6 +658,9 @@
     OS << " has_var";
   if (Node->hasElseStorage())
     OS << " has_else";
+  if (Node->getBranchHint() != BranchHint::BH_NoHint)
+    OS << ((Node->getBranchHint() == BranchHint::BH_Taken) ? " likely"
+                                                           : " unlikely");
 }
 
 void TextNodeDumper::VisitSwitchStmt(const SwitchStmt *Node) {
@@ -670,6 +673,27 @@
 void TextNodeDumper::VisitWhileStmt(const WhileStmt *Node) {
   if (Node->hasVarStorage())
     OS << " has_var";
+  if (Node->getBranchHint() != BranchHint::BH_NoHint)
+    OS << (Node->getBranchHint() == BranchHint::BH_Taken ? " likely"
+                                                         : " unlikely");
+}
+
+void TextNodeDumper::VisitForStmt(const ForStmt *Node) {
+  if (Node->getBranchHint() != BranchHint::BH_NoHint)
+    OS << (Node->getBranchHint() == BranchHint::BH_Taken ? " likely"
+                                                         : " unlikely");
+}
+
+void TextNodeDumper::VisitDoStmt(const DoStmt *Node) {
+  if (Node->getBranchHint() != BranchHint::BH_NoHint)
+    OS << (Node->getBranchHint() == BranchHint::BH_Taken ? " likely"
+                                                         : " unlikely");
+}
+
+void TextNodeDumper::VisitCXXForRangeStmt(const CXXForRangeStmt *Node) {
+  if (Node->getBranchHint() != BranchHint::BH_NoHint)
+    OS << (Node->getBranchHint() == BranchHint::BH_Taken ? " likely"
+                                                         : " unlikely");
 }
 
 void TextNodeDumper::VisitLabelStmt(const LabelStmt *Node) {
Index: clang/lib/AST/StmtCXX.cpp
===================================================================
--- clang/lib/AST/StmtCXX.cpp
+++ clang/lib/AST/StmtCXX.cpp
@@ -49,7 +49,7 @@
                                  Expr *Cond, Expr *Inc, DeclStmt *LoopVar,
                                  Stmt *Body, SourceLocation FL,
                                  SourceLocation CAL, SourceLocation CL,
-                                 SourceLocation RPL)
+                                 SourceLocation RPL, BranchHint Hint)
     : Stmt(CXXForRangeStmtClass), ForLoc(FL), CoawaitLoc(CAL), ColonLoc(CL),
       RParenLoc(RPL) {
   SubExprs[INIT] = Init;
@@ -60,6 +60,7 @@
   SubExprs[INC] = Inc;
   SubExprs[LOOPVAR] = LoopVar;
   SubExprs[BODY] = Body;
+  setBranchHint(Hint);
 }
 
 Expr *CXXForRangeStmt::getRangeInit() {
Index: clang/lib/AST/Stmt.cpp
===================================================================
--- clang/lib/AST/Stmt.cpp
+++ clang/lib/AST/Stmt.cpp
@@ -798,7 +798,7 @@
 
 IfStmt::IfStmt(const ASTContext &Ctx, SourceLocation IL, bool IsConstexpr,
                Stmt *Init, VarDecl *Var, Expr *Cond, Stmt *Then,
-               SourceLocation EL, Stmt *Else)
+               SourceLocation EL, Stmt *Else, BranchHint Hint)
     : Stmt(IfStmtClass) {
   bool HasElse = Else != nullptr;
   bool HasVar = Var != nullptr;
@@ -806,6 +806,7 @@
   IfStmtBits.HasElse = HasElse;
   IfStmtBits.HasVar = HasVar;
   IfStmtBits.HasInit = HasInit;
+  IfStmtBits.Hint = Hint;
 
   setConstexpr(IsConstexpr);
 
@@ -832,7 +833,8 @@
 
 IfStmt *IfStmt::Create(const ASTContext &Ctx, SourceLocation IL,
                        bool IsConstexpr, Stmt *Init, VarDecl *Var, Expr *Cond,
-                       Stmt *Then, SourceLocation EL, Stmt *Else) {
+                       Stmt *Then, SourceLocation EL, Stmt *Else,
+                       BranchHint Hint) {
   bool HasElse = Else != nullptr;
   bool HasVar = Var != nullptr;
   bool HasInit = Init != nullptr;
@@ -841,7 +843,7 @@
           NumMandatoryStmtPtr + HasElse + HasVar + HasInit, HasElse),
       alignof(IfStmt));
   return new (Mem)
-      IfStmt(Ctx, IL, IsConstexpr, Init, Var, Cond, Then, EL, Else);
+      IfStmt(Ctx, IL, IsConstexpr, Init, Var, Cond, Then, EL, Else, Hint);
 }
 
 IfStmt *IfStmt::CreateEmpty(const ASTContext &Ctx, bool HasElse, bool HasVar,
@@ -880,15 +882,15 @@
 
 ForStmt::ForStmt(const ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar,
                  Expr *Inc, Stmt *Body, SourceLocation FL, SourceLocation LP,
-                 SourceLocation RP)
-  : Stmt(ForStmtClass), LParenLoc(LP), RParenLoc(RP)
-{
+                 SourceLocation RP, BranchHint Hint)
+    : Stmt(ForStmtClass), LParenLoc(LP), RParenLoc(RP) {
   SubExprs[INIT] = Init;
   setConditionVariable(C, condVar);
   SubExprs[COND] = Cond;
   SubExprs[INC] = Inc;
   SubExprs[BODY] = Body;
   ForStmtBits.ForLoc = FL;
+  ForStmtBits.Hint = Hint;
 }
 
 VarDecl *ForStmt::getConditionVariable() const {
@@ -976,10 +978,11 @@
 }
 
 WhileStmt::WhileStmt(const ASTContext &Ctx, VarDecl *Var, Expr *Cond,
-                     Stmt *Body, SourceLocation WL)
+                     Stmt *Body, SourceLocation WL, BranchHint Hint)
     : Stmt(WhileStmtClass) {
   bool HasVar = Var != nullptr;
   WhileStmtBits.HasVar = HasVar;
+  WhileStmtBits.Hint = Hint;
 
   setCond(Cond);
   setBody(Body);
@@ -995,12 +998,12 @@
 }
 
 WhileStmt *WhileStmt::Create(const ASTContext &Ctx, VarDecl *Var, Expr *Cond,
-                             Stmt *Body, SourceLocation WL) {
+                             Stmt *Body, SourceLocation WL, BranchHint Hint) {
   bool HasVar = Var != nullptr;
   void *Mem =
       Ctx.Allocate(totalSizeToAlloc<Stmt *>(NumMandatoryStmtPtr + HasVar),
                    alignof(WhileStmt));
-  return new (Mem) WhileStmt(Ctx, Var, Cond, Body, WL);
+  return new (Mem) WhileStmt(Ctx, Var, Cond, Body, WL, Hint);
 }
 
 WhileStmt *WhileStmt::CreateEmpty(const ASTContext &Ctx, bool HasVar) {
Index: clang/lib/AST/ASTImporter.cpp
===================================================================
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -5682,7 +5682,7 @@
 
   return IfStmt::Create(Importer.getToContext(), ToIfLoc, S->isConstexpr(),
                         ToInit, ToConditionVariable, ToCond, ToThen, ToElseLoc,
-                        ToElse);
+                        ToElse, S->getBranchHint());
 }
 
 ExpectedStmt ASTNodeImporter::VisitSwitchStmt(SwitchStmt *S) {
@@ -5733,7 +5733,7 @@
   std::tie(ToConditionVariable, ToCond, ToBody, ToWhileLoc) = *Imp;
 
   return WhileStmt::Create(Importer.getToContext(), ToConditionVariable, ToCond,
-                           ToBody, ToWhileLoc);
+                           ToBody, ToWhileLoc, S->getBranchHint());
 }
 
 ExpectedStmt ASTNodeImporter::VisitDoStmt(DoStmt *S) {
@@ -5749,7 +5749,7 @@
   std::tie(ToBody, ToCond, ToDoLoc, ToWhileLoc, ToRParenLoc) = *Imp;
 
   return new (Importer.getToContext()) DoStmt(
-      ToBody, ToCond, ToDoLoc, ToWhileLoc, ToRParenLoc);
+      ToBody, ToCond, ToDoLoc, ToWhileLoc, ToRParenLoc, S->getBranchHint());
 }
 
 ExpectedStmt ASTNodeImporter::VisitForStmt(ForStmt *S) {
@@ -5764,14 +5764,12 @@
   VarDecl *ToConditionVariable;
   Stmt *ToBody;
   SourceLocation ToForLoc, ToLParenLoc, ToRParenLoc;
-  std::tie(
-      ToInit, ToCond, ToConditionVariable,  ToInc, ToBody, ToForLoc,
-      ToLParenLoc, ToRParenLoc) = *Imp;
+  std::tie(ToInit, ToCond, ToConditionVariable, ToInc, ToBody, ToForLoc,
+           ToLParenLoc, ToRParenLoc) = *Imp;
 
   return new (Importer.getToContext()) ForStmt(
-      Importer.getToContext(),
-      ToInit, ToCond, ToConditionVariable, ToInc, ToBody, ToForLoc, ToLParenLoc,
-      ToRParenLoc);
+      Importer.getToContext(), ToInit, ToCond, ToConditionVariable, ToInc,
+      ToBody, ToForLoc, ToLParenLoc, ToRParenLoc, S->getBranchHint());
 }
 
 ExpectedStmt ASTNodeImporter::VisitGotoStmt(GotoStmt *S) {
@@ -5886,9 +5884,10 @@
   SourceLocation ToForLoc, ToCoawaitLoc, ToColonLoc, ToRParenLoc;
   std::tie(ToForLoc, ToCoawaitLoc, ToColonLoc, ToRParenLoc) = *Imp2;
 
-  return new (Importer.getToContext()) CXXForRangeStmt(
-      ToInit, ToRangeStmt, ToBeginStmt, ToEndStmt, ToCond, ToInc, ToLoopVarStmt,
-      ToBody, ToForLoc, ToCoawaitLoc, ToColonLoc, ToRParenLoc);
+  return new (Importer.getToContext())
+      CXXForRangeStmt(ToInit, ToRangeStmt, ToBeginStmt, ToEndStmt, ToCond,
+                      ToInc, ToLoopVarStmt, ToBody, ToForLoc, ToCoawaitLoc,
+                      ToColonLoc, ToRParenLoc, S->getBranchHint());
 }
 
 ExpectedStmt
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -3834,32 +3834,33 @@
                                  Stmt *SubStmt);
 
   class ConditionResult;
-  StmtResult ActOnIfStmt(SourceLocation IfLoc, bool IsConstexpr,
-                         Stmt *InitStmt,
+  /// Diagnose conflicting attribute and determinate the hint.
+  BranchHint HandleIfStmtHint(LikelihoodAttr *ThenLikelihoodAttr,
+                              LikelihoodAttr *ElseLikelihoodAttr);
+
+  StmtResult ActOnIfStmt(SourceLocation IfLoc, bool IsConstexpr, Stmt *InitStmt,
                          ConditionResult Cond, Stmt *ThenVal,
-                         SourceLocation ElseLoc, Stmt *ElseVal);
-  StmtResult BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr,
-                         Stmt *InitStmt,
+                         SourceLocation ElseLoc, Stmt *ElseVal,
+                         BranchHint Hint);
+  StmtResult BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr, Stmt *InitStmt,
                          ConditionResult Cond, Stmt *ThenVal,
-                         SourceLocation ElseLoc, Stmt *ElseVal);
-  StmtResult ActOnStartOfSwitchStmt(SourceLocation SwitchLoc,
-                                    Stmt *InitStmt,
+                         SourceLocation ElseLoc, Stmt *ElseVal,
+                         BranchHint Hint);
+  StmtResult ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Stmt *InitStmt,
                                     ConditionResult Cond);
   StmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc,
                                            Stmt *Switch, Stmt *Body);
   StmtResult ActOnWhileStmt(SourceLocation WhileLoc, ConditionResult Cond,
-                            Stmt *Body);
+                            Stmt *Body, BranchHint Hint);
   StmtResult ActOnDoStmt(SourceLocation DoLoc, Stmt *Body,
                          SourceLocation WhileLoc, SourceLocation CondLParen,
-                         Expr *Cond, SourceLocation CondRParen);
-
-  StmtResult ActOnForStmt(SourceLocation ForLoc,
-                          SourceLocation LParenLoc,
-                          Stmt *First,
-                          ConditionResult Second,
-                          FullExprArg Third,
-                          SourceLocation RParenLoc,
-                          Stmt *Body);
+                         Expr *Cond, SourceLocation CondRParen,
+                         BranchHint Hint);
+
+  StmtResult ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
+                          Stmt *First, ConditionResult Second,
+                          FullExprArg Third, SourceLocation RParenLoc,
+                          Stmt *Body, BranchHint Hint);
   ExprResult CheckObjCForCollectionOperand(SourceLocation forLoc,
                                            Expr *collection);
   StmtResult ActOnObjCForCollectionStmt(SourceLocation ForColLoc,
@@ -3894,7 +3895,7 @@
                                   Stmt *LoopVarDecl,
                                   SourceLocation RParenLoc,
                                   BuildForRangeKind Kind);
-  StmtResult FinishCXXForRangeStmt(Stmt *ForRange, Stmt *Body);
+  StmtResult FinishCXXForRangeStmt(Stmt *ForRange, Stmt *Body, BranchHint Hint);
 
   StmtResult ActOnGotoStmt(SourceLocation GotoLoc,
                            SourceLocation LabelLoc,
Index: clang/include/clang/Sema/Scope.h
===================================================================
--- clang/include/clang/Sema/Scope.h
+++ clang/include/clang/Sema/Scope.h
@@ -33,6 +33,7 @@
 class DeclContext;
 class UsingDirectiveDecl;
 class VarDecl;
+class LikelihoodAttr;
 
 /// Scope - A scope is a transient data structure that is used while parsing the
 /// program.  It assists with resolving identifiers to the appropriate
@@ -163,6 +164,10 @@
   /// declared in this scope.
   unsigned short PrototypeIndex;
 
+  /// BranchLikelihoodAttr - This is the Likelihood attribute associated with
+  /// this Branch or a nullptr.
+  LikelihoodAttr *BranchLikelihoodAttr;
+
   /// FnParent - If this scope has a parent scope that is a function body, this
   /// pointer is non-null and points to it.  This is used for label processing.
   Scope *FnParent;
@@ -224,6 +229,17 @@
   /// isBlockScope - Return true if this scope correspond to a closure.
   bool isBlockScope() const { return Flags & BlockScope; }
 
+  /// getBranchLikelihoodAttr - Return the branching attribute associated with
+  /// this scope.
+  const LikelihoodAttr *getBranchLikelihoodAttr() const {
+    return BranchLikelihoodAttr;
+  }
+  LikelihoodAttr *getBranchLikelihoodAttr() { return BranchLikelihoodAttr; }
+
+  void setBranchLikelihoodAttr(LikelihoodAttr *Attribute) {
+    BranchLikelihoodAttr = Attribute;
+  }
+
   /// getParent - Return the scope that this is nested in.
   const Scope *getParent() const { return AnyParent; }
   Scope *getParent() { return AnyParent; }
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -7348,6 +7348,8 @@
   "use of the %0 attribute is a C++14 extension">, InGroup<CXX14>;
 def ext_cxx17_attr : Extension<
   "use of the %0 attribute is a C++17 extension">, InGroup<CXX17>;
+def ext_cxx2a_attr : Extension<
+  "use of the %0 attribute is a C++2a extension">, InGroup<CXX2a>;
 
 def warn_unused_comparison : Warning<
   "%select{equality|inequality|relational|three-way}0 comparison result unused">,
@@ -8167,6 +8169,13 @@
   "fallthrough annotation in unreachable code">,
   InGroup<ImplicitFallthrough>, DefaultIgnore;
 
+def warn_likelihood_on_case_outside_switch : Error<
+  "%0 attribute on %1 statement is outside switch statement">;
+def warn_no_likelihood_attr_associated_branch : Warning<
+  "attribute %0 is not associated with a branch and is ignored">, InGroup<IgnoredAttributes>;
+def warn_conflicting_likelihood_attrs : Warning<
+  "attribute %0 conflicts with previous attribute %1">, InGroup<IgnoredAttributes>;
+
 def warn_unreachable_default : Warning<
   "default label in switch which covers all enumeration values">,
   InGroup<CoveredSwitchDefault>, DefaultIgnore;
Index: clang/include/clang/Basic/AttrDocs.td
===================================================================
--- clang/include/clang/Basic/AttrDocs.td
+++ clang/include/clang/Basic/AttrDocs.td
@@ -1502,6 +1502,39 @@
   }];
 }
 
+def LikelihoodDocs : Documentation {
+  let Category = DocCatStmt;
+  let Heading = "likely / unlikely";
+  let Content = [{
+
+The ``likely`` or ``unlikely`` attribute is used to annotate that a statement or label is likely or unlikely to executed
+
+Here is an example:
+
+.. code-block:: c++
+
+  void g(int);
+  int f(int n) {
+    if (n > 5) [[unlikely]] {     // n > 5 is considered to be arbitrarily unlikely
+      g(0);
+      return n * 2 + 1;
+    }
+
+    switch (n) {
+    case 1:
+      g(1);
+      [[fallthrough]];
+
+    [[likely]] case 2:            // n == 2 is considered to be arbitrarily more
+      g(2);                       // likely than any other value of n
+      break;
+    }
+    return 3;
+  }
+
+  }];
+}
+
 def ARMInterruptDocs : Documentation {
   let Category = DocCatFunction;
   let Heading = "interrupt (ARM)";
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -1147,6 +1147,23 @@
   let Documentation = [FallthroughDocs];
 }
 
+def Likelihood : StmtAttr {
+  let Spellings = [CXX11<"", "likely", 201803>, Clang<"likely">, CXX11<"", "unlikely", 201803>, Clang<"unlikely">];
+// let Subjects = [Stmt, LabelStmt];
+  let AdditionalMembers = [{
+    bool isLikely() {
+      return getSpelling()[0] == 'l';
+    }
+    bool isUnlikely() {
+      return getSpelling()[0] == 'u';
+    }
+    bool isEqual(LikelihoodAttr* OtherAttr) {
+      return getSpelling()[0] == OtherAttr->getSpelling()[0];
+    }
+  }];
+  let Documentation = [LikelihoodDocs];
+}
+
 def FastCall : DeclOrTypeAttr {
   let Spellings = [GCC<"fastcall">, Keyword<"__fastcall">,
                    Keyword<"_fastcall">];
Index: clang/include/clang/AST/TextNodeDumper.h
===================================================================
--- clang/include/clang/AST/TextNodeDumper.h
+++ clang/include/clang/AST/TextNodeDumper.h
@@ -225,6 +225,9 @@
   void VisitIfStmt(const IfStmt *Node);
   void VisitSwitchStmt(const SwitchStmt *Node);
   void VisitWhileStmt(const WhileStmt *Node);
+  void VisitForStmt(const ForStmt *Node);
+  void VisitDoStmt(const DoStmt *Node);
+  void VisitCXXForRangeStmt(const CXXForRangeStmt *Node);
   void VisitLabelStmt(const LabelStmt *Node);
   void VisitGotoStmt(const GotoStmt *Node);
   void VisitCaseStmt(const CaseStmt *Node);
Index: clang/include/clang/AST/StmtCXX.h
===================================================================
--- clang/include/clang/AST/StmtCXX.h
+++ clang/include/clang/AST/StmtCXX.h
@@ -138,7 +138,7 @@
   CXXForRangeStmt(Stmt *InitStmt, DeclStmt *Range, DeclStmt *Begin,
                   DeclStmt *End, Expr *Cond, Expr *Inc, DeclStmt *LoopVar,
                   Stmt *Body, SourceLocation FL, SourceLocation CAL,
-                  SourceLocation CL, SourceLocation RPL);
+                  SourceLocation CL, SourceLocation RPL, BranchHint Hint);
   CXXForRangeStmt(EmptyShell Empty) : Stmt(CXXForRangeStmtClass, Empty) { }
 
   Stmt *getInit() { return SubExprs[INIT]; }
@@ -160,6 +160,9 @@
   DeclStmt *getLoopVarStmt() { return cast<DeclStmt>(SubExprs[LOOPVAR]); }
   Stmt *getBody() { return SubExprs[BODY]; }
 
+  BranchHint getBranchHint() const { return CXXForRangeStmtBits.Hint; }
+  void setBranchHint(BranchHint Hint) { CXXForRangeStmtBits.Hint = Hint; }
+
   const DeclStmt *getRangeStmt() const {
     return cast<DeclStmt>(SubExprs[RANGE]);
   }
Index: clang/include/clang/AST/Stmt.h
===================================================================
--- clang/include/clang/AST/Stmt.h
+++ clang/include/clang/AST/Stmt.h
@@ -55,6 +55,11 @@
 class StringLiteral;
 class Token;
 class VarDecl;
+class CXXForRangeStmt;
+
+/// BranchHint - This indicate if a conditional statement is expected to be
+/// taken, not taken or no indication.
+enum class BranchHint : unsigned { BH_NoHint, BH_Taken, BH_NotTaken };
 
 //===----------------------------------------------------------------------===//
 // AST classes for statements.
@@ -175,6 +180,9 @@
     /// True if this if statement has storage for an init statement.
     unsigned HasInit : 1;
 
+    /// holds information about likeliness of the branch being taken
+    BranchHint Hint : 2;
+
     /// The location of the "if".
     SourceLocation IfLoc;
   };
@@ -208,6 +216,9 @@
     /// True if the WhileStmt has storage for a condition variable.
     unsigned HasVar : 1;
 
+    /// holds information about likeliness of the branch being taken
+    BranchHint Hint : 2;
+
     /// The location of the "while".
     SourceLocation WhileLoc;
   };
@@ -217,6 +228,9 @@
 
     unsigned : NumStmtBits;
 
+    /// holds information about likeliness of the branch being taken
+    BranchHint Hint : 2;
+
     /// The location of the "do".
     SourceLocation DoLoc;
   };
@@ -226,6 +240,9 @@
 
     unsigned : NumStmtBits;
 
+    /// holds information about likeliness of the branch being taken
+    BranchHint Hint : 2;
+
     /// The location of the "for".
     SourceLocation ForLoc;
   };
@@ -284,6 +301,15 @@
     SourceLocation KeywordLoc;
   };
 
+  class CXXForRangeStmtBitfields {
+    friend class CXXForRangeStmt;
+
+    unsigned : NumStmtBits;
+
+    /// holds information about likeliness of the branch being taken
+    BranchHint Hint : 2;
+  };
+
   //===--- Expression bitfields classes ---===//
 
   class ExprBitfields {
@@ -917,6 +943,9 @@
     ReturnStmtBitfields ReturnStmtBits;
     SwitchCaseBitfields SwitchCaseBits;
 
+    // C++ Statements
+    CXXForRangeStmtBitfields CXXForRangeStmtBits;
+
     // Expressions
     ExprBitfields ExprBits;
     PredefinedExprBitfields PredefinedExprBits;
@@ -1766,7 +1795,8 @@
 
   /// Build an if/then/else statement.
   IfStmt(const ASTContext &Ctx, SourceLocation IL, bool IsConstexpr, Stmt *Init,
-         VarDecl *Var, Expr *Cond, Stmt *Then, SourceLocation EL, Stmt *Else);
+         VarDecl *Var, Expr *Cond, Stmt *Then, SourceLocation EL, Stmt *Else,
+         BranchHint Hint);
 
   /// Build an empty if/then/else statement.
   explicit IfStmt(EmptyShell Empty, bool HasElse, bool HasVar, bool HasInit);
@@ -1776,7 +1806,8 @@
   static IfStmt *Create(const ASTContext &Ctx, SourceLocation IL,
                         bool IsConstexpr, Stmt *Init, VarDecl *Var, Expr *Cond,
                         Stmt *Then, SourceLocation EL = SourceLocation(),
-                        Stmt *Else = nullptr);
+                        Stmt *Else = nullptr,
+                        BranchHint Hint = BranchHint::BH_NoHint);
 
   /// Create an empty IfStmt optionally with storage for an else statement,
   /// condition variable and init expression.
@@ -1792,6 +1823,9 @@
   /// True if this IfStmt has storage for an else statement.
   bool hasElseStorage() const { return IfStmtBits.HasElse; }
 
+  BranchHint getBranchHint() const { return IfStmtBits.Hint; }
+  void setBranchHint(BranchHint Hint) { IfStmtBits.Hint = Hint; }
+
   Expr *getCond() {
     return reinterpret_cast<Expr *>(getTrailingObjects<Stmt *>()[condOffset()]);
   }
@@ -2125,7 +2159,7 @@
 
   /// Build a while statement.
   WhileStmt(const ASTContext &Ctx, VarDecl *Var, Expr *Cond, Stmt *Body,
-            SourceLocation WL);
+            SourceLocation WL, BranchHint Hint);
 
   /// Build an empty while statement.
   explicit WhileStmt(EmptyShell Empty, bool HasVar);
@@ -2133,7 +2167,7 @@
 public:
   /// Create a while statement.
   static WhileStmt *Create(const ASTContext &Ctx, VarDecl *Var, Expr *Cond,
-                           Stmt *Body, SourceLocation WL);
+                           Stmt *Body, SourceLocation WL, BranchHint Hint);
 
   /// Create an empty while statement optionally with storage for
   /// a condition variable.
@@ -2142,6 +2176,9 @@
   /// True if this WhileStmt has storage for a condition variable.
   bool hasVarStorage() const { return WhileStmtBits.HasVar; }
 
+  BranchHint getBranchHint() const { return WhileStmtBits.Hint; }
+  void setBranchHint(BranchHint Hint) { WhileStmtBits.Hint = Hint; }
+
   Expr *getCond() {
     return reinterpret_cast<Expr *>(getTrailingObjects<Stmt *>()[condOffset()]);
   }
@@ -2223,11 +2260,12 @@
 
 public:
   DoStmt(Stmt *Body, Expr *Cond, SourceLocation DL, SourceLocation WL,
-         SourceLocation RP)
+         SourceLocation RP, BranchHint Hint)
       : Stmt(DoStmtClass), WhileLoc(WL), RParenLoc(RP) {
     setCond(Cond);
     setBody(Body);
     setDoLoc(DL);
+    setBranchHint(Hint);
   }
 
   /// Build an empty do-while statement.
@@ -2240,6 +2278,9 @@
 
   void setCond(Expr *Cond) { SubExprs[COND] = reinterpret_cast<Stmt *>(Cond); }
 
+  BranchHint getBranchHint() const { return DoStmtBits.Hint; }
+  void setBranchHint(BranchHint Hint) { DoStmtBits.Hint = Hint; }
+
   Stmt *getBody() { return SubExprs[BODY]; }
   const Stmt *getBody() const { return SubExprs[BODY]; }
   void setBody(Stmt *Body) { SubExprs[BODY] = Body; }
@@ -2275,7 +2316,7 @@
 public:
   ForStmt(const ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar,
           Expr *Inc, Stmt *Body, SourceLocation FL, SourceLocation LP,
-          SourceLocation RP);
+          SourceLocation RP, BranchHint Hint);
 
   /// Build an empty for statement.
   explicit ForStmt(EmptyShell Empty) : Stmt(ForStmtClass, Empty) {}
@@ -2299,6 +2340,9 @@
     return reinterpret_cast<DeclStmt*>(SubExprs[CONDVAR]);
   }
 
+  BranchHint getBranchHint() const { return ForStmtBits.Hint; }
+  void setBranchHint(BranchHint Hint) { ForStmtBits.Hint = Hint; }
+
   Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); }
   Expr *getInc()  { return reinterpret_cast<Expr*>(SubExprs[INC]); }
   Stmt *getBody() { return SubExprs[BODY]; }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to