atmnpatel created this revision.
atmnpatel added reviewers: jdoerfert, aqjune, RalfJung.
Herald added subscribers: cfe-commits, danielkiss.
Herald added a project: clang.
atmnpatel requested review of this revision.

The `noprogress` LLVM IR attribute currently under discussion is deduced for 
functions that contain loops that have a constant non-zero conditional as per 
the C Spec. In addition, these particular loops have an additional bit of 
metadata `llvm.loop.noprogress` so llvm can differentiate between the loops 
that can be optimized out and ones that can't be optimized out. The changes to 
the LoopDeletion pass is incoming.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D86841

Files:
  clang/lib/CodeGen/CGLoopInfo.cpp
  clang/lib/CodeGen/CGLoopInfo.h
  clang/lib/CodeGen/CGStmt.cpp
  clang/test/CodeGen/attr-noprogress.c

Index: clang/test/CodeGen/attr-noprogress.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/attr-noprogress.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -S -emit-llvm %s -o - | grep " noprogress " | count 1
+// RUN: %clang_cc1 -S -emit-llvm %s -o - | grep llvm.loop.noprogress | count 1
+
+void f() {
+  for (; 1;) {
+  }
+}
+
+void w() {
+  while (1) {
+  }
+}
+
+void d() {
+  do {
+
+  } while (1);
+}
Index: clang/lib/CodeGen/CGStmt.cpp
===================================================================
--- clang/lib/CodeGen/CGStmt.cpp
+++ clang/lib/CodeGen/CGStmt.cpp
@@ -736,10 +736,26 @@
   JumpDest LoopHeader = getJumpDestInCurrentScope("while.cond");
   EmitBlock(LoopHeader.getBlock());
 
+  // Evaluate the conditional in the while header.  C99 6.8.5.1: The
+  // evaluation of the controlling expression takes place before each
+  // execution of the loop body.
+  llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
+
+  // while(1) is common, avoid extra exit blocks.  Be sure
+  // to correctly handle break/continue though.
+  bool EmitBoolCondBranch = true;
+  bool NoProgress = false;
+  if (llvm::ConstantInt *C = dyn_cast<llvm::ConstantInt>(BoolCondVal))
+    if (C->isOne()) {
+      EmitBoolCondBranch = false;
+      CurFn->addFnAttr(llvm::Attribute::NoProgress);
+      NoProgress = true;
+    }
+
   const SourceRange &R = S.getSourceRange();
   LoopStack.push(LoopHeader.getBlock(), CGM.getContext(), CGM.getCodeGenOpts(),
                  WhileAttrs, SourceLocToDebugLoc(R.getBegin()),
-                 SourceLocToDebugLoc(R.getEnd()));
+                 SourceLocToDebugLoc(R.getEnd()), NoProgress);
 
   // Create an exit block for when the condition fails, which will
   // also become the break target.
@@ -760,18 +776,6 @@
   if (S.getConditionVariable())
     EmitDecl(*S.getConditionVariable());
 
-  // Evaluate the conditional in the while header.  C99 6.8.5.1: The
-  // evaluation of the controlling expression takes place before each
-  // execution of the loop body.
-  llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
-
-  // while(1) is common, avoid extra exit blocks.  Be sure
-  // to correctly handle break/continue though.
-  bool EmitBoolCondBranch = true;
-  if (llvm::ConstantInt *C = dyn_cast<llvm::ConstantInt>(BoolCondVal))
-    if (C->isOne())
-      EmitBoolCondBranch = false;
-
   // As long as the condition is true, go to the loop body.
   llvm::BasicBlock *LoopBody = createBasicBlock("while.body");
   if (EmitBoolCondBranch) {
@@ -838,27 +842,33 @@
 
   EmitBlock(LoopCond.getBlock());
 
-  const SourceRange &R = S.getSourceRange();
-  LoopStack.push(LoopBody, CGM.getContext(), CGM.getCodeGenOpts(), DoAttrs,
-                 SourceLocToDebugLoc(R.getBegin()),
-                 SourceLocToDebugLoc(R.getEnd()));
-
-  // C99 6.8.5.2: "The evaluation of the controlling expression takes place
-  // after each execution of the loop body."
-
   // Evaluate the conditional in the while header.
   // 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());
 
-  BreakContinueStack.pop_back();
-
   // "do {} while (0)" is common in macros, avoid extra blocks.  Be sure
   // to correctly handle break/continue though.
   bool EmitBoolCondBranch = true;
-  if (llvm::ConstantInt *C = dyn_cast<llvm::ConstantInt>(BoolCondVal))
+  bool NoProgress = false;
+  if (llvm::ConstantInt *C = dyn_cast<llvm::ConstantInt>(BoolCondVal)) {
     if (C->isZero())
       EmitBoolCondBranch = false;
+    if (C->isOne()) {
+      CurFn->addFnAttr(llvm::Attribute::NoProgress);
+      NoProgress = true;
+    }
+  }
+
+  const SourceRange &R = S.getSourceRange();
+  LoopStack.push(LoopBody, CGM.getContext(), CGM.getCodeGenOpts(), DoAttrs,
+                 SourceLocToDebugLoc(R.getBegin()),
+                 SourceLocToDebugLoc(R.getEnd()), NoProgress);
+
+  // C99 6.8.5.2: "The evaluation of the controlling expression takes place
+  // after each execution of the loop body."
+
+  BreakContinueStack.pop_back();
 
   // As long as the condition is true, iterate the loop.
   if (EmitBoolCondBranch) {
@@ -896,10 +906,20 @@
   llvm::BasicBlock *CondBlock = Continue.getBlock();
   EmitBlock(CondBlock);
 
+  bool NoProgress = false;
+  if (S.getCond()) {
+    llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
+    if (llvm::ConstantInt *C = dyn_cast<llvm::ConstantInt>(BoolCondVal))
+      if (C->isOne()) {
+        CurFn->addFnAttr(llvm::Attribute::NoProgress);
+        NoProgress = true;
+      }
+  }
+
   const SourceRange &R = S.getSourceRange();
   LoopStack.push(CondBlock, CGM.getContext(), CGM.getCodeGenOpts(), ForAttrs,
                  SourceLocToDebugLoc(R.getBegin()),
-                 SourceLocToDebugLoc(R.getEnd()));
+                 SourceLocToDebugLoc(R.getEnd()), NoProgress);
 
   // If the for loop doesn't have an increment we can just use the
   // condition as the continue block.  Otherwise we'll need to create
Index: clang/lib/CodeGen/CGLoopInfo.h
===================================================================
--- clang/lib/CodeGen/CGLoopInfo.h
+++ clang/lib/CodeGen/CGLoopInfo.h
@@ -75,6 +75,9 @@
 
   /// Value for llvm.loop.pipeline.iicount metadata.
   unsigned PipelineInitiationInterval;
+
+  /// Value to prevent Dead Loop Elimination.
+  bool NoProgress;
 };
 
 /// Information used when generating a structured loop.
@@ -205,7 +208,7 @@
   void push(llvm::BasicBlock *Header, clang::ASTContext &Ctx,
             const clang::CodeGenOptions &CGOpts,
             llvm::ArrayRef<const Attr *> Attrs, const llvm::DebugLoc &StartLoc,
-            const llvm::DebugLoc &EndLoc);
+            const llvm::DebugLoc &EndLoc, const bool NoProgress = false);
 
   /// End the current loop.
   void pop();
@@ -272,6 +275,9 @@
     StagedAttrs.PipelineInitiationInterval = C;
   }
 
+  /// Set no progress for the next loop pushed.
+  void setNoProgress(bool P) { StagedAttrs.NoProgress = P; }
+
 private:
   /// Returns true if there is LoopInfo on the stack.
   bool hasInfo() const { return !Active.empty(); }
Index: clang/lib/CodeGen/CGLoopInfo.cpp
===================================================================
--- clang/lib/CodeGen/CGLoopInfo.cpp
+++ clang/lib/CodeGen/CGLoopInfo.cpp
@@ -418,10 +418,14 @@
       LoopProperties.push_back(EndLoc.getAsMDNode());
   }
 
+  LLVMContext &Ctx = Header->getContext();
+  if (Attrs.NoProgress)
+    LoopProperties.push_back(
+        MDNode::get(Ctx, MDString::get(Ctx, "llvm.loop.noprogress")));
+
   assert(!!AccGroup == Attrs.IsParallel &&
          "There must be an access group iff the loop is parallel");
   if (Attrs.IsParallel) {
-    LLVMContext &Ctx = Header->getContext();
     LoopProperties.push_back(MDNode::get(
         Ctx, {MDString::get(Ctx, "llvm.loop.parallel_accesses"), AccGroup}));
   }
@@ -438,7 +442,7 @@
       VectorizePredicateEnable(LoopAttributes::Unspecified), VectorizeWidth(0),
       InterleaveCount(0), UnrollCount(0), UnrollAndJamCount(0),
       DistributeEnable(LoopAttributes::Unspecified), PipelineDisabled(false),
-      PipelineInitiationInterval(0) {}
+      PipelineInitiationInterval(0), NoProgress(false) {}
 
 void LoopAttributes::clear() {
   IsParallel = false;
@@ -453,6 +457,7 @@
   DistributeEnable = LoopAttributes::Unspecified;
   PipelineDisabled = false;
   PipelineInitiationInterval = 0;
+  NoProgress = false;
 }
 
 LoopInfo::LoopInfo(BasicBlock *Header, const LoopAttributes &Attrs,
@@ -476,7 +481,7 @@
       Attrs.UnrollEnable == LoopAttributes::Unspecified &&
       Attrs.UnrollAndJamEnable == LoopAttributes::Unspecified &&
       Attrs.DistributeEnable == LoopAttributes::Unspecified && !StartLoc &&
-      !EndLoc)
+      !EndLoc && !Attrs.NoProgress)
     return;
 
   TempLoopID = MDNode::getTemporary(Header->getContext(), None);
@@ -577,8 +582,7 @@
                          const clang::CodeGenOptions &CGOpts,
                          ArrayRef<const clang::Attr *> Attrs,
                          const llvm::DebugLoc &StartLoc,
-                         const llvm::DebugLoc &EndLoc) {
-
+                         const llvm::DebugLoc &EndLoc, const bool NoProgress) {
   // Identify loop hint attributes from Attrs.
   for (const auto *Attr : Attrs) {
     const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(Attr);
@@ -755,6 +759,8 @@
     }
   }
 
+  setNoProgress(NoProgress);
+
   if (CGOpts.OptimizationLevel > 0)
     // Disable unrolling for the loop, if unrolling is disabled (via
     // -fno-unroll-loops) and no pragmas override the decision.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to