[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