[polly] r202854 - Emit llvm.loop metadata for parallel loops

Tobias Grosser tobias at grosser.es
Tue Mar 4 06:59:01 PST 2014


Author: grosser
Date: Tue Mar  4 08:59:00 2014
New Revision: 202854

URL: http://llvm.org/viewvc/llvm-project?rev=202854&view=rev
Log:
Emit llvm.loop metadata for parallel loops

For now we only mark innermost loops for the loop vectorizer.  We could later
also mark not-innermost loops to enable the introduction of openmp parallelism.

Added:
    polly/trunk/lib/CodeGen/IRBuilder.cpp
    polly/trunk/test/Isl/CodeGen/LoopParallelMD/
    polly/trunk/test/Isl/CodeGen/LoopParallelMD/single_loop_param_parallel.ll
Modified:
    polly/trunk/include/polly/CodeGen/IRBuilder.h
    polly/trunk/include/polly/CodeGen/LoopGenerators.h
    polly/trunk/lib/CMakeLists.txt
    polly/trunk/lib/CodeGen/IslCodeGeneration.cpp
    polly/trunk/lib/CodeGen/LoopGenerators.cpp

Modified: polly/trunk/include/polly/CodeGen/IRBuilder.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/include/polly/CodeGen/IRBuilder.h?rev=202854&r1=202853&r2=202854&view=diff
==============================================================================
--- polly/trunk/include/polly/CodeGen/IRBuilder.h (original)
+++ polly/trunk/include/polly/CodeGen/IRBuilder.h Tue Mar  4 08:59:00 2014
@@ -7,8 +7,8 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// The Polly IRBuilder file contains Polly specific extensions for the
-// IRBuilder.
+// The Polly IRBuilder file contains Polly specific extensions for the IRBuilder
+// that are used e.g. to emit the llvm.loop.parallel metadata.
 //
 //===----------------------------------------------------------------------===//
 
@@ -16,8 +16,87 @@
 #define POLLY_CODEGEN_IRBUILDER_H
 
 #include "llvm/IR/IRBuilder.h"
-
 namespace polly {
-typedef llvm::IRBuilder<> PollyIRBuilder;
+
+/// @brief Keeps information about generated loops.
+class PollyLoopInfo {
+public:
+  PollyLoopInfo(llvm::BasicBlock *Header)
+      : LoopID(0), Header(Header), Parallel(false) {}
+
+  /// @brief Get the loop id metadata node.
+  ///
+  /// Each loop is identified by a self referencing metadata node of the form:
+  ///
+  ///    '!n = metadata !{metadata !n}'
+  ///
+  /// This functions creates such metadata on demand if not yet available.
+  ///
+  /// @return The loop id metadata node.
+  llvm::MDNode *GetLoopID() const;
+
+  /// @brief Get the head basic block of this loop.
+  llvm::BasicBlock *GetHeader() const { return Header; }
+
+  /// @brief Check if the loop is parallel.
+  ///
+  /// @return True, if the loop is parallel.
+  bool IsParallel() const { return Parallel; }
+
+  /// @brief Set a loop as parallel.
+  ///
+  /// @IsParallel True, if the loop is to be marked as parallel. False, if the
+  //              loop should be marked sequential.
+  void SetParallel(bool IsParallel = true) { Parallel = IsParallel; }
+
+private:
+  mutable llvm::MDNode *LoopID;
+  llvm::BasicBlock *Header;
+  bool Parallel;
+};
+
+class LoopAnnotator {
+public:
+  void Begin(llvm::BasicBlock *Header);
+  void SetCurrentParallel();
+  void End();
+  void Annotate(llvm::Instruction *I);
+
+private:
+  std::vector<PollyLoopInfo> Active;
+};
+
+/// @brief Add Polly specifics when running IRBuilder.
+///
+/// This is used to add additional items such as e.g. the llvm.loop.parallel
+/// metadata.
+template <bool PreserveNames>
+class PollyBuilderInserter
+    : protected llvm::IRBuilderDefaultInserter<PreserveNames> {
+public:
+  PollyBuilderInserter() : Annotator(0) {}
+  PollyBuilderInserter(class LoopAnnotator &A) : Annotator(&A) {}
+
+protected:
+  void InsertHelper(llvm::Instruction *I, const llvm::Twine &Name,
+                    llvm::BasicBlock *BB,
+                    llvm::BasicBlock::iterator InsertPt) const {
+    llvm::IRBuilderDefaultInserter<PreserveNames>::InsertHelper(I, Name, BB,
+                                                                InsertPt);
+    if (Annotator)
+      Annotator->Annotate(I);
+  }
+
+private:
+  class LoopAnnotator *Annotator;
+};
+
+#ifdef NDEBUG
+typedef PollyBuilderInserter<false> IRInserter;
+typedef llvm::IRBuilder<false, llvm::ConstantFolder, IRInserter> PollyIRBuilder;
+#else
+typedef PollyBuilderInserter<true> IRInserter;
+typedef llvm::IRBuilder<true, llvm::ConstantFolder, IRInserter> PollyIRBuilder;
+#endif
 }
 #endif

Modified: polly/trunk/include/polly/CodeGen/LoopGenerators.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/include/polly/CodeGen/LoopGenerators.h?rev=202854&r1=202853&r2=202854&view=diff
==============================================================================
--- polly/trunk/include/polly/CodeGen/LoopGenerators.h (original)
+++ polly/trunk/include/polly/CodeGen/LoopGenerators.h Tue Mar  4 08:59:00 2014
@@ -38,10 +38,14 @@ using namespace llvm;
 ///                   to update analysis information.
 /// @param ExitBlock  The block the loop will exit to.
 /// @param Predicate  The predicate used to generate the upper loop bound.
+/// @param Annotator  This function can (optionally) take a LoopAnnotator which
+///                   tracks the loop structure.
+/// @param Parallel   If this loop should be marked parallel in the Annotator.
 /// @return Value*    The newly created induction variable for this loop.
 Value *createLoop(Value *LowerBound, Value *UpperBound, Value *Stride,
                   PollyIRBuilder &Builder, Pass *P, BasicBlock *&ExitBlock,
-                  ICmpInst::Predicate Predicate);
+                  ICmpInst::Predicate Predicate,
+                  LoopAnnotator *Annotator = NULL, bool Parallel = false);
 
 class OMPGenerator {
 public:

Modified: polly/trunk/lib/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/CMakeLists.txt?rev=202854&r1=202853&r2=202854&view=diff
==============================================================================
--- polly/trunk/lib/CMakeLists.txt (original)
+++ polly/trunk/lib/CMakeLists.txt Tue Mar  4 08:59:00 2014
@@ -53,6 +53,7 @@ add_polly_library(LLVMPollyLib
   ${CLOOG_FILES}
   ${ISL_CODEGEN_FILES}
   CodeGen/LoopGenerators.cpp
+  CodeGen/IRBuilder.cpp
   CodeGen/Utils.cpp
   ${GPGPU_CODEGEN_FILES}
   Support/GICHelper.cpp

Added: polly/trunk/lib/CodeGen/IRBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/CodeGen/IRBuilder.cpp?rev=202854&view=auto
==============================================================================
--- polly/trunk/lib/CodeGen/IRBuilder.cpp (added)
+++ polly/trunk/lib/CodeGen/IRBuilder.cpp Tue Mar  4 08:59:00 2014
@@ -0,0 +1,60 @@
+//===------ PollyIRBuilder.cpp --------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// The Polly IRBuilder file contains Polly specific extensions for the IRBuilder
+// that are used e.g. to emit the llvm.loop.parallel metadata.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/CodeGen/IRBuilder.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/IR/Metadata.h"
+#include "llvm/Support/Debug.h"
+
+using namespace llvm;
+using namespace polly;
+
+llvm::MDNode *polly::PollyLoopInfo::GetLoopID() const {
+  if (LoopID)
+    return LoopID;
+
+  llvm::Value *Args[] = {0};
+  LoopID = llvm::MDNode::get(Header->getContext(), Args);
+  LoopID->replaceOperandWith(0, LoopID);
+  return LoopID;
+}
+
+void polly::LoopAnnotator::Begin(llvm::BasicBlock *Header) {
+  Active.push_back(PollyLoopInfo(Header));
+}
+
+void polly::LoopAnnotator::End() { Active.pop_back(); }
+
+void polly::LoopAnnotator::SetCurrentParallel() {
+  Active.back().SetParallel(true);
+}
+
+void polly::LoopAnnotator::Annotate(llvm::Instruction *Inst) {
+  if (Active.empty())
+    return;
+
+  const PollyLoopInfo &L = Active.back();
+  if (!L.IsParallel())
+    return;
+
+  if (TerminatorInst *TI = dyn_cast<llvm::TerminatorInst>(Inst)) {
+    for (unsigned i = 0, ie = TI->getNumSuccessors(); i != ie; ++i)
+      if (TI->getSuccessor(i) == L.GetHeader()) {
+        TI->setMetadata("llvm.loop", L.GetLoopID());
+        break;
+      }
+  } else if (Inst->mayReadOrWriteMemory()) {
+    Inst->setMetadata("llvm.mem.parallel_loop_access", L.GetLoopID());
+  }
+}

Modified: polly/trunk/lib/CodeGen/IslCodeGeneration.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/CodeGen/IslCodeGeneration.cpp?rev=202854&r1=202853&r2=202854&view=diff
==============================================================================
--- polly/trunk/lib/CodeGen/IslCodeGeneration.cpp (original)
+++ polly/trunk/lib/CodeGen/IslCodeGeneration.cpp Tue Mar  4 08:59:00 2014
@@ -539,8 +539,9 @@ Value *IslExprBuilder::create(__isl_take
 
 class IslNodeBuilder {
 public:
-  IslNodeBuilder(PollyIRBuilder &Builder, Pass *P)
-      : Builder(Builder), ExprBuilder(Builder, IDToValue, P), P(P) {}
+  IslNodeBuilder(PollyIRBuilder &Builder, LoopAnnotator &Annotator, Pass *P)
+      : Builder(Builder), Annotator(Annotator),
+        ExprBuilder(Builder, IDToValue, P), P(P) {}
 
   void addParameters(__isl_take isl_set *Context);
   void create(__isl_take isl_ast_node *Node);
@@ -548,6 +549,7 @@ public:
 
 private:
   PollyIRBuilder &Builder;
+  LoopAnnotator &Annotator;
   IslExprBuilder ExprBuilder;
   Pass *P;
 
@@ -778,6 +780,9 @@ void IslNodeBuilder::createForSequential
   BasicBlock *ExitBlock;
   Value *IV;
   CmpInst::Predicate Predicate;
+  bool Parallel;
+
+  Parallel = isInnermostParallel(For);
 
   Body = isl_ast_node_for_get_body(For);
 
@@ -809,11 +814,14 @@ void IslNodeBuilder::createForSequential
   if (MaxType != ValueInc->getType())
     ValueInc = Builder.CreateSExt(ValueInc, MaxType);
 
-  IV = createLoop(ValueLB, ValueUB, ValueInc, Builder, P, ExitBlock, Predicate);
+  IV = createLoop(ValueLB, ValueUB, ValueInc, Builder, P, ExitBlock, Predicate,
+                  &Annotator, Parallel);
   IDToValue[IteratorID] = IV;
 
   create(Body);
 
+  Annotator.End();
+
   IDToValue.erase(IteratorID);
 
   Builder.SetInsertPoint(ExitBlock->begin());
@@ -1032,9 +1040,12 @@ public:
 
     BasicBlock *StartBlock = executeScopConditionally(S, this);
     isl_ast_node *Ast = AstInfo.getAst();
-    PollyIRBuilder Builder(StartBlock->begin());
+    LoopAnnotator Annotator;
+    PollyIRBuilder Builder(StartBlock->getContext(), llvm::ConstantFolder(),
+                           polly::IRInserter(Annotator));
+    Builder.SetInsertPoint(StartBlock->begin());
 
-    IslNodeBuilder NodeBuilder(Builder, this);
+    IslNodeBuilder NodeBuilder(Builder, Annotator, this);
 
     // Build condition that evaluates at run-time if all assumptions taken
     // for the scop hold. If we detect some assumptions do not hold, the

Modified: polly/trunk/lib/CodeGen/LoopGenerators.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/CodeGen/LoopGenerators.cpp?rev=202854&r1=202853&r2=202854&view=diff
==============================================================================
--- polly/trunk/lib/CodeGen/LoopGenerators.cpp (original)
+++ polly/trunk/lib/CodeGen/LoopGenerators.cpp Tue Mar  4 08:59:00 2014
@@ -48,7 +48,8 @@ using namespace polly;
 //       always executed at least once, we can get rid of this branch.
 Value *polly::createLoop(Value *LB, Value *UB, Value *Stride,
                          PollyIRBuilder &Builder, Pass *P, BasicBlock *&ExitBB,
-                         ICmpInst::Predicate Predicate) {
+                         ICmpInst::Predicate Predicate,
+                         LoopAnnotator *Annotator, bool Parallel) {
 
   DominatorTree &DT = P->getAnalysis<DominatorTreeWrapperPass>().getDomTree();
   LoopInfo &LI = P->getAnalysis<LoopInfo>();
@@ -65,6 +66,12 @@ Value *polly::createLoop(Value *LB, Valu
   BasicBlock *PreHeaderBB =
       BasicBlock::Create(Context, "polly.loop_preheader", F);
 
+  if (Annotator) {
+    Annotator->Begin(HeaderBB);
+    if (Parallel)
+      Annotator->SetCurrentParallel();
+  }
+
   // Update LoopInfo
   Loop *OuterLoop = LI.getLoopFor(BeforeBB);
   Loop *NewLoop = new Loop();

Added: polly/trunk/test/Isl/CodeGen/LoopParallelMD/single_loop_param_parallel.ll
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/Isl/CodeGen/LoopParallelMD/single_loop_param_parallel.ll?rev=202854&view=auto
==============================================================================
--- polly/trunk/test/Isl/CodeGen/LoopParallelMD/single_loop_param_parallel.ll (added)
+++ polly/trunk/test/Isl/CodeGen/LoopParallelMD/single_loop_param_parallel.ll Tue Mar  4 08:59:00 2014
@@ -0,0 +1,102 @@
+; RUN: opt %loadPolly -polly-codegen-isl -S < %s | FileCheck %s -check-prefix=SEQUENTIAL
+; RUN: opt %loadPolly -polly-codegen-isl -S -polly-codegen-scev < %s | FileCheck %s -check-prefix=SEQUENTIAL-SCEV
+; RUN: opt %loadPolly -polly-codegen-isl -polly-ast-detect-parallel -S < %s | FileCheck %s -check-prefix=PARALLEL
+; RUN: opt %loadPolly -polly-codegen-isl -polly-ast-detect-parallel -S -polly-codegen-scev < %s | FileCheck %s -check-prefix=PARALLEL-SCEV
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+target triple = "x86_64-pc-linux-gnu"
+
+; This is a trivially parallel loop. We just use it to ensure that we actually
+; emit the right information.
+;
+; for (i = 0; i < n; i++)
+;   A[i] = 1;
+;
+ at A = common global [1024 x i32] zeroinitializer
+define void @test-one(i64 %n) {
+start:
+  fence seq_cst
+  br label %loop.header
+
+loop.header:
+  %i = phi i64 [ 0, %start ], [ %i.next, %loop.backedge ]
+  %exitcond = icmp ne i64 %i, %n
+  br i1 %exitcond, label %loop.body, label %ret
+
+loop.body:
+  %scevgep = getelementptr [1024 x i32]* @A, i64 0, i64 %i
+  store i32 1, i32* %scevgep
+  br label %loop.backedge
+
+loop.backedge:
+  %i.next = add nsw i64 %i, 1
+  br label %loop.header
+
+ret:
+  fence seq_cst
+  ret void
+}
+
+; SEQUENTIAL: @test-one
+; SEQUENTIAL-NOT: !llvm.mem.parallel_loop_access
+; SEQUENTIAL-NOT: !llvm.loop !0
+; SEQUENTIAL-SCEV: @test-one
+; SEQUENTIAL-SCEV-NOT: !llvm.mem.parallel_loop_access
+; SEQUENTIAL-SCEV-NOT: !llvm.loop
+
+; PARALLEL: @test-one
+; PARALLEL: store i32 1, i32* %p_scevgep, !llvm.mem.parallel_loop_access !0
+; PARALLEL:  br i1 %polly.loop_cond, label %polly.loop_header, label %polly.loop_exit, !llvm.loop !0
+; PARALLEL-SCEV: @test-one
+; PARALLEL-SCEV: store i32 1, i32* %scevgep1, !llvm.mem.parallel_loop_access !0
+; PARALLEL-SCEV:  br i1 %polly.loop_cond, label %polly.loop_header, label %polly.loop_exit, !llvm.loop !0
+
+; This loop has memory dependences that require at least a simple dependence
+; analysis to detect the parallelism.
+;
+; for (i = 0; i < n; i++)
+;   A[2 * i] = A[2 * i + 1];
+;
+define void @test-two(i64 %n) {
+start:
+  fence seq_cst
+  br label %loop.header
+
+loop.header:
+  %i = phi i64 [ 0, %start ], [ %i.next, %loop.backedge ]
+  %exitcond = icmp ne i64 %i, %n
+  br i1 %exitcond, label %loop.body, label %ret
+
+loop.body:
+  %loadoffset1 = mul nsw i64 %i, 2
+  %loadoffset2 = add nsw i64 %loadoffset1, 1
+  %scevgepload = getelementptr [1024 x i32]* @A, i64 0, i64 %loadoffset2
+  %val = load i32* %scevgepload
+  %storeoffset = mul i64 %i, 2
+  %scevgepstore = getelementptr [1024 x i32]* @A, i64 0, i64 %storeoffset
+  store i32 %val, i32* %scevgepstore
+  br label %loop.backedge
+
+loop.backedge:
+  %i.next = add nsw i64 %i, 1
+  br label %loop.header
+
+ret:
+  fence seq_cst
+  ret void
+}
+
+; SEQUENTIAL: @test-two
+; SEQUENTIAL-NOT: !llvm.mem.parallel_loop_access
+; SEQUENTIAL-NOT: !llvm.loop !0
+; SEQUENTIAL-SCEV: @test-two
+; SEQUENTIAL-SCEV-NOT: !llvm.mem.parallel_loop_access
+; SEQUENTIAL-SCEV-NOT: !llvm.loop
+
+; PARALLEL: @test-two
+; PARALLEL: %val_p_scalar_ = load i32* %p_scevgepload, !llvm.mem.parallel_loop_access !1
+; PARALLEL: store i32 %val_p_scalar_, i32* %p_scevgepstore, !llvm.mem.parallel_loop_access !1
+; PARALLEL: br i1 %polly.loop_cond, label %polly.loop_header, label %polly.loop_exit, !llvm.loop !1
+; PARALLEL-SCEV: @test-two
+; PARALLEL-SCEV: %val_p_scalar_ = load i32* %scevgep, !llvm.mem.parallel_loop_access !1
+; PARALLEL-SCEV: store i32 %val_p_scalar_, i32* %scevgep1, !llvm.mem.parallel_loop_access !1
+; PARALLEL-SCEV:  br i1 %polly.loop_cond, label %polly.loop_header, label %polly.loop_exit, !llvm.loop !1





More information about the llvm-commits mailing list