[clang] b46fddf - [CodeGen] Implement [[likely]] and [[unlikely]] for while and for loop.

Mark de Wever via cfe-commits cfe-commits at lists.llvm.org
Sat Oct 31 09:51:59 PDT 2020


Author: Mark de Wever
Date: 2020-10-31T17:51:29+01:00
New Revision: b46fddf75fc27ee1545f00ab853d50b10c1d7ee6

URL: https://github.com/llvm/llvm-project/commit/b46fddf75fc27ee1545f00ab853d50b10c1d7ee6
DIFF: https://github.com/llvm/llvm-project/commit/b46fddf75fc27ee1545f00ab853d50b10c1d7ee6.diff

LOG: [CodeGen] Implement [[likely]] and [[unlikely]] for while and for loop.

The attribute has no effect on a do statement since the path of execution
will always include its substatement.

It adds a diagnostic when the attribute is used on an infinite while loop
since the codegen omits the branch here. Since the likelihood attributes
have no effect on a do statement no diagnostic will be issued for
do [[unlikely]] {...} while(0);

Differential Revision: https://reviews.llvm.org/D89899

Added: 
    clang/test/CodeGenCXX/attr-likelihood-iteration-stmt.cpp

Modified: 
    clang/include/clang/AST/Stmt.h
    clang/include/clang/Basic/AttrDocs.td
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/lib/AST/Stmt.cpp
    clang/lib/CodeGen/CGStmt.cpp
    clang/lib/CodeGen/CodeGenFunction.cpp
    clang/lib/CodeGen/CodeGenFunction.h
    clang/test/CodeGenCXX/attr-likelihood-if-branch-weights.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index c2452f426566..c2e69a91e55d 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -1183,6 +1183,9 @@ class alignas(void *) Stmt {
   /// \returns the likelihood of a statement.
   static Likelihood getLikelihood(const Stmt *S);
 
+  /// \returns the likelihood attribute of a statement.
+  static const Attr *getLikelihoodAttr(const Stmt *S);
+
   /// \returns the likelihood of the 'then' branch of an 'if' statement. The
   /// 'else' branch is required to determine whether both branches specify the
   /// same likelihood, which affects the result.

diff  --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 912af82dee8c..238b0752a1a2 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -1738,7 +1738,8 @@ PGO (Profile-Guided Optimization) or at optimization level 0.
 
 In Clang, the attributes will be ignored if they're not placed on
 * the ``case`` or ``default`` label of a ``switch`` statement,
-* or on the substatement of an ``if`` or ``else`` statement.
+* or on the substatement of an ``if`` or ``else`` statement,
+* or on the substatement of an ``for`` or ``while`` statement.
 The C++ Standard recommends to honor them on every statement in the
 path of execution, but that can be confusing:
 
@@ -1769,8 +1770,7 @@ path of execution, but that can be confusing:
   }
 
 
-At the moment the attributes only have effect when used in an ``if``, ``else``,
-or ``switch`` statement.
+Below are some example usages of the likelihood attributes and their effects:
 
 .. code-block:: c++
 
@@ -1850,6 +1850,23 @@ or ``switch`` statement.
       break;
   }
 
+  for(int i = 0; i != size; ++i) [[likely]] {
+    ...               // The loop is the likely path of execution
+  }
+
+  for(const auto &E : Elements) [[likely]] {
+    ...               // The loop is the likely path of execution
+  }
+
+  while(i != size) [[unlikely]] {
+    ...               // The loop is the unlikely path of execution
+  }                   // The generated code will optimize to skip the loop body
+
+  while(true) [[unlikely]] {
+    ...               // The attribute has no effect
+  }                   // Clang elides the comparison and generates an infinite
+                      // loop
+
   }];
 }
 

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index fe6b88321f6b..2b19eac7e0c8 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3157,6 +3157,11 @@ def warn_cxx11_gnu_attribute_on_type : Warning<
 def warn_unhandled_ms_attribute_ignored : Warning<
   "__declspec attribute %0 is not supported">,
   InGroup<IgnoredAttributes>;
+def warn_attribute_has_no_effect_on_infinite_loop : Warning<
+  "attribute %0 has no effect when annotating an infinite loop">,
+   InGroup<IgnoredAttributes>;
+def note_attribute_has_no_effect_on_infinite_loop_here : Note<
+  "annotating the infinite loop here">;
 def err_decl_attribute_invalid_on_stmt : Error<
   "%0 attribute cannot be applied to a statement">;
 def err_stmt_attribute_invalid_on_decl : Error<

diff  --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp
index 09503079ffae..8b2564d7fc96 100644
--- a/clang/lib/AST/Stmt.cpp
+++ b/clang/lib/AST/Stmt.cpp
@@ -158,6 +158,10 @@ Stmt::Likelihood Stmt::getLikelihood(const Stmt *S) {
   return ::getLikelihood(S).first;
 }
 
+const Attr *Stmt::getLikelihoodAttr(const Stmt *S) {
+  return ::getLikelihood(S).second;
+}
+
 Stmt::Likelihood Stmt::getLikelihood(const Stmt *Then, const Stmt *Else) {
   Likelihood LHT = ::getLikelihood(Then).first;
   Likelihood LHE = ::getLikelihood(Else).first;

diff  --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 3f8f77654f6d..38e5ce1ab11b 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -18,6 +18,7 @@
 #include "clang/AST/Attr.h"
 #include "clang/AST/StmtVisitor.h"
 #include "clang/Basic/Builtins.h"
+#include "clang/Basic/DiagnosticSema.h"
 #include "clang/Basic/PrettyStackTrace.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Basic/TargetInfo.h"
@@ -806,14 +807,22 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S,
     llvm::BasicBlock *ExitBlock = LoopExit.getBlock();
     if (ConditionScope.requiresCleanups())
       ExitBlock = createBasicBlock("while.exit");
-    Builder.CreateCondBr(
-        BoolCondVal, LoopBody, ExitBlock,
-        createProfileWeightsForLoop(S.getCond(), getProfileCount(S.getBody())));
+    llvm::MDNode *Weights = createProfileOrBranchWeightsForLoop(
+        S.getCond(), getProfileCount(S.getBody()), S.getBody());
+    Builder.CreateCondBr(BoolCondVal, LoopBody, ExitBlock, Weights);
 
     if (ExitBlock != LoopExit.getBlock()) {
       EmitBlock(ExitBlock);
       EmitBranchThroughCleanup(LoopExit);
     }
+  } else if (const Attr *A = Stmt::getLikelihoodAttr(S.getBody())) {
+    CGM.getDiags().Report(A->getLocation(),
+                          diag::warn_attribute_has_no_effect_on_infinite_loop)
+        << A << A->getRange();
+    CGM.getDiags().Report(
+        S.getWhileLoc(),
+        diag::note_attribute_has_no_effect_on_infinite_loop_here)
+        << SourceRange(S.getWhileLoc(), S.getRParenLoc());
   }
 
   // Emit the loop body.  We have to emit this in a cleanup scope
@@ -961,9 +970,9 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S,
     // 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());
-    Builder.CreateCondBr(
-        BoolCondVal, ForBody, ExitBlock,
-        createProfileWeightsForLoop(S.getCond(), getProfileCount(S.getBody())));
+    llvm::MDNode *Weights = createProfileOrBranchWeightsForLoop(
+        S.getCond(), getProfileCount(S.getBody()), S.getBody());
+    Builder.CreateCondBr(BoolCondVal, ForBody, ExitBlock, Weights);
 
     if (ExitBlock != LoopExit.getBlock()) {
       EmitBlock(ExitBlock);
@@ -1042,9 +1051,9 @@ CodeGenFunction::EmitCXXForRangeStmt(const CXXForRangeStmt &S,
   // The body is executed if the expression, contextually converted
   // to bool, is true.
   llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
-  Builder.CreateCondBr(
-      BoolCondVal, ForBody, ExitBlock,
-      createProfileWeightsForLoop(S.getCond(), getProfileCount(S.getBody())));
+  llvm::MDNode *Weights = createProfileOrBranchWeightsForLoop(
+      S.getCond(), getProfileCount(S.getBody()), S.getBody());
+  Builder.CreateCondBr(BoolCondVal, ForBody, ExitBlock, Weights);
 
   if (ExitBlock != LoopExit.getBlock()) {
     EmitBlock(ExitBlock);

diff  --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index 77b2c972be46..f1fe8f92c07c 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -2555,3 +2555,12 @@ llvm::MDNode *CodeGenFunction::createBranchWeights(Stmt::Likelihood LH) const {
   llvm::MDBuilder MDHelper(CGM.getLLVMContext());
   return MDHelper.createBranchWeights(LHW->first, LHW->second);
 }
+
+llvm::MDNode *CodeGenFunction::createProfileOrBranchWeightsForLoop(
+    const Stmt *Cond, uint64_t LoopCount, const Stmt *Body) const {
+  llvm::MDNode *Weights = createProfileWeightsForLoop(Cond, LoopCount);
+  if (!Weights && CGM.getCodeGenOpts().OptimizationLevel)
+    Weights = createBranchWeights(Stmt::getLikelihood(Body));
+
+  return Weights;
+}

diff  --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 2616226338d0..4cf857a5a3ec 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -1407,6 +1407,13 @@ class CodeGenFunction : public CodeGenTypeCache {
   llvm::MDNode *createProfileWeightsForLoop(const Stmt *Cond,
                                             uint64_t LoopCount) const;
 
+  /// Calculate the branch weight for PGO data or the likelihood attribute.
+  /// The function tries to get the weight of \ref createProfileWeightsForLoop.
+  /// If that fails it gets the weight of \ref createBranchWeights.
+  llvm::MDNode *createProfileOrBranchWeightsForLoop(const Stmt *Cond,
+                                                    uint64_t LoopCount,
+                                                    const Stmt *Body) const;
+
 public:
   /// Increment the profiler's counter for the given statement by \p StepV.
   /// If \p StepV is null, the default increment is 1.

diff  --git a/clang/test/CodeGenCXX/attr-likelihood-if-branch-weights.cpp b/clang/test/CodeGenCXX/attr-likelihood-if-branch-weights.cpp
index 6327396a9285..18b6228f09ba 100644
--- a/clang/test/CodeGenCXX/attr-likelihood-if-branch-weights.cpp
+++ b/clang/test/CodeGenCXX/attr-likelihood-if-branch-weights.cpp
@@ -69,6 +69,7 @@ void WhileStmt() {
 
   // CHECK-NOT: br {{.*}} %if.end{{.*}} !prof
   if (b)
+    // CHECK: br {{.*}} !prof !7
     while (B())
       [[unlikely]] { b = false; }
 }
@@ -96,6 +97,7 @@ void ForStmt() {
 
   // CHECK-NOT: br {{.*}} %if.end{{.*}} !prof
   if (b)
+    // CHECK: br {{.*}} !prof !7
     for (; B();)
       [[unlikely]] {}
 }

diff  --git a/clang/test/CodeGenCXX/attr-likelihood-iteration-stmt.cpp b/clang/test/CodeGenCXX/attr-likelihood-iteration-stmt.cpp
new file mode 100644
index 000000000000..1c87ee411f50
--- /dev/null
+++ b/clang/test/CodeGenCXX/attr-likelihood-iteration-stmt.cpp
@@ -0,0 +1,60 @@
+// RUN: %clang_cc1 -O1 -disable-llvm-passes -emit-llvm %s -o - -triple=x86_64-linux-gnu -verify
+// RUN: %clang_cc1 -O1 -disable-llvm-passes -emit-llvm %s -o - -triple=x86_64-linux-gnu | FileCheck %s
+
+void wl(int e){
+  // CHECK-LABEL: define{{.*}}wl
+  // CHECK: br {{.*}} !prof !6
+  while(e) [[likely]] ++e;
+}
+
+void wu(int e){
+  // CHECK-LABEL: define{{.*}}wu
+  // CHECK: br {{.*}} !prof !9
+  while(e) [[unlikely]] ++e;
+}
+
+void w_branch_elided(unsigned e){
+  // CHECK-LABEL: define{{.*}}w_branch_elided
+  // CHECK-NOT: br {{.*}} !prof
+  // expected-warning at +2 {{attribute 'likely' has no effect when annotating an infinite loop}}
+  // expected-note at +1 {{annotating the infinite loop here}}
+  while(1) [[likely]] ++e;
+}
+
+void fl(unsigned e)
+{
+  // CHECK-LABEL: define{{.*}}fl
+  // CHECK: br {{.*}} !prof !6
+  for(int i = 0; i != e; ++e) [[likely]];
+}
+
+void fu(int e)
+{
+  // CHECK-LABEL: define{{.*}}fu
+  // CHECK: br {{.*}} !prof !9
+  for(int i = 0; i != e; ++e) [[unlikely]];
+}
+
+void f_branch_elided()
+{
+  // CHECK-LABEL: define{{.*}}f_branch_elided
+  // CHECK-NOT: br {{.*}} !prof
+  for(;;) [[likely]];
+}
+
+void frl(int (&&e) [4])
+{
+  // CHECK-LABEL: define{{.*}}frl
+  // CHECK: br {{.*}} !prof !6
+  for(int i : e) [[likely]];
+}
+
+void fru(int (&&e) [4])
+{
+  // CHECK-LABEL: define{{.*}}fru
+  // CHECK: br {{.*}} !prof !9
+  for(int i : e) [[unlikely]];
+}
+
+// CHECK: !6 = !{!"branch_weights", i32 2000, i32 1}
+// CHECK: !9 = !{!"branch_weights", i32 1, i32 2000}


        


More information about the cfe-commits mailing list