Mordante updated this revision to Diff 288781.
Mordante marked an inline comment as done.
Mordante added a comment.

Reworked the patch to match the behaviour as discussed in D86559 
<https://reviews.llvm.org/D86559>.

- The likelihood attributes only have an effect when used directly on the 
ThenStmt and ElseStmt.
- Conflicting attributes on the ThenStmt and ElseStmt generate a diagnostic.
- Moved the likelihood determination from the CodeGen to the Sema. This 
requires the state to be stored in the AST.
- Updated the AST functions for the new likelihood bits.
- Updated the documentation.

Note currently there's no diagnostic for ignored attributes, this will be added 
in a future patch.


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

https://reviews.llvm.org/D85091

Files:
  clang/include/clang/AST/Stmt.h
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/AttrDocs.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/Sema.h
  clang/lib/AST/JSONNodeDumper.cpp
  clang/lib/AST/Stmt.cpp
  clang/lib/AST/TextNodeDumper.cpp
  clang/lib/CodeGen/CGStmt.cpp
  clang/lib/CodeGen/CodeGenFunction.cpp
  clang/lib/CodeGen/CodeGenFunction.h
  clang/lib/Parse/ParseDeclCXX.cpp
  clang/lib/Sema/SemaStmt.cpp
  clang/lib/Sema/SemaStmtAttr.cpp
  clang/lib/Serialization/ASTReaderStmt.cpp
  clang/lib/Serialization/ASTWriterStmt.cpp
  clang/test/AST/ast-dump-if-json.cpp
  clang/test/AST/ast-dump-stmt.cpp
  clang/test/CodeGenCXX/attr-likelihood-if-branch-weights.cpp
  clang/test/Preprocessor/has_attribute.cpp
  clang/test/Sema/attr-likelihood.c
  clang/test/SemaCXX/attr-likelihood.cpp
  clang/www/cxx_status.html
  llvm/include/llvm/Transforms/Scalar/LowerExpectIntrinsic.h
  llvm/lib/Transforms/Scalar/LowerExpectIntrinsic.cpp

Index: llvm/lib/Transforms/Scalar/LowerExpectIntrinsic.cpp
===================================================================
--- llvm/lib/Transforms/Scalar/LowerExpectIntrinsic.cpp
+++ llvm/lib/Transforms/Scalar/LowerExpectIntrinsic.cpp
@@ -24,7 +24,6 @@
 #include "llvm/IR/Metadata.h"
 #include "llvm/InitializePasses.h"
 #include "llvm/Pass.h"
-#include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Transforms/Scalar.h"
 #include "llvm/Transforms/Utils/MisExpect.h"
@@ -48,10 +47,10 @@
 // 'select' instructions. It may be worthwhile to hoist these values to some
 // shared space, so they can be used directly by other passes.
 
-static cl::opt<uint32_t> LikelyBranchWeight(
+cl::opt<uint32_t> llvm::LikelyBranchWeight(
     "likely-branch-weight", cl::Hidden, cl::init(2000),
     cl::desc("Weight of the branch likely to be taken (default = 2000)"));
-static cl::opt<uint32_t> UnlikelyBranchWeight(
+cl::opt<uint32_t> llvm::UnlikelyBranchWeight(
     "unlikely-branch-weight", cl::Hidden, cl::init(1),
     cl::desc("Weight of the branch unlikely to be taken (default = 1)"));
 
Index: llvm/include/llvm/Transforms/Scalar/LowerExpectIntrinsic.h
===================================================================
--- llvm/include/llvm/Transforms/Scalar/LowerExpectIntrinsic.h
+++ llvm/include/llvm/Transforms/Scalar/LowerExpectIntrinsic.h
@@ -17,6 +17,7 @@
 
 #include "llvm/IR/Function.h"
 #include "llvm/IR/PassManager.h"
+#include "llvm/Support/CommandLine.h"
 
 namespace llvm {
 
@@ -31,6 +32,8 @@
   PreservedAnalyses run(Function &F, FunctionAnalysisManager &);
 };
 
+extern cl::opt<uint32_t> LikelyBranchWeight;
+extern cl::opt<uint32_t> UnlikelyBranchWeight;
 }
 
 #endif
Index: clang/www/cxx_status.html
===================================================================
--- clang/www/cxx_status.html
+++ clang/www/cxx_status.html
@@ -987,7 +987,7 @@
     <tr>
       <td><tt>[[likely]]</tt> and <tt>[[unlikely]]</tt> attributes</td>
       <td><a href="https://wg21.link/p0479r5";>P0479R5</a></td>
-      <td class="none" align="center">No</td>
+      <td class="none" align="center">Clang 12 (partial)</td>
     </tr>
     <tr>
       <td><tt>typename</tt> optional in more contexts</td>
Index: clang/test/SemaCXX/attr-likelihood.cpp
===================================================================
--- /dev/null
+++ clang/test/SemaCXX/attr-likelihood.cpp
@@ -0,0 +1,132 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify
+// RUN: %clang_cc1 %s -DPEDANTIC -pedantic -fsyntax-only -verify
+
+#if PEDANTIC
+void g() {
+  if (true)
+    [[likely]] {} // expected-warning {{use of the 'likely' attribute is a C++20 extension}}
+  else
+    [[unlikely]] {} // expected-warning {{use of the 'unlikely' attribute is a C++20 extension}}
+}
+#else
+void a() {
+  if (true)
+    [[likely]]; // expected-warning {{conflicting attributes 'likely' are ignored}}
+  else
+    [[likely]]; // expected-note {{conflicting attribute is here}}
+}
+
+void b() {
+  if (true)
+    [[unlikely]]; // expected-warning {{conflicting attributes 'unlikely' are ignored}}
+  else
+    [[unlikely]]; // expected-note {{conflicting attribute is here}}
+}
+
+void c() {
+  if (true)
+    [[likely]];
+}
+
+void d() {
+  if (true)
+    [[unlikely]];
+}
+
+void g() {
+  if (true)
+    [[likely]] {}
+  else
+    [[unlikely]] {}
+}
+
+void h() {
+  if (true)
+    [[likely]] {}
+  else {
+  }
+}
+
+void i() {
+  if (true)
+    [[unlikely]] {}
+  else {
+  }
+}
+
+void j() {
+  if (true) {
+  } else
+    [[likely]] {}
+}
+
+void k() {
+  if (true) {
+  } else
+    [[likely]] {}
+}
+
+void l() {
+  if (true)
+    [[likely]] {}
+  else
+    [[unlikely]] if (false) [[likely]] {}
+}
+
+void m() {
+  [[likely]] int x = 42; // expected-error {{'likely' attribute cannot be applied to a declaration}}
+
+  if (x)
+    [[unlikely]] {}
+  if (x) {
+    [[unlikely]];
+  }
+  switch (x) {
+  case 1:
+    [[likely]] {}
+    break;
+    [[likely]] case 2 : case 3 : {}
+    break;
+  }
+
+  do {
+    [[unlikely]];
+  } while (x);
+  do
+    [[unlikely]] {}
+  while (x);
+  do { // expected-note {{to match this 'do'}}
+  }
+  [[unlikely]] while (x); // expected-error {{expected 'while' in do/while loop}}
+  for (;;)
+    [[unlikely]] {}
+  for (;;) {
+    [[unlikely]];
+  }
+  while (x)
+    [[unlikely]] {}
+  while (x) {
+    [[unlikely]];
+  }
+
+  switch (x)
+    [[unlikely]] {}
+
+  if (x)
+    goto lbl;
+
+  // FIXME: allow the attribute on the label
+  [[unlikely]] lbl : // expected-error {{'unlikely' attribute cannot be applied to a declaration}}
+                     [[likely]] x = x + 1;
+
+  [[likely]]++ x;
+}
+
+void n() [[likely]] // expected-error {{'likely' attribute cannot be applied to types}}
+{
+  try
+    [[likely]] {} // expected-error {{expected '{'}}
+  catch (...) [[likely]] { // expected-error {{expected expression}}
+  }
+}
+#endif
Index: clang/test/Sema/attr-likelihood.c
===================================================================
--- /dev/null
+++ clang/test/Sema/attr-likelihood.c
@@ -0,0 +1,51 @@
+// RUN: %clang_cc1 %s -fsyntax-only -fdouble-square-bracket-attributes -verify
+
+void g() {
+  if (1)
+    [[clang::likely]] {}
+}
+void m() {
+  [[clang::likely]] int x = 42; // expected-error {{'likely' attribute cannot be applied to a declaration}}
+
+  if (x)
+    [[clang::unlikely]] {}
+  if (x) {
+    [[clang::unlikely]];
+  }
+  switch (x) {
+  case 1:
+    [[clang::likely]] {}
+    break;
+    [[clang::likely]] case 2 : case 3 : {}
+    break;
+  }
+
+  do {
+    [[clang::unlikely]];
+  } while (x);
+  do
+    [[clang::unlikely]] {}
+  while (x);
+  do { // expected-note {{to match this 'do'}}
+  }
+  [[clang::unlikely]] while (x); // expected-error {{expected 'while' in do/while loop}}
+  for (;;)
+    [[clang::unlikely]] {}
+  for (;;) {
+    [[clang::unlikely]];
+  }
+  while (x)
+    [[clang::unlikely]] {}
+  while (x) {
+    [[clang::unlikely]];
+  }
+
+  if (x)
+    goto lbl;
+
+  // FIXME: allow the attribute on the label
+  [[clang::unlikely]] lbl : // expected-error {{'unlikely' attribute cannot be applied to a declaration}}
+  [[clang::likely]] x = x + 1;
+
+  [[clang::likely]]++ x;
+}
Index: clang/test/Preprocessor/has_attribute.cpp
===================================================================
--- clang/test/Preprocessor/has_attribute.cpp
+++ clang/test/Preprocessor/has_attribute.cpp
@@ -62,13 +62,13 @@
 // FIXME(201806L) CHECK: ensures: 0
 // FIXME(201806L) CHECK: expects: 0
 // CHECK: fallthrough: 201603L
-// FIXME(201803L) CHECK: likely: 0
+// FIXME(201803L) CHECK: likely: 2L
 // CHECK: maybe_unused: 201603L
 // ITANIUM: no_unique_address: 201803L
 // WINDOWS: no_unique_address: 0
 // CHECK: nodiscard: 201907L
 // CHECK: noreturn: 200809L
-// FIXME(201803L) CHECK: unlikely: 0
+// FIXME(201803L) CHECK: unlikely: 2L
 
 // Test for Microsoft __declspec attributes
 
Index: clang/test/CodeGenCXX/attr-likelihood-if-branch-weights.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGenCXX/attr-likelihood-if-branch-weights.cpp
@@ -0,0 +1,146 @@
+// RUN: %clang_cc1 -O1 -emit-llvm %s -o - -triple=x86_64-linux-gnu | FileCheck -DLIKELY=2000 -DUNLIKELY=1 %s
+// RUN: %clang_cc1 -O1 -emit-llvm %s -triple=x86_64-linux-gnu -mllvm -likely-branch-weight=99 -mllvm -unlikely-branch-weight=42 -o - | FileCheck -DLIKELY=99 -DUNLIKELY=42 %s
+
+extern volatile bool b;
+extern volatile int i;
+extern bool A();
+extern bool B();
+
+bool f() {
+  // CHECK-LABEL: define zeroext i1 @_Z1fv
+  // CHECK: br {{.*}} !prof !7
+  if (b)
+    [[likely]] {
+      return A();
+    }
+  return B();
+}
+
+bool g() {
+  // CHECK-LABEL: define zeroext i1 @_Z1gv
+  // CHECK: br {{.*}} !prof !8
+  if (b)
+    [[unlikely]] {
+      return A();
+    }
+
+  return B();
+}
+
+bool h() {
+  // CHECK-LABEL: define zeroext i1 @_Z1hv
+  // CHECK: br {{.*}} !prof !8
+  if (b)
+    [[unlikely]] return A();
+
+  return B();
+}
+
+void NullStmt() {
+  // CHECK-LABEL: define{{.*}}NullStmt
+  // CHECK: br {{.*}} !prof !8
+  if (b)
+    [[unlikely]];
+  else {
+    // Make sure the branches aren't optimized away.
+    b = true;
+  }
+}
+
+void IfStmt() {
+  // CHECK-LABEL: define{{.*}}IfStmt
+  // CHECK: br {{.*}} !prof !8
+  if (b)
+    [[unlikely]] if (B()) {}
+
+  // CHECK-NOT: br {{.*}} !prof
+  // CHECK: br {{.*}} !prof
+  if (b) {
+    if (B())
+      [[unlikely]] { b = false; }
+  }
+}
+
+void WhileStmt() {
+  // CHECK-LABEL: define{{.*}}WhileStmt
+  // CHECK: br {{.*}} !prof !8
+  if (b)
+    [[unlikely]] while (B()) {}
+
+  // CHECK-NOT: br {{.*}} %if.end{{.*}} !prof
+  if (b)
+    while (B())
+      [[unlikely]] { b = false; }
+}
+
+void DoStmt() {
+  // CHECK-LABEL: define{{.*}}DoStmt
+  // CHECK: br {{.*}} !prof !8
+  if (b)
+    [[unlikely]] do {}
+    while (B())
+      ;
+
+  // CHECK-NOT: br {{.*}} %if.end{{.*}} !prof
+  if (b)
+    do
+      [[unlikely]] {}
+    while (B());
+}
+
+void ForStmt() {
+  // CHECK-LABEL: define{{.*}}ForStmt
+  // CHECK: br {{.*}} !prof !8
+  if (b)
+    [[unlikely]] for (; B();) {}
+
+  // CHECK-NOT: br {{.*}} %if.end{{.*}} !prof
+  if (b)
+    for (; B();)
+      [[unlikely]] {}
+}
+
+void GotoStmt() {
+  // CHECK-LABEL: define{{.*}}GotoStmt
+  // CHECK: br {{.*}} !prof !8
+  if (b)
+    [[unlikely]] goto end;
+  else {
+    // Make sure the branches aren't optimized away.
+    b = true;
+  }
+end:;
+}
+
+void ReturnStmt() {
+  // CHECK-LABEL: define{{.*}}ReturnStmt
+  // CHECK: br {{.*}} !prof !8
+  if (b)
+    [[unlikely]] return;
+  else {
+    // Make sure the branches aren't optimized away.
+    b = true;
+  }
+}
+
+void SwitchStmt() {
+  // CHECK-LABEL: define{{.*}}SwitchStmt
+  // CHECK: br {{.*}} !prof !8
+  if (b)
+    [[unlikely]] switch (i) {}
+  else {
+    // Make sure the branches aren't optimized away.
+    b = true;
+  }
+  // CHECK-NOT: br {{.*}} %if.end{{.*}} !prof
+  if (b)
+    switch (i)
+      [[unlikely]] {}
+  else {
+    // Make sure the branches aren't optimized away.
+    b = true;
+  }
+}
+
+// CHECK: !7 = !{!"branch_weights", i32 [[UNLIKELY]], i32 [[LIKELY]]}
+// CHECK: !8 = !{!"branch_weights", i32 [[LIKELY]], i32 [[UNLIKELY]]}
Index: clang/test/AST/ast-dump-stmt.cpp
===================================================================
--- clang/test/AST/ast-dump-stmt.cpp
+++ clang/test/AST/ast-dump-stmt.cpp
@@ -126,6 +126,47 @@
   // CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} <col:19> 'bool' lvalue ParmVar 0x{{[^ ]*}} 'b' 'bool'
   // CHECK-NEXT: NullStmt
 
+  if (int i = 12; b) [[likely]]
+    ;
+  // CHECK: IfStmt 0x{{[^ ]*}} <line:[[@LINE-2]]:3, line:[[@LINE-1]]:5> has_init likely
+  // CHECK-NEXT: DeclStmt
+  // CHECK-NEXT: VarDecl 0x{{[^ ]*}} <col:7, col:15> col:11 i 'int' cinit
+  // CHECK-NEXT: IntegerLiteral 0x{{[^ ]*}} <col:15> 'int' 12
+  // CHECK-NEXT: ImplicitCastExpr
+  // CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} <col:19> 'bool' lvalue ParmVar 0x{{[^ ]*}} 'b' 'bool'
+  // CHECK-NEXT: AttributedStmt
+  // CHECK-NEXT: LikelyAttr
+  // CHECK-NEXT: NullStmt
+
+  if (int i = 12; b) [[unlikely]]
+    ;
+  // CHECK: IfStmt 0x{{[^ ]*}} <line:[[@LINE-2]]:3, line:[[@LINE-1]]:5> has_init unlikely
+  // CHECK-NEXT: DeclStmt
+  // CHECK-NEXT: VarDecl 0x{{[^ ]*}} <col:7, col:15> col:11 i 'int' cinit
+  // CHECK-NEXT: IntegerLiteral 0x{{[^ ]*}} <col:15> 'int' 12
+  // CHECK-NEXT: ImplicitCastExpr
+  // CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} <col:19> 'bool' lvalue ParmVar 0x{{[^ ]*}} 'b' 'bool'
+  // CHECK-NEXT: AttributedStmt
+  // CHECK-NEXT: UnlikelyAttr
+  // CHECK-NEXT: NullStmt
+
+  if (int i = 12; b) [[likely]]
+    ;
+  else [[likely]]
+    ;
+  // CHECK: IfStmt 0x{{[^ ]*}} <line:[[@LINE-4]]:3, line:[[@LINE-1]]:5> has_init has_else likelihood_conflict
+  // CHECK-NEXT: DeclStmt
+  // CHECK-NEXT: VarDecl 0x{{[^ ]*}} <col:7, col:15> col:11 i 'int' cinit
+  // CHECK-NEXT: IntegerLiteral 0x{{[^ ]*}} <col:15> 'int' 12
+  // CHECK-NEXT: ImplicitCastExpr
+  // CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} <col:19> 'bool' lvalue ParmVar 0x{{[^ ]*}} 'b' 'bool'
+  // CHECK-NEXT: AttributedStmt
+  // CHECK-NEXT: LikelyAttr
+  // CHECK-NEXT: NullStmt
+  // CHECK-NEXT: AttributedStmt
+  // CHECK-NEXT: LikelyAttr
+  // CHECK-NEXT: NullStmt
+
   if constexpr (sizeof(b) == 1)
     ;
   // CHECK: IfStmt 0x{{[^ ]*}} <line:[[@LINE-2]]:3, line:[[@LINE-1]]:5>
Index: clang/test/AST/ast-dump-if-json.cpp
===================================================================
--- clang/test/AST/ast-dump-if-json.cpp
+++ clang/test/AST/ast-dump-if-json.cpp
@@ -24,6 +24,16 @@
 
   if (int i = 12; i)
     ;
+
+  if (val) [[likely]]
+    ;
+
+  if (val) [[likely]]
+    ;
+  if (val) [[unlikely]]
+    ;
+  else [[unlikely]]
+    ;
 }
 
 // NOTE: CHECK lines have been autogenerated by gen_ast_dump_json_test.py
@@ -1004,3 +1014,505 @@
 // CHECK-NEXT:   }
 // CHECK-NEXT:  ]
 // CHECK-NEXT: }
+
+
+// CHECK:  "kind": "IfStmt",
+// CHECK-NEXT:  "range": {
+// CHECK-NEXT:   "begin": {
+// CHECK-NEXT:    "offset": 298,
+// CHECK-NEXT:    "line": 28,
+// CHECK-NEXT:    "col": 3,
+// CHECK-NEXT:    "tokLen": 2
+// CHECK-NEXT:   },
+// CHECK-NEXT:   "end": {
+// CHECK-NEXT:    "offset": 322,
+// CHECK-NEXT:    "line": 29,
+// CHECK-NEXT:    "col": 5,
+// CHECK-NEXT:    "tokLen": 1
+// CHECK-NEXT:   }
+// CHECK-NEXT:  },
+// CHECK-NEXT:  "thenLikelihood": "likely",
+// CHECK-NEXT:  "inner": [
+// CHECK-NEXT:   {
+// CHECK-NEXT:    "id": "0x{{.*}}",
+// CHECK-NEXT:    "kind": "ImplicitCastExpr",
+// CHECK-NEXT:    "range": {
+// CHECK-NEXT:     "begin": {
+// CHECK-NEXT:      "offset": 302,
+// CHECK-NEXT:      "line": 28,
+// CHECK-NEXT:      "col": 7,
+// CHECK-NEXT:      "tokLen": 3
+// CHECK-NEXT:     },
+// CHECK-NEXT:     "end": {
+// CHECK-NEXT:      "offset": 302,
+// CHECK-NEXT:      "col": 7,
+// CHECK-NEXT:      "tokLen": 3
+// CHECK-NEXT:     }
+// CHECK-NEXT:    },
+// CHECK-NEXT:    "type": {
+// CHECK-NEXT:     "qualType": "bool"
+// CHECK-NEXT:    },
+// CHECK-NEXT:    "valueCategory": "rvalue",
+// CHECK-NEXT:    "castKind": "IntegralToBoolean",
+// CHECK-NEXT:    "inner": [
+// CHECK-NEXT:     {
+// CHECK-NEXT:      "id": "0x{{.*}}",
+// CHECK-NEXT:      "kind": "ImplicitCastExpr",
+// CHECK-NEXT:      "range": {
+// CHECK-NEXT:       "begin": {
+// CHECK-NEXT:        "offset": 302,
+// CHECK-NEXT:        "col": 7,
+// CHECK-NEXT:        "tokLen": 3
+// CHECK-NEXT:       },
+// CHECK-NEXT:       "end": {
+// CHECK-NEXT:        "offset": 302,
+// CHECK-NEXT:        "col": 7,
+// CHECK-NEXT:        "tokLen": 3
+// CHECK-NEXT:       }
+// CHECK-NEXT:      },
+// CHECK-NEXT:      "type": {
+// CHECK-NEXT:       "qualType": "int"
+// CHECK-NEXT:      },
+// CHECK-NEXT:      "valueCategory": "rvalue",
+// CHECK-NEXT:      "castKind": "LValueToRValue",
+// CHECK-NEXT:      "inner": [
+// CHECK-NEXT:       {
+// CHECK-NEXT:        "id": "0x{{.*}}",
+// CHECK-NEXT:        "kind": "DeclRefExpr",
+// CHECK-NEXT:        "range": {
+// CHECK-NEXT:         "begin": {
+// CHECK-NEXT:          "offset": 302,
+// CHECK-NEXT:          "col": 7,
+// CHECK-NEXT:          "tokLen": 3
+// CHECK-NEXT:         },
+// CHECK-NEXT:         "end": {
+// CHECK-NEXT:          "offset": 302,
+// CHECK-NEXT:          "col": 7,
+// CHECK-NEXT:          "tokLen": 3
+// CHECK-NEXT:         }
+// CHECK-NEXT:        },
+// CHECK-NEXT:        "type": {
+// CHECK-NEXT:         "qualType": "int"
+// CHECK-NEXT:        },
+// CHECK-NEXT:        "valueCategory": "lvalue",
+// CHECK-NEXT:        "referencedDecl": {
+// CHECK-NEXT:         "id": "0x{{.*}}",
+// CHECK-NEXT:         "kind": "ParmVarDecl",
+// CHECK-NEXT:         "name": "val",
+// CHECK-NEXT:         "type": {
+// CHECK-NEXT:          "qualType": "int"
+// CHECK-NEXT:         }
+// CHECK-NEXT:        }
+// CHECK-NEXT:       }
+// CHECK-NEXT:      ]
+// CHECK-NEXT:     }
+// CHECK-NEXT:    ]
+// CHECK-NEXT:   },
+// CHECK-NEXT:   {
+// CHECK-NEXT:    "id": "0x{{.*}}",
+// CHECK-NEXT:    "kind": "AttributedStmt",
+// CHECK-NEXT:    "range": {
+// CHECK-NEXT:     "begin": {
+// CHECK-NEXT:      "offset": 307,
+// CHECK-NEXT:      "col": 12,
+// CHECK-NEXT:      "tokLen": 1
+// CHECK-NEXT:     },
+// CHECK-NEXT:     "end": {
+// CHECK-NEXT:      "offset": 322,
+// CHECK-NEXT:      "line": 29,
+// CHECK-NEXT:      "col": 5,
+// CHECK-NEXT:      "tokLen": 1
+// CHECK-NEXT:     }
+// CHECK-NEXT:    },
+// CHECK-NEXT:    "inner": [
+// CHECK-NEXT:     {
+// CHECK-NEXT:      "id": "0x{{.*}}",
+// CHECK-NEXT:      "kind": "LikelyAttr",
+// CHECK-NEXT:      "range": {
+// CHECK-NEXT:       "begin": {
+// CHECK-NEXT:        "offset": 309,
+// CHECK-NEXT:        "line": 28,
+// CHECK-NEXT:        "col": 14,
+// CHECK-NEXT:        "tokLen": 6
+// CHECK-NEXT:       },
+// CHECK-NEXT:       "end": {
+// CHECK-NEXT:        "offset": 309,
+// CHECK-NEXT:        "col": 14,
+// CHECK-NEXT:        "tokLen": 6
+// CHECK-NEXT:       }
+// CHECK-NEXT:      }
+// CHECK-NEXT:     },
+// CHECK-NEXT:     {
+// CHECK-NEXT:      "id": "0x{{.*}}",
+// CHECK-NEXT:      "kind": "NullStmt",
+// CHECK-NEXT:      "range": {
+// CHECK-NEXT:       "begin": {
+// CHECK-NEXT:        "offset": 322,
+// CHECK-NEXT:        "line": 29,
+// CHECK-NEXT:        "col": 5,
+// CHECK-NEXT:        "tokLen": 1
+// CHECK-NEXT:       },
+// CHECK-NEXT:       "end": {
+// CHECK-NEXT:        "offset": 322,
+// CHECK-NEXT:        "col": 5,
+// CHECK-NEXT:        "tokLen": 1
+// CHECK-NEXT:       }
+// CHECK-NEXT:      }
+// CHECK-NEXT:     }
+// CHECK-NEXT:    ]
+// CHECK-NEXT:   }
+// CHECK-NEXT:  ]
+// CHECK-NEXT: }
+
+
+// CHECK:  "kind": "IfStmt",
+// CHECK-NEXT:  "range": {
+// CHECK-NEXT:   "begin": {
+// CHECK-NEXT:    "offset": 327,
+// CHECK-NEXT:    "line": 31,
+// CHECK-NEXT:    "col": 3,
+// CHECK-NEXT:    "tokLen": 2
+// CHECK-NEXT:   },
+// CHECK-NEXT:   "end": {
+// CHECK-NEXT:    "offset": 351,
+// CHECK-NEXT:    "line": 32,
+// CHECK-NEXT:    "col": 5,
+// CHECK-NEXT:    "tokLen": 1
+// CHECK-NEXT:   }
+// CHECK-NEXT:  },
+// CHECK-NEXT:  "thenLikelihood": "likely",
+// CHECK-NEXT:  "inner": [
+// CHECK-NEXT:   {
+// CHECK-NEXT:    "id": "0x{{.*}}",
+// CHECK-NEXT:    "kind": "ImplicitCastExpr",
+// CHECK-NEXT:    "range": {
+// CHECK-NEXT:     "begin": {
+// CHECK-NEXT:      "offset": 331,
+// CHECK-NEXT:      "line": 31,
+// CHECK-NEXT:      "col": 7,
+// CHECK-NEXT:      "tokLen": 3
+// CHECK-NEXT:     },
+// CHECK-NEXT:     "end": {
+// CHECK-NEXT:      "offset": 331,
+// CHECK-NEXT:      "col": 7,
+// CHECK-NEXT:      "tokLen": 3
+// CHECK-NEXT:     }
+// CHECK-NEXT:    },
+// CHECK-NEXT:    "type": {
+// CHECK-NEXT:     "qualType": "bool"
+// CHECK-NEXT:    },
+// CHECK-NEXT:    "valueCategory": "rvalue",
+// CHECK-NEXT:    "castKind": "IntegralToBoolean",
+// CHECK-NEXT:    "inner": [
+// CHECK-NEXT:     {
+// CHECK-NEXT:      "id": "0x{{.*}}",
+// CHECK-NEXT:      "kind": "ImplicitCastExpr",
+// CHECK-NEXT:      "range": {
+// CHECK-NEXT:       "begin": {
+// CHECK-NEXT:        "offset": 331,
+// CHECK-NEXT:        "col": 7,
+// CHECK-NEXT:        "tokLen": 3
+// CHECK-NEXT:       },
+// CHECK-NEXT:       "end": {
+// CHECK-NEXT:        "offset": 331,
+// CHECK-NEXT:        "col": 7,
+// CHECK-NEXT:        "tokLen": 3
+// CHECK-NEXT:       }
+// CHECK-NEXT:      },
+// CHECK-NEXT:      "type": {
+// CHECK-NEXT:       "qualType": "int"
+// CHECK-NEXT:      },
+// CHECK-NEXT:      "valueCategory": "rvalue",
+// CHECK-NEXT:      "castKind": "LValueToRValue",
+// CHECK-NEXT:      "inner": [
+// CHECK-NEXT:       {
+// CHECK-NEXT:        "id": "0x{{.*}}",
+// CHECK-NEXT:        "kind": "DeclRefExpr",
+// CHECK-NEXT:        "range": {
+// CHECK-NEXT:         "begin": {
+// CHECK-NEXT:          "offset": 331,
+// CHECK-NEXT:          "col": 7,
+// CHECK-NEXT:          "tokLen": 3
+// CHECK-NEXT:         },
+// CHECK-NEXT:         "end": {
+// CHECK-NEXT:          "offset": 331,
+// CHECK-NEXT:          "col": 7,
+// CHECK-NEXT:          "tokLen": 3
+// CHECK-NEXT:         }
+// CHECK-NEXT:        },
+// CHECK-NEXT:        "type": {
+// CHECK-NEXT:         "qualType": "int"
+// CHECK-NEXT:        },
+// CHECK-NEXT:        "valueCategory": "lvalue",
+// CHECK-NEXT:        "referencedDecl": {
+// CHECK-NEXT:         "id": "0x{{.*}}",
+// CHECK-NEXT:         "kind": "ParmVarDecl",
+// CHECK-NEXT:         "name": "val",
+// CHECK-NEXT:         "type": {
+// CHECK-NEXT:          "qualType": "int"
+// CHECK-NEXT:         }
+// CHECK-NEXT:        }
+// CHECK-NEXT:       }
+// CHECK-NEXT:      ]
+// CHECK-NEXT:     }
+// CHECK-NEXT:    ]
+// CHECK-NEXT:   },
+// CHECK-NEXT:   {
+// CHECK-NEXT:    "id": "0x{{.*}}",
+// CHECK-NEXT:    "kind": "AttributedStmt",
+// CHECK-NEXT:    "range": {
+// CHECK-NEXT:     "begin": {
+// CHECK-NEXT:      "offset": 336,
+// CHECK-NEXT:      "col": 12,
+// CHECK-NEXT:      "tokLen": 1
+// CHECK-NEXT:     },
+// CHECK-NEXT:     "end": {
+// CHECK-NEXT:      "offset": 351,
+// CHECK-NEXT:      "line": 32,
+// CHECK-NEXT:      "col": 5,
+// CHECK-NEXT:      "tokLen": 1
+// CHECK-NEXT:     }
+// CHECK-NEXT:    },
+// CHECK-NEXT:    "inner": [
+// CHECK-NEXT:     {
+// CHECK-NEXT:      "id": "0x{{.*}}",
+// CHECK-NEXT:      "kind": "LikelyAttr",
+// CHECK-NEXT:      "range": {
+// CHECK-NEXT:       "begin": {
+// CHECK-NEXT:        "offset": 338,
+// CHECK-NEXT:        "line": 31,
+// CHECK-NEXT:        "col": 14,
+// CHECK-NEXT:        "tokLen": 6
+// CHECK-NEXT:       },
+// CHECK-NEXT:       "end": {
+// CHECK-NEXT:        "offset": 338,
+// CHECK-NEXT:        "col": 14,
+// CHECK-NEXT:        "tokLen": 6
+// CHECK-NEXT:       }
+// CHECK-NEXT:      }
+// CHECK-NEXT:     },
+// CHECK-NEXT:     {
+// CHECK-NEXT:      "id": "0x{{.*}}",
+// CHECK-NEXT:      "kind": "NullStmt",
+// CHECK-NEXT:      "range": {
+// CHECK-NEXT:       "begin": {
+// CHECK-NEXT:        "offset": 351,
+// CHECK-NEXT:        "line": 32,
+// CHECK-NEXT:        "col": 5,
+// CHECK-NEXT:        "tokLen": 1
+// CHECK-NEXT:       },
+// CHECK-NEXT:       "end": {
+// CHECK-NEXT:        "offset": 351,
+// CHECK-NEXT:        "col": 5,
+// CHECK-NEXT:        "tokLen": 1
+// CHECK-NEXT:       }
+// CHECK-NEXT:      }
+// CHECK-NEXT:     }
+// CHECK-NEXT:    ]
+// CHECK-NEXT:   }
+// CHECK-NEXT:  ]
+// CHECK-NEXT: }
+
+
+// CHECK:  "kind": "IfStmt",
+// CHECK-NEXT:  "range": {
+// CHECK-NEXT:   "begin": {
+// CHECK-NEXT:    "offset": 355,
+// CHECK-NEXT:    "line": 33,
+// CHECK-NEXT:    "col": 3,
+// CHECK-NEXT:    "tokLen": 2
+// CHECK-NEXT:   },
+// CHECK-NEXT:   "end": {
+// CHECK-NEXT:    "offset": 407,
+// CHECK-NEXT:    "line": 36,
+// CHECK-NEXT:    "col": 5,
+// CHECK-NEXT:    "tokLen": 1
+// CHECK-NEXT:   }
+// CHECK-NEXT:  },
+// CHECK-NEXT:  "hasElse": true,
+// CHECK-NEXT:  "thenLikelihood": "conflict",
+// CHECK-NEXT:  "inner": [
+// CHECK-NEXT:   {
+// CHECK-NEXT:    "id": "0x{{.*}}",
+// CHECK-NEXT:    "kind": "ImplicitCastExpr",
+// CHECK-NEXT:    "range": {
+// CHECK-NEXT:     "begin": {
+// CHECK-NEXT:      "offset": 359,
+// CHECK-NEXT:      "line": 33,
+// CHECK-NEXT:      "col": 7,
+// CHECK-NEXT:      "tokLen": 3
+// CHECK-NEXT:     },
+// CHECK-NEXT:     "end": {
+// CHECK-NEXT:      "offset": 359,
+// CHECK-NEXT:      "col": 7,
+// CHECK-NEXT:      "tokLen": 3
+// CHECK-NEXT:     }
+// CHECK-NEXT:    },
+// CHECK-NEXT:    "type": {
+// CHECK-NEXT:     "qualType": "bool"
+// CHECK-NEXT:    },
+// CHECK-NEXT:    "valueCategory": "rvalue",
+// CHECK-NEXT:    "castKind": "IntegralToBoolean",
+// CHECK-NEXT:    "inner": [
+// CHECK-NEXT:     {
+// CHECK-NEXT:      "id": "0x{{.*}}",
+// CHECK-NEXT:      "kind": "ImplicitCastExpr",
+// CHECK-NEXT:      "range": {
+// CHECK-NEXT:       "begin": {
+// CHECK-NEXT:        "offset": 359,
+// CHECK-NEXT:        "col": 7,
+// CHECK-NEXT:        "tokLen": 3
+// CHECK-NEXT:       },
+// CHECK-NEXT:       "end": {
+// CHECK-NEXT:        "offset": 359,
+// CHECK-NEXT:        "col": 7,
+// CHECK-NEXT:        "tokLen": 3
+// CHECK-NEXT:       }
+// CHECK-NEXT:      },
+// CHECK-NEXT:      "type": {
+// CHECK-NEXT:       "qualType": "int"
+// CHECK-NEXT:      },
+// CHECK-NEXT:      "valueCategory": "rvalue",
+// CHECK-NEXT:      "castKind": "LValueToRValue",
+// CHECK-NEXT:      "inner": [
+// CHECK-NEXT:       {
+// CHECK-NEXT:        "id": "0x{{.*}}",
+// CHECK-NEXT:        "kind": "DeclRefExpr",
+// CHECK-NEXT:        "range": {
+// CHECK-NEXT:         "begin": {
+// CHECK-NEXT:          "offset": 359,
+// CHECK-NEXT:          "col": 7,
+// CHECK-NEXT:          "tokLen": 3
+// CHECK-NEXT:         },
+// CHECK-NEXT:         "end": {
+// CHECK-NEXT:          "offset": 359,
+// CHECK-NEXT:          "col": 7,
+// CHECK-NEXT:          "tokLen": 3
+// CHECK-NEXT:         }
+// CHECK-NEXT:        },
+// CHECK-NEXT:        "type": {
+// CHECK-NEXT:         "qualType": "int"
+// CHECK-NEXT:        },
+// CHECK-NEXT:        "valueCategory": "lvalue",
+// CHECK-NEXT:        "referencedDecl": {
+// CHECK-NEXT:         "id": "0x{{.*}}",
+// CHECK-NEXT:         "kind": "ParmVarDecl",
+// CHECK-NEXT:         "name": "val",
+// CHECK-NEXT:         "type": {
+// CHECK-NEXT:          "qualType": "int"
+// CHECK-NEXT:         }
+// CHECK-NEXT:        }
+// CHECK-NEXT:       }
+// CHECK-NEXT:      ]
+// CHECK-NEXT:     }
+// CHECK-NEXT:    ]
+// CHECK-NEXT:   },
+// CHECK-NEXT:   {
+// CHECK-NEXT:    "id": "0x{{.*}}",
+// CHECK-NEXT:    "kind": "AttributedStmt",
+// CHECK-NEXT:    "range": {
+// CHECK-NEXT:     "begin": {
+// CHECK-NEXT:      "offset": 364,
+// CHECK-NEXT:      "col": 12,
+// CHECK-NEXT:      "tokLen": 1
+// CHECK-NEXT:     },
+// CHECK-NEXT:     "end": {
+// CHECK-NEXT:      "offset": 381,
+// CHECK-NEXT:      "line": 34,
+// CHECK-NEXT:      "col": 5,
+// CHECK-NEXT:      "tokLen": 1
+// CHECK-NEXT:     }
+// CHECK-NEXT:    },
+// CHECK-NEXT:    "inner": [
+// CHECK-NEXT:     {
+// CHECK-NEXT:      "id": "0x{{.*}}",
+// CHECK-NEXT:      "kind": "UnlikelyAttr",
+// CHECK-NEXT:      "range": {
+// CHECK-NEXT:       "begin": {
+// CHECK-NEXT:        "offset": 366,
+// CHECK-NEXT:        "line": 33,
+// CHECK-NEXT:        "col": 14,
+// CHECK-NEXT:        "tokLen": 8
+// CHECK-NEXT:       },
+// CHECK-NEXT:       "end": {
+// CHECK-NEXT:        "offset": 366,
+// CHECK-NEXT:        "col": 14,
+// CHECK-NEXT:        "tokLen": 8
+// CHECK-NEXT:       }
+// CHECK-NEXT:      }
+// CHECK-NEXT:     },
+// CHECK-NEXT:     {
+// CHECK-NEXT:      "id": "0x{{.*}}",
+// CHECK-NEXT:      "kind": "NullStmt",
+// CHECK-NEXT:      "range": {
+// CHECK-NEXT:       "begin": {
+// CHECK-NEXT:        "offset": 381,
+// CHECK-NEXT:        "line": 34,
+// CHECK-NEXT:        "col": 5,
+// CHECK-NEXT:        "tokLen": 1
+// CHECK-NEXT:       },
+// CHECK-NEXT:       "end": {
+// CHECK-NEXT:        "offset": 381,
+// CHECK-NEXT:        "col": 5,
+// CHECK-NEXT:        "tokLen": 1
+// CHECK-NEXT:       }
+// CHECK-NEXT:      }
+// CHECK-NEXT:     }
+// CHECK-NEXT:    ]
+// CHECK-NEXT:   },
+// CHECK-NEXT:   {
+// CHECK-NEXT:    "id": "0x{{.*}}",
+// CHECK-NEXT:    "kind": "AttributedStmt",
+// CHECK-NEXT:    "range": {
+// CHECK-NEXT:     "begin": {
+// CHECK-NEXT:      "offset": 390,
+// CHECK-NEXT:      "line": 35,
+// CHECK-NEXT:      "col": 8,
+// CHECK-NEXT:      "tokLen": 1
+// CHECK-NEXT:     },
+// CHECK-NEXT:     "end": {
+// CHECK-NEXT:      "offset": 407,
+// CHECK-NEXT:      "line": 36,
+// CHECK-NEXT:      "col": 5,
+// CHECK-NEXT:      "tokLen": 1
+// CHECK-NEXT:     }
+// CHECK-NEXT:    },
+// CHECK-NEXT:    "inner": [
+// CHECK-NEXT:     {
+// CHECK-NEXT:      "id": "0x{{.*}}",
+// CHECK-NEXT:      "kind": "UnlikelyAttr",
+// CHECK-NEXT:      "range": {
+// CHECK-NEXT:       "begin": {
+// CHECK-NEXT:        "offset": 392,
+// CHECK-NEXT:        "line": 35,
+// CHECK-NEXT:        "col": 10,
+// CHECK-NEXT:        "tokLen": 8
+// CHECK-NEXT:       },
+// CHECK-NEXT:       "end": {
+// CHECK-NEXT:        "offset": 392,
+// CHECK-NEXT:        "col": 10,
+// CHECK-NEXT:        "tokLen": 8
+// CHECK-NEXT:       }
+// CHECK-NEXT:      }
+// CHECK-NEXT:     },
+// CHECK-NEXT:     {
+// CHECK-NEXT:      "id": "0x{{.*}}",
+// CHECK-NEXT:      "kind": "NullStmt",
+// CHECK-NEXT:      "range": {
+// CHECK-NEXT:       "begin": {
+// CHECK-NEXT:        "offset": 407,
+// CHECK-NEXT:        "line": 36,
+// CHECK-NEXT:        "col": 5,
+// CHECK-NEXT:        "tokLen": 1
+// CHECK-NEXT:       },
+// CHECK-NEXT:       "end": {
+// CHECK-NEXT:        "offset": 407,
+// CHECK-NEXT:        "col": 5,
+// CHECK-NEXT:        "tokLen": 1
+// CHECK-NEXT:       }
+// CHECK-NEXT:      }
+// CHECK-NEXT:     }
+// CHECK-NEXT:    ]
+// CHECK-NEXT:   }
+// CHECK-NEXT:  ]
+// CHECK-NEXT: }
Index: clang/lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- clang/lib/Serialization/ASTWriterStmt.cpp
+++ clang/lib/Serialization/ASTWriterStmt.cpp
@@ -141,6 +141,7 @@
   Record.push_back(HasElse);
   Record.push_back(HasVar);
   Record.push_back(HasInit);
+  Record.push_back(S->getThenLikelihood());
 
   Record.AddStmt(S->getCond());
   Record.AddStmt(S->getThen());
Index: clang/lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- clang/lib/Serialization/ASTReaderStmt.cpp
+++ clang/lib/Serialization/ASTReaderStmt.cpp
@@ -215,6 +215,7 @@
   bool HasElse = Record.readInt();
   bool HasVar = Record.readInt();
   bool HasInit = Record.readInt();
+  S->setThenLikelihood(static_cast<Stmt::Likelihood>(Record.readInt()));
 
   S->setCond(Record.readSubExpr());
   S->setThen(Record.readSubStmt());
Index: clang/lib/Sema/SemaStmtAttr.cpp
===================================================================
--- clang/lib/Sema/SemaStmtAttr.cpp
+++ clang/lib/Sema/SemaStmtAttr.cpp
@@ -210,6 +210,24 @@
   return ::new (S.Context) NoMergeAttr(S.Context, A);
 }
 
+static Attr *handleLikely(Sema &S, Stmt *St, const ParsedAttr &A,
+                          SourceRange Range) {
+
+  if (!S.getLangOpts().CPlusPlus20 && A.isCXX11Attribute() && !A.getScopeName())
+    S.Diag(A.getLoc(), diag::ext_cxx20_attr) << A << Range;
+
+  return ::new (S.Context) LikelyAttr(S.Context, A);
+}
+
+static Attr *handleUnlikely(Sema &S, Stmt *St, const ParsedAttr &A,
+                            SourceRange Range) {
+
+  if (!S.getLangOpts().CPlusPlus20 && A.isCXX11Attribute() && !A.getScopeName())
+    S.Diag(A.getLoc(), diag::ext_cxx20_attr) << A << Range;
+
+  return ::new (S.Context) UnlikelyAttr(S.Context, A);
+}
+
 static void
 CheckForIncompatibleAttributes(Sema &S,
                                const SmallVectorImpl<const Attr *> &Attrs) {
@@ -315,6 +333,32 @@
           << CategoryState.NumericAttr->getDiagnosticName(Policy);
     }
   }
+
+  // C++20 [dcl.attr.likelihood]p1 The attribute-token likely shall not appear
+  // in an attribute-specifier-seq that contains the attribute-token unlikely.
+  const LikelyAttr *Likely = nullptr;
+  const UnlikelyAttr *Unlikely = nullptr;
+  for (const auto *I : Attrs) {
+    if (const auto *Attr = dyn_cast<LikelyAttr>(I)) {
+      if (Unlikely) {
+        S.Diag(Attr->getLocation(), diag::err_attributes_are_not_compatible)
+            << Attr << Unlikely << Attr->getRange();
+        S.Diag(Unlikely->getLocation(), diag::note_conflicting_attribute)
+            << Unlikely->getRange();
+        return;
+      }
+      Likely = Attr;
+    } else if (const auto *Attr = dyn_cast<UnlikelyAttr>(I)) {
+      if (Likely) {
+        S.Diag(Attr->getLocation(), diag::err_attributes_are_not_compatible)
+            << Attr << Likely << Attr->getRange();
+        S.Diag(Likely->getLocation(), diag::note_conflicting_attribute)
+            << Likely->getRange();
+        return;
+      }
+      Unlikely = Attr;
+    }
+  }
 }
 
 static Attr *handleOpenCLUnrollHint(Sema &S, Stmt *St, const ParsedAttr &A,
@@ -377,6 +421,10 @@
     return handleSuppressAttr(S, St, A, Range);
   case ParsedAttr::AT_NoMerge:
     return handleNoMergeAttr(S, St, A, Range);
+  case ParsedAttr::AT_Likely:
+    return handleLikely(S, St, A, Range);
+  case ParsedAttr::AT_Unlikely:
+    return handleUnlikely(S, St, A, Range);
   default:
     // if we're here, then we parsed a known attribute, but didn't recognize
     // it as a statement attribute => it is declaration attribute
Index: clang/lib/Sema/SemaStmt.cpp
===================================================================
--- clang/lib/Sema/SemaStmt.cpp
+++ clang/lib/Sema/SemaStmt.cpp
@@ -574,6 +574,55 @@
 };
 }
 
+static std::pair<Stmt::Likelihood, const Attr *>
+getLikelihood(const Stmt *Stmt) {
+  if (const auto *AS = dyn_cast<AttributedStmt>(Stmt))
+    for (const auto *A : AS->getAttrs()) {
+      if (isa<LikelyAttr>(A))
+        return std::make_pair(Stmt::LH_Likely, A);
+
+      if (isa<UnlikelyAttr>(A))
+        return std::make_pair(Stmt::LH_Unlikely, A);
+    }
+
+  return std::make_pair(Stmt::LH_None, nullptr);
+}
+
+static Stmt::Likelihood calculateLikelihood(Sema &S, const Stmt *Then,
+                                            const Stmt *Else) {
+  assert(Then && "IfStmt without a ThenStmt");
+
+  std::pair<Stmt::Likelihood, const Attr *> ThenLH = getLikelihood(Then);
+  if (!Else)
+    return ThenLH.first;
+
+  std::pair<Stmt::Likelihood, const Attr *> ElseLH = getLikelihood(Else);
+  if (ThenLH.first == Stmt::LH_None && ElseLH.first == Stmt::LH_None)
+    return Stmt::LH_None;
+
+  // The returned state is never LH_Conflict, now determine whether there's a
+  // conflict. A conflict occurs if both branches contain the same attribute.
+  // The condition where both are LH_None can't happen here.
+  if (ThenLH.first == ElseLH.first) {
+    S.Diag(ThenLH.second->getLocation(),
+           diag::warn_attributes_likelihood_ifstmt_conflict)
+        << ThenLH.second << ThenLH.second->getRange();
+    S.Diag(ElseLH.second->getLocation(), diag::note_conflicting_attribute)
+        << ElseLH.second << ElseLH.second->getRange();
+
+    return Stmt::LH_Conflict;
+  }
+  if (ThenLH.first != Stmt::LH_None)
+    return ThenLH.first;
+
+  // The function returs the likelihood of Then so invert the likelihood of
+  // Else.
+  if (ElseLH.first == Stmt::LH_Likely)
+    return Stmt::LH_Unlikely;
+
+  return Stmt::LH_Likely;
+}
+
 StmtResult Sema::ActOnIfStmt(SourceLocation IfLoc, bool IsConstexpr,
                              SourceLocation LParenLoc, Stmt *InitStmt,
                              ConditionResult Cond, SourceLocation RParenLoc,
@@ -597,15 +646,16 @@
     DiagnoseEmptyStmtBody(CondExpr->getEndLoc(), thenStmt,
                           diag::warn_empty_if_body);
 
+  Stmt::Likelihood LH = calculateLikelihood(*this, thenStmt, elseStmt);
   return BuildIfStmt(IfLoc, IsConstexpr, LParenLoc, InitStmt, Cond, RParenLoc,
-                     thenStmt, ElseLoc, elseStmt);
+                     thenStmt, ElseLoc, elseStmt, LH);
 }
 
 StmtResult Sema::BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr,
                              SourceLocation LParenLoc, Stmt *InitStmt,
                              ConditionResult Cond, SourceLocation RParenLoc,
                              Stmt *thenStmt, SourceLocation ElseLoc,
-                             Stmt *elseStmt) {
+                             Stmt *elseStmt, Stmt::Likelihood LH) {
   if (Cond.isInvalid())
     return StmtError();
 
@@ -614,7 +664,7 @@
 
   return IfStmt::Create(Context, IfLoc, IsConstexpr, InitStmt, Cond.get().first,
                         Cond.get().second, LParenLoc, RParenLoc, thenStmt,
-                        ElseLoc, elseStmt);
+                        ElseLoc, elseStmt, LH);
 }
 
 namespace {
Index: clang/lib/Parse/ParseDeclCXX.cpp
===================================================================
--- clang/lib/Parse/ParseDeclCXX.cpp
+++ clang/lib/Parse/ParseDeclCXX.cpp
@@ -4018,6 +4018,8 @@
   case ParsedAttr::AT_FallThrough:
   case ParsedAttr::AT_CXX11NoReturn:
   case ParsedAttr::AT_NoUniqueAddress:
+  case ParsedAttr::AT_Likely:
+  case ParsedAttr::AT_Unlikely:
     return true;
   case ParsedAttr::AT_WarnUnusedResult:
     return !ScopeName && AttrName->getName().equals("nodiscard");
Index: clang/lib/CodeGen/CodeGenFunction.h
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.h
+++ clang/lib/CodeGen/CodeGenFunction.h
@@ -4360,7 +4360,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,
+                            llvm::MDNode *Weights = nullptr);
 
   /// 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
@@ -1462,16 +1462,15 @@
   return true;
 }
 
-
-
 /// EmitBranchOnBoolExpr - Emit a branch on a boolean condition (e.g. for an if
 /// statement) to the specified blocks.  Based on the condition, this might try
 /// to simplify the codegen of the conditional based on the branch.
-///
+/// \param Weights The weights determined by the likelihood attributes.
 void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond,
                                            llvm::BasicBlock *TrueBlock,
                                            llvm::BasicBlock *FalseBlock,
-                                           uint64_t TrueCount) {
+                                           uint64_t TrueCount,
+                                           llvm::MDNode *Weights) {
   Cond = Cond->IgnoreParens();
 
   if (const BinaryOperator *CondBOp = dyn_cast<BinaryOperator>(Cond)) {
@@ -1486,7 +1485,7 @@
         // br(1 && X) -> br(X).
         incrementProfileCounter(CondBOp);
         return EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock,
-                                    TrueCount);
+                                    TrueCount, Weights);
       }
 
       // If we have "X && 1", simplify the code to use an uncond branch.
@@ -1495,7 +1494,7 @@
           ConstantBool) {
         // br(X && 1) -> br(X).
         return EmitBranchOnBoolExpr(CondBOp->getLHS(), TrueBlock, FalseBlock,
-                                    TrueCount);
+                                    TrueCount, Weights);
       }
 
       // Emit the LHS as a conditional.  If the LHS conditional is false, we
@@ -1508,7 +1507,8 @@
       ConditionalEvaluation eval(*this);
       {
         ApplyDebugLocation DL(*this, Cond);
-        EmitBranchOnBoolExpr(CondBOp->getLHS(), LHSTrue, FalseBlock, RHSCount);
+        EmitBranchOnBoolExpr(CondBOp->getLHS(), LHSTrue, FalseBlock, RHSCount,
+                             Weights);
         EmitBlock(LHSTrue);
       }
 
@@ -1517,7 +1517,8 @@
 
       // Any temporaries created here are conditional.
       eval.begin(*this);
-      EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock, TrueCount);
+      EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock, TrueCount,
+                           Weights);
       eval.end(*this);
 
       return;
@@ -1532,7 +1533,7 @@
         // br(0 || X) -> br(X).
         incrementProfileCounter(CondBOp);
         return EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock,
-                                    TrueCount);
+                                    TrueCount, Weights);
       }
 
       // If we have "X || 0", simplify the code to use an uncond branch.
@@ -1541,7 +1542,7 @@
           !ConstantBool) {
         // br(X || 0) -> br(X).
         return EmitBranchOnBoolExpr(CondBOp->getLHS(), TrueBlock, FalseBlock,
-                                    TrueCount);
+                                    TrueCount, Weights);
       }
 
       // Emit the LHS as a conditional.  If the LHS conditional is true, we
@@ -1557,7 +1558,8 @@
       ConditionalEvaluation eval(*this);
       {
         ApplyDebugLocation DL(*this, Cond);
-        EmitBranchOnBoolExpr(CondBOp->getLHS(), TrueBlock, LHSFalse, LHSCount);
+        EmitBranchOnBoolExpr(CondBOp->getLHS(), TrueBlock, LHSFalse, LHSCount,
+                             Weights);
         EmitBlock(LHSFalse);
       }
 
@@ -1566,7 +1568,8 @@
 
       // Any temporaries created here are conditional.
       eval.begin(*this);
-      EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock, RHSCount);
+      EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock, RHSCount,
+                           Weights);
 
       eval.end(*this);
 
@@ -1581,7 +1584,7 @@
       uint64_t FalseCount = getCurrentProfileCount() - TrueCount;
       // Negate the condition and swap the destination blocks.
       return EmitBranchOnBoolExpr(CondUOp->getSubExpr(), FalseBlock, TrueBlock,
-                                  FalseCount);
+                                  FalseCount, Weights);
     }
   }
 
@@ -1592,7 +1595,7 @@
 
     ConditionalEvaluation cond(*this);
     EmitBranchOnBoolExpr(CondOp->getCond(), LHSBlock, RHSBlock,
-                         getProfileCount(CondOp));
+                         getProfileCount(CondOp), Weights);
 
     // When computing PGO branch weights, we only know the overall count for
     // the true block. This code is essentially doing tail duplication of the
@@ -1612,14 +1615,14 @@
     {
       ApplyDebugLocation DL(*this, Cond);
       EmitBranchOnBoolExpr(CondOp->getLHS(), TrueBlock, FalseBlock,
-                           LHSScaledTrueCount);
+                           LHSScaledTrueCount, Weights);
     }
     cond.end(*this);
 
     cond.begin(*this);
     EmitBlock(RHSBlock);
     EmitBranchOnBoolExpr(CondOp->getRHS(), TrueBlock, FalseBlock,
-                         TrueCount - LHSScaledTrueCount);
+                         TrueCount - LHSScaledTrueCount, Weights);
     cond.end(*this);
 
     return;
@@ -1650,9 +1653,10 @@
 
   // Create branch weights based on the number of times we get here and the
   // number of times the condition should be true.
-  uint64_t CurrentCount = std::max(getCurrentProfileCount(), TrueCount);
-  llvm::MDNode *Weights =
-      createProfileWeights(TrueCount, CurrentCount - TrueCount);
+  if (!Weights) {
+    uint64_t CurrentCount = std::max(getCurrentProfileCount(), TrueCount);
+    Weights = createProfileWeights(TrueCount, CurrentCount - TrueCount);
+  }
 
   // Emit the code with the fully general case.
   llvm::Value *CondV;
Index: clang/lib/CodeGen/CGStmt.cpp
===================================================================
--- clang/lib/CodeGen/CGStmt.cpp
+++ clang/lib/CodeGen/CGStmt.cpp
@@ -27,6 +27,7 @@
 #include "llvm/IR/Intrinsics.h"
 #include "llvm/IR/MDBuilder.h"
 #include "llvm/Support/SaveAndRestore.h"
+#include "llvm/Transforms/Scalar/LowerExpectIntrinsic.h"
 
 using namespace clang;
 using namespace CodeGen;
@@ -652,6 +653,24 @@
   EmitBranch(IndGotoBB);
 }
 
+static Optional<std::pair<uint32_t, uint32_t>>
+getLikelihoodWeights(const IfStmt &If) {
+  switch (If.getThenLikelihood()) {
+  case Stmt::LH_None:
+  case Stmt::LH_Conflict:
+    return None;
+
+  case Stmt::LH_Likely:
+    return std::pair<uint32_t, uint32_t>(llvm::LikelyBranchWeight,
+                                         llvm::UnlikelyBranchWeight);
+
+  case Stmt::LH_Unlikely:
+    return std::pair<uint32_t, uint32_t>(llvm::UnlikelyBranchWeight,
+                                         llvm::LikelyBranchWeight);
+  }
+  llvm_unreachable("Unknown Likelihood");
+}
+
 void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
   // C99 6.8.4.1: The first substatement is executed if the expression compares
   // unequal to 0.  The condition must be a scalar type.
@@ -695,8 +714,20 @@
   if (S.getElse())
     ElseBlock = createBasicBlock("if.else");
 
-  EmitBranchOnBoolExpr(S.getCond(), ThenBlock, ElseBlock,
-                       getProfileCount(S.getThen()));
+  // Prefer the PGO based weights over the likelihood attribute.
+  // When the build isn't optimized the metadata isn't used, so don't generate
+  // it.
+  llvm::MDNode *Weights = nullptr;
+  uint64_t Count = getProfileCount(S.getThen());
+  if (!Count && CGM.getCodeGenOpts().OptimizationLevel) {
+    Optional<std::pair<uint32_t, uint32_t>> LHW = getLikelihoodWeights(S);
+    if (LHW) {
+      llvm::MDBuilder MDHelper(CGM.getLLVMContext());
+      Weights = MDHelper.createBranchWeights(LHW->first, LHW->second);
+    }
+  }
+
+  EmitBranchOnBoolExpr(S.getCond(), ThenBlock, ElseBlock, Count, Weights);
 
   // Emit the 'then' code.
   EmitBlock(ThenBlock);
Index: clang/lib/AST/TextNodeDumper.cpp
===================================================================
--- clang/lib/AST/TextNodeDumper.cpp
+++ clang/lib/AST/TextNodeDumper.cpp
@@ -56,6 +56,23 @@
   llvm_unreachable("Decl that isn't part of DeclNodes.inc!");
 }
 
+static void dumpLikelihood(raw_ostream &OS, Stmt::Likelihood LH) {
+  switch (LH) {
+  case Stmt::LH_None:
+    return;
+  case Stmt::LH_Likely:
+    OS << " likely";
+    return;
+  case Stmt::LH_Unlikely:
+    OS << " unlikely";
+    return;
+  case Stmt::LH_Conflict:
+    OS << " likelihood_conflict";
+    return;
+  }
+  llvm_unreachable("Invalid likelihood value");
+}
+
 TextNodeDumper::TextNodeDumper(raw_ostream &OS, const ASTContext &Context,
                                bool ShowColors)
     : TextTreeStructure(OS, ShowColors), OS(OS), ShowColors(ShowColors),
@@ -907,6 +924,7 @@
     OS << " has_var";
   if (Node->hasElseStorage())
     OS << " has_else";
+  dumpLikelihood(OS, Node->getThenLikelihood());
 }
 
 void TextNodeDumper::VisitSwitchStmt(const SwitchStmt *Node) {
Index: clang/lib/AST/Stmt.cpp
===================================================================
--- clang/lib/AST/Stmt.cpp
+++ clang/lib/AST/Stmt.cpp
@@ -828,7 +828,8 @@
 
 IfStmt::IfStmt(const ASTContext &Ctx, SourceLocation IL, bool IsConstexpr,
                Stmt *Init, VarDecl *Var, Expr *Cond, SourceLocation LPL,
-               SourceLocation RPL, Stmt *Then, SourceLocation EL, Stmt *Else)
+               SourceLocation RPL, Stmt *Then, SourceLocation EL, Stmt *Else,
+               Likelihood LH)
     : Stmt(IfStmtClass), LParenLoc(LPL), RParenLoc(RPL) {
   bool HasElse = Else != nullptr;
   bool HasVar = Var != nullptr;
@@ -836,6 +837,7 @@
   IfStmtBits.HasElse = HasElse;
   IfStmtBits.HasVar = HasVar;
   IfStmtBits.HasInit = HasInit;
+  IfStmtBits.ThenLikelihood = LH;
 
   setConstexpr(IsConstexpr);
 
@@ -858,12 +860,13 @@
   IfStmtBits.HasElse = HasElse;
   IfStmtBits.HasVar = HasVar;
   IfStmtBits.HasInit = HasInit;
+  IfStmtBits.ThenLikelihood = LH_None;
 }
 
 IfStmt *IfStmt::Create(const ASTContext &Ctx, SourceLocation IL,
                        bool IsConstexpr, Stmt *Init, VarDecl *Var, Expr *Cond,
                        SourceLocation LPL, SourceLocation RPL, Stmt *Then,
-                       SourceLocation EL, Stmt *Else) {
+                       SourceLocation EL, Stmt *Else, Likelihood LH) {
   bool HasElse = Else != nullptr;
   bool HasVar = Var != nullptr;
   bool HasInit = Init != nullptr;
@@ -871,8 +874,8 @@
       totalSizeToAlloc<Stmt *, SourceLocation>(
           NumMandatoryStmtPtr + HasElse + HasVar + HasInit, HasElse),
       alignof(IfStmt));
-  return new (Mem)
-      IfStmt(Ctx, IL, IsConstexpr, Init, Var, Cond, LPL, RPL, Then, EL, Else);
+  return new (Mem) IfStmt(Ctx, IL, IsConstexpr, Init, Var, Cond, LPL, RPL, Then,
+                          EL, Else, LH);
 }
 
 IfStmt *IfStmt::CreateEmpty(const ASTContext &Ctx, bool HasElse, bool HasVar,
Index: clang/lib/AST/JSONNodeDumper.cpp
===================================================================
--- clang/lib/AST/JSONNodeDumper.cpp
+++ clang/lib/AST/JSONNodeDumper.cpp
@@ -6,6 +6,24 @@
 
 using namespace clang;
 
+static void dumpLikelihood(llvm::json::OStream &JOS, StringRef Key,
+                           Stmt::Likelihood LH) {
+  switch (LH) {
+  case Stmt::LH_None:
+    return;
+  case Stmt::LH_Likely:
+    JOS.attribute(Key, "likely");
+    return;
+  case Stmt::LH_Unlikely:
+    JOS.attribute(Key, "unlikely");
+    return;
+  case Stmt::LH_Conflict:
+    JOS.attribute(Key, "conflict");
+    return;
+  }
+  llvm_unreachable("Invalid likelihood value");
+}
+
 void JSONNodeDumper::addPreviousDeclaration(const Decl *D) {
   switch (D->getKind()) {
 #define DECL(DERIVED, BASE)                                                    \
@@ -1431,6 +1449,7 @@
   attributeOnlyIfTrue("hasVar", IS->hasVarStorage());
   attributeOnlyIfTrue("hasElse", IS->hasElseStorage());
   attributeOnlyIfTrue("isConstexpr", IS->isConstexpr());
+  dumpLikelihood(JOS, "thenLikelihood", IS->getThenLikelihood());
 }
 
 void JSONNodeDumper::VisitSwitchStmt(const SwitchStmt *SS) {
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -4386,7 +4386,8 @@
   StmtResult BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr,
                          SourceLocation LParenLoc, Stmt *InitStmt,
                          ConditionResult Cond, SourceLocation RParenLoc,
-                         Stmt *ThenVal, SourceLocation ElseLoc, Stmt *ElseVal);
+                         Stmt *ThenVal, SourceLocation ElseLoc, Stmt *ElseVal,
+                         Stmt::Likelihood LH);
   StmtResult ActOnStartOfSwitchStmt(SourceLocation SwitchLoc,
                                     SourceLocation LParenLoc, Stmt *InitStmt,
                                     ConditionResult Cond,
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3138,6 +3138,9 @@
 def warn_attribute_after_definition_ignored : Warning<
   "attribute %0 after definition is ignored">,
    InGroup<IgnoredAttributes>;
+def warn_attributes_likelihood_ifstmt_conflict
+    : Warning<"conflicting attributes %0 are ignored">,
+      InGroup<IgnoredAttributes>;
 def warn_cxx11_gnu_attribute_on_type : Warning<
   "attribute %0 ignored, because it cannot be applied to a type">,
   InGroup<IgnoredAttributes>;
Index: clang/include/clang/Basic/AttrDocs.td
===================================================================
--- clang/include/clang/Basic/AttrDocs.td
+++ clang/include/clang/Basic/AttrDocs.td
@@ -1684,6 +1684,100 @@
   }];
 }
 
+def LikelihoodDocs : Documentation {
+  let Category = DocCatStmt;
+  let Heading = "likely and unlikely";
+  let Content = [{
+The ``likely`` and ``unlikely`` attributes are used as compiler hints.
+The attributes are used to aid the compiler to determine which branch is
+likely or unlikely to be taken. This is done by marking the first statement in
+the branch with one of the two attributes.
+
+It isn't allowed to annotate a single statement with both ``likely`` and
+``unlikely``. It's allowed to create a contradictions by marking
+the first statement in the ``true`` and ``false`` branch with the same
+attribute.  These contradictions will result in a diagnostic and the compiler
+will ignore the attributes.
+
+These attributes have no effect on the generated code when using
+PGO (Profile-Guided Optimization) or at optimization level 0.
+
+In Clang the attributes will be ignored if they're not placed on the first
+statement in a branch. The C++ Standard recommends to honor them on every
+statement in the path of execution, but that can be confusing:
+
+.. code-block:: c++
+
+  if (b) {
+    [[unlikely]] --b; // In the path of execution,
+                      // this branch is considered unlikely.
+  }
+
+  if (b) {
+    --b;
+    if(b)
+      return;
+    [[unlikely]] --b; // Not in the path of execution,
+  }                   // the branch has no likelihood information.
+
+  if (b) {
+    --b;
+    foo(b);
+	// Whether or not the next statement is in the path of execution depends
+    // on the declaration of foo():
+    // In the path of execution: void foo(int);
+    // Not in the path of execution: [[noreturn]] void foo(int);
+	// This means the likelihood of the branch depends on the declaration
+    // of foo().
+    [[unlikely]] --b;
+  }
+
+
+At the moment the attribute only has effect when used in an ``if`` statement.
+
+.. code-block:: c++
+
+  if (b) [[likely]] { // Placement on the first statement in the branch.
+    // The compiler will optimize to execute the code here.
+  } else {
+  }
+
+  if (b)
+    [[unlikely]] b++; // Placement on the first statement in the branch.
+  else {
+    // The compiler will optimize to execute the code here.
+  }
+
+  if (b) {
+    [[unlikely]] b++; // Placement on the second statement in the branch.
+  }                   // The attribute will be ignored.
+
+  if (b) [[likely]] {
+    [[unlikely]] b++; // No contradiction since the second attribute
+  }                   // is ignored.
+
+  if (b)
+    ;
+  else [[likely]] {
+    // The compiler will optimize to execute the code here.
+  }
+
+  if (b)
+    ;
+  else
+    // The compiler will optimize to execute the next statement.
+    [[likely]] b = f();
+
+  if (b) [[likely]]; // Both branches are likely. A diagnostic is issued
+  else [[likely]];   // and the attributes are ignored.
+
+  if (b)
+    [[likely]] int i = 5; // Issues a diagnostic since the attribute
+                          // isn't allowed on a declaration.
+
+  }];
+}
+
 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
@@ -1288,6 +1288,18 @@
   let Documentation = [FallthroughDocs];
 }
 
+def Likely : StmtAttr {
+  // FIXME: Change the date to 201803 once the implementation is finished.
+  let Spellings = [CXX11<"", "likely", 2>, C2x<"clang", "likely">];
+  let Documentation = [LikelihoodDocs];
+}
+
+def Unlikely : StmtAttr {
+  // FIXME: Change the date to 201803 once the implementation is finished.
+  let Spellings = [CXX11<"", "unlikely", 2>, C2x<"clang", "unlikely">];
+  let Documentation = [LikelihoodDocs];
+}
+
 def NoMerge : StmtAttr {
   let Spellings = [Clang<"nomerge">];
   let Documentation = [NoMergeDocs];
Index: clang/include/clang/AST/Stmt.h
===================================================================
--- clang/include/clang/AST/Stmt.h
+++ clang/include/clang/AST/Stmt.h
@@ -172,6 +172,10 @@
     /// True if this if statement has storage for an init statement.
     unsigned HasInit : 1;
 
+    /// The likelihood of taking the ThenStmt.
+    /// One of the enumeration values in Stmt::Likelihood.
+    unsigned ThenLikelihood : 2;
+
     /// The location of the "if".
     SourceLocation IfLoc;
   };
@@ -1098,6 +1102,14 @@
   /// de-serialization).
   struct EmptyShell {};
 
+  /// The likelihood of a branch being taken.
+  enum Likelihood {
+    LH_None,     ///< No attribute set.
+    LH_Likely,   ///< Branch has the [[likely]] attribute.
+    LH_Unlikely, ///< Branch has the [[unlikely]] attribute.
+    LH_Conflict  ///< Both branches of the IfStmt have the same attribute.
+  };
+
 protected:
   /// Iterator for iterating over Stmt * arrays that contain only T *.
   ///
@@ -1918,7 +1930,8 @@
   /// Build an if/then/else statement.
   IfStmt(const ASTContext &Ctx, SourceLocation IL, bool IsConstexpr, Stmt *Init,
          VarDecl *Var, Expr *Cond, SourceLocation LParenLoc,
-         SourceLocation RParenLoc, Stmt *Then, SourceLocation EL, Stmt *Else);
+         SourceLocation RParenLoc, Stmt *Then, SourceLocation EL, Stmt *Else,
+         Likelihood LH);
 
   /// Build an empty if/then/else statement.
   explicit IfStmt(EmptyShell Empty, bool HasElse, bool HasVar, bool HasInit);
@@ -1929,7 +1942,7 @@
                         bool IsConstexpr, Stmt *Init, VarDecl *Var, Expr *Cond,
                         SourceLocation LPL, SourceLocation RPL, Stmt *Then,
                         SourceLocation EL = SourceLocation(),
-                        Stmt *Else = nullptr);
+                        Stmt *Else = nullptr, Likelihood LH = LH_None);
 
   /// Create an empty IfStmt optionally with storage for an else statement,
   /// condition variable and init expression.
@@ -2046,6 +2059,13 @@
   bool isConstexpr() const { return IfStmtBits.IsConstexpr; }
   void setConstexpr(bool C) { IfStmtBits.IsConstexpr = C; }
 
+  Likelihood getThenLikelihood() const {
+    return static_cast<Likelihood>(IfStmtBits.ThenLikelihood);
+  }
+  void setThenLikelihood(Likelihood LH) {
+    IfStmtBits.ThenLikelihood = static_cast<unsigned>(LH);
+  }
+
   /// If this is an 'if constexpr', determine which substatement will be taken.
   /// Otherwise, or if the condition is value-dependent, returns None.
   Optional<const Stmt*> getNondiscardedCase(const ASTContext &Ctx) const;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to