Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions llvm/include/llvm/Transforms/Scalar/LoopNestTutorial.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//===- LoopNestTutorial.h - Loop Nest Tutorial Pass -------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file contains a small loop nest pass to be used to illustrate several
// aspects about writing a loop nest optimization. It was developed as part of
// the "How to utilize LoopNest pass" tutorial, presented at LLVM Devepeloper's
// Conference, 2021.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_TRANSFORMS_SCALAR_LOOPNESTTUTORIAL_H
#define LLVM_TRANSFORMS_SCALAR_LOOPNESTTUTORIAL_H

#include "llvm/Transforms/Scalar/LoopPassManager.h"

namespace llvm {

// Creating a LoopNest pass is almost the same as creating a Loop pass.
class LoopNestTutorialPass : public PassInfoMixin<LoopNestTutorialPass> {
public:
LoopNestTutorialPass() = default;

// One difference: note that the run method takes a LoopNest object rather
// than a Loop.
PreservedAnalyses run(LoopNest &LN, LoopAnalysisManager &LAM,
LoopStandardAnalysisResults &AR, LPMUpdater &U);
};

} // end namespace llvm

#endif // LLVM_TRANSFORMS_SCALAR_LOOPNESTTUTORIAL_H
1 change: 1 addition & 0 deletions llvm/lib/Passes/PassBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@
#include "llvm/Transforms/Scalar/LoopInstSimplify.h"
#include "llvm/Transforms/Scalar/LoopInterchange.h"
#include "llvm/Transforms/Scalar/LoopLoadElimination.h"
#include "llvm/Transforms/Scalar/LoopNestTutorial.h"
#include "llvm/Transforms/Scalar/LoopPassManager.h"
#include "llvm/Transforms/Scalar/LoopPredication.h"
#include "llvm/Transforms/Scalar/LoopReroll.h"
Expand Down
5 changes: 4 additions & 1 deletion llvm/lib/Passes/PassBuilderPipelines.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
#include "llvm/Transforms/Scalar/LoopInstSimplify.h"
#include "llvm/Transforms/Scalar/LoopInterchange.h"
#include "llvm/Transforms/Scalar/LoopLoadElimination.h"
#include "llvm/Transforms/Scalar/LoopNestTutorial.h"
#include "llvm/Transforms/Scalar/LoopPassManager.h"
#include "llvm/Transforms/Scalar/LoopRotation.h"
#include "llvm/Transforms/Scalar/LoopSimplifyCFG.h"
Expand Down Expand Up @@ -293,8 +294,10 @@ PassBuilder::buildO1FunctionSimplificationPipeline(OptimizationLevel Level,

LPM2.addPass(LoopDeletionPass());

if (EnableLoopInterchange)
if (EnableLoopInterchange) {
LPM2.addPass(LoopNestTutorialPass());
LPM2.addPass(LoopInterchangePass());
}

// Do not enable unrolling in PreLinkThinLTO phase during sample PGO
// because it changes IR to makes profile annotation in back compile
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Passes/PassRegistry.def
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,7 @@ FUNCTION_PASS_WITH_PARAMS("print<stack-lifetime>",
LOOPNEST_PASS("lnicm", LNICMPass())
LOOPNEST_PASS("loop-flatten", LoopFlattenPass())
LOOPNEST_PASS("loop-interchange", LoopInterchangePass())
LOOPNEST_PASS("loop-nest-tutorial", LoopNestTutorialPass())
LOOPNEST_PASS("loop-unroll-and-jam", LoopUnrollAndJamPass())
LOOPNEST_PASS("no-op-loopnest", NoOpLoopNestPass())
#undef LOOPNEST_PASS
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Transforms/Scalar/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ add_llvm_component_library(LLVMScalarOpts
LoopInterchange.cpp
LoopFlatten.cpp
LoopLoadElimination.cpp
LoopNestTutorial.cpp
LoopPassManager.cpp
LoopPredication.cpp
LoopRerollPass.cpp
Expand Down
77 changes: 77 additions & 0 deletions llvm/lib/Transforms/Scalar/LoopNestTutorial.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
//===- LoopNestTutorial.cpp - Loop Nest Tutorial Pass ---------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This pass interchanges perfect loop nest with loop depth two.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/Scalar/LoopNestTutorial.h"
#include "llvm/IR/Verifier.h"

using namespace llvm;

#define DEBUG_TYPE "loop-nest-tutorial"

// This class will contain the main transformation code.
class LoopNestTutorial {
public:
LoopNestTutorial(LoopInfo *LI, DominatorTree *DT) : LI(LI), DT(DT) {}

bool run(LoopNest &LN) const {
LLVM_DEBUG(dbgs() << "Entering LoopNestTutorial::run\n");
LLVM_DEBUG(
dbgs() << "TODO: Need to check if LoopNest is a valid candidate\n");
(void)LI;
(void)DT;
return false;
}

private:
LoopInfo *LI = nullptr;
DominatorTree *DT = nullptr;
};

// Verify that the transformation preserved correctness of analysis data
// structures, and proper function code structure.
static void verify(const LoopInfo &LI, const DominatorTree &DT) {
Function &F = *(*LI.begin())->getHeader()->getParent();
assert(!verifyFunction(F, &errs()) && "Incorrect Function");
assert(DT.verify() && "Incorrect DT");
LI.verify(DT);
}

PreservedAnalyses LoopNestTutorialPass::run(LoopNest &LN,
LoopAnalysisManager &LAM,
LoopStandardAnalysisResults &AR,
LPMUpdater &U) {

LLVM_DEBUG(dbgs() << "Entering LoopNestTutorialPass::run\n");

// The implementation of the pass run method is simpler.
// If we were using a function pass we would have to write code to simplify
// the loop, and create a loop nest object. Example:
// auto *DT = &AM.getResult<DominatorTreeAnalysis>(F);
// auto *LI = &AM.getResult<LoopAnalysis>(F);
// auto *SE = &AM.getResult<ScalarEvolutionAnalysis>(F);
// bool Simplified = false;
// for (const auto *L : *LI) {
// Simplified |= simplifyLoop(L, DT, LI, SE, nullptr, nullptr, true);
// LoopNest LN(*L, *SE);
// ...
// }

LLVM_DEBUG(dbgs() << "LoopNest: " << LN << "\n");
bool Changed = LoopNestTutorial(&AR.LI, &AR.DT).run(LN);

if (!Changed)
return PreservedAnalyses::all();

verify(AR.LI, AR.DT);

return getLoopPassPreservedAnalyses();
}
33 changes: 33 additions & 0 deletions llvm/test/Transforms/LoopNestTutorial/loop_nest.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
; RUN: opt -passes='loop-nest-tutorial' -debug-only=loop-nest-tutorial -S < %s 2>&1 | FileCheck %s
; REQUIRES: asserts

; CHECK: Entering LoopNestTutorialPass::run
; CHECK-NEXT: LoopNest: IsPerfect=true, Depth=2, OutermostLoop: header.outer, Loops: ( header.outer header.inner )
; CHECK-NEXT: Entering LoopNestTutorial::run
; CHECK-NEXT: TODO: Need to check if LoopNest is a valid candidate

define void @perfectloopnest() {
preheader.outer:
br label %header.outer

header.outer:
%i = phi i32 [ 0, %preheader.outer ], [ %inc.outer, %latch.outer ]
br label %header.inner

header.inner:
%j = phi i32 [ 0, %header.outer ], [ %inc.inner, %header.inner ]
call void @foo(i32 %i, i32 %j)
%inc.inner = add nsw i32 %j, 1
%cmp.inner = icmp slt i32 %inc.inner, 100
br i1 %cmp.inner, label %header.inner, label %latch.outer

latch.outer:
%inc.outer = add nsw i32 %i, 1
%cmp.outer = icmp slt i32 %inc.outer, 100
br i1 %cmp.outer, label %header.outer, label %exit.outer

exit.outer:
ret void
}

declare void @foo(i32, i32)