This repository has been archived by the owner on Jan 19, 2025. It is now read-only.
forked from NN-complr-tech/llvm
-
Notifications
You must be signed in to change notification settings - Fork 59
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Реализован плагин и тесты по задаче: Найти все циклы внутри функции и обернуть их в вызовы loop_start()/loop_end(). Можно использовать Loop Analysis.
- Loading branch information
Showing
3 changed files
with
347 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
set(PluginName AtikinLoopPass) | ||
|
||
file(GLOB_RECURSE ALL_SOURCE_FILES *.cpp *.h) | ||
|
||
if (NOT WIN32 AND NOT CYGWIN) | ||
add_llvm_pass_plugin(${PluginName} | ||
${ALL_SOURCE_FILES} | ||
DEPENDS | ||
intrinsics_gen | ||
BUILDTREE_ONLY | ||
) | ||
|
||
set(LLVM_TEST_DEPENDS ${PluginName} ${LLVM_TEST_DEPENDS} PARENT_SCOPE) | ||
endif() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
#include "llvm/ADT/ArrayRef.h" | ||
#include "llvm/ADT/SmallVector.h" | ||
#include "llvm/IR/Function.h" | ||
#include "llvm/IR/IRBuilder.h" | ||
#include "llvm/IR/PassManager.h" | ||
#include "llvm/Pass.h" | ||
#include "llvm/Passes/PassBuilder.h" | ||
#include "llvm/Passes/PassPlugin.h" | ||
|
||
using namespace llvm; | ||
|
||
class MyLoopPass : public PassInfoMixin<MyLoopPass> { | ||
public: | ||
PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM) { | ||
auto *Ty = FunctionType::get(llvm::Type::getVoidTy(F.getContext()), | ||
false); // get func type | ||
auto *M = F.getParent(); | ||
|
||
auto LoopStartFunc = M->getOrInsertFunction("_Z10loop_startv", | ||
Ty); // get or create func start | ||
auto LoopEndFunc = | ||
M->getOrInsertFunction("_Z8loop_endv", Ty); // get or create func end | ||
|
||
auto &LI = FAM.getResult<LoopAnalysis>(F); | ||
|
||
for (auto &L : LI) { // for by loop | ||
auto *Preheader = | ||
L->getLoopPreheader(); // get preheader block of the loop | ||
|
||
SmallVector<BasicBlock *, 1> ExitBlocks; | ||
L->getExitBlocks(ExitBlocks); | ||
|
||
if (!Preheader || ExitBlocks.empty()) | ||
continue; | ||
|
||
int loop_start_inside = 0; | ||
int loop_end_inside = 0; | ||
|
||
for (Instruction &Instr : *Preheader) { | ||
if (CallInst *CI = dyn_cast<CallInst>(&Instr)) { | ||
if (CI->getCalledFunction() && | ||
CI->getCalledFunction()->getName() == "_Z10loop_startv") { | ||
loop_start_inside = 1; | ||
break; | ||
} | ||
} | ||
} | ||
|
||
IRBuilder<> Builder(Preheader->getTerminator()); // api for basic block | ||
|
||
if (!loop_start_inside) | ||
Builder.CreateCall(LoopStartFunc); // paste loop_start | ||
|
||
for (auto &ExitBlock : ExitBlocks) { | ||
loop_end_inside = 0; | ||
for (Instruction &Instr : *ExitBlock) { | ||
if (CallInst *CI = dyn_cast<CallInst>(&Instr)) { | ||
if (CI->getCalledFunction() && | ||
CI->getCalledFunction()->getName() == "_Z8loop_endv") { | ||
loop_end_inside = 1; | ||
break; | ||
} | ||
} | ||
} | ||
Builder.SetInsertPoint( | ||
ExitBlock->getFirstNonPHI()); // set pointer to exit block | ||
|
||
if (!loop_end_inside) | ||
Builder.CreateCall(LoopEndFunc); // paste loop_start | ||
} | ||
} | ||
return PreservedAnalyses::all(); | ||
} | ||
}; | ||
|
||
/* New PM Registration */ | ||
llvm::PassPluginLibraryInfo getAtikinLoopPassPluginInfo() { | ||
return {LLVM_PLUGIN_API_VERSION, "AtikinLoopPass", LLVM_VERSION_STRING, | ||
[](llvm::PassBuilder &PB) { | ||
PB.registerPipelineParsingCallback( | ||
[](llvm::StringRef Name, llvm::FunctionPassManager &PM, | ||
llvm::ArrayRef<llvm::PassBuilder::PipelineElement>) { | ||
if (Name == "ivanov-loop-pass") { | ||
PM.addPass(MyLoopPass()); | ||
return true; | ||
} | ||
return false; | ||
}); | ||
}}; | ||
} | ||
|
||
extern "C" LLVM_ATTRIBUTE_WEAK ::llvm::PassPluginLibraryInfo | ||
llvmGetPassPluginInfo() { | ||
return getAtikinLoopPassPluginInfo(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,238 @@ | ||
; RUN: opt -load-pass-plugin=%llvmshlibdir/AtikinLoopPass%shlibext -passes=ivanov-loop-pass -S %s | FileCheck %s | ||
|
||
; void foo(int n, int m) { | ||
; int c0; | ||
; int c1; | ||
; for (c0 = n; c0 > 0; c0--) { | ||
; c1++; | ||
; } | ||
; } | ||
|
||
; void while_test(){ | ||
; int i = 0; | ||
; while(i < 10){ | ||
; i++; | ||
; } | ||
; } | ||
|
||
; void do_while_test(){ | ||
; int i = 0; | ||
; do { | ||
; i++; | ||
; } while(i < 10); | ||
; } | ||
|
||
; void no_loop(){ | ||
; int a = 2; | ||
; if (a > 0){ | ||
; a = 0; | ||
; } else { | ||
; a = 10; | ||
; } | ||
; } | ||
|
||
; void loop_start(); | ||
; void loop_end(); | ||
|
||
; void with_lopps_func(){ | ||
; int i = 0; | ||
; loop_start(); | ||
; while(i < 10){ | ||
; i++; | ||
; } | ||
; loop_end(); | ||
; } | ||
|
||
; void LoopWithRet(int &a) { | ||
; int i = 0; | ||
; while(i < 100){ | ||
; i++; | ||
; if (i > 10) { | ||
; return; | ||
; } | ||
; a = a + i; | ||
; } | ||
; a *= i -1; | ||
; return; | ||
; } | ||
|
||
define dso_local void @_Z3fooii(i32 noundef %n, i32 noundef %m) { | ||
entry: | ||
%n.addr = alloca i32, align 4 | ||
%m.addr = alloca i32, align 4 | ||
%c0 = alloca i32, align 4 | ||
%c1 = alloca i32, align 4 | ||
store i32 %n, ptr %n.addr, align 4 | ||
store i32 %m, ptr %m.addr, align 4 | ||
%0 = load i32, ptr %n.addr, align 4 | ||
store i32 %0, ptr %c0, align 4 | ||
; CHECK: call void @_Z10loop_startv() | ||
br label %for.cond | ||
|
||
for.cond: | ||
%1 = load i32, ptr %c0, align 4 | ||
%cmp = icmp sgt i32 %1, 0 | ||
br i1 %cmp, label %for.body, label %for.end | ||
|
||
for.body: | ||
%2 = load i32, ptr %c1, align 4 | ||
%inc = add nsw i32 %2, 1 | ||
store i32 %inc, ptr %c1, align 4 | ||
br label %for.inc | ||
|
||
for.inc: | ||
%3 = load i32, ptr %c0, align 4 | ||
%dec = add nsw i32 %3, -1 | ||
store i32 %dec, ptr %c0, align 4 | ||
br label %for.cond | ||
|
||
for.end: | ||
; CHECK: call void @_Z8loop_endv() | ||
ret void | ||
} | ||
|
||
define dso_local void @_Z10while_testv() { | ||
entry: | ||
%i = alloca i32, align 4 | ||
store i32 0, ptr %i, align 4 | ||
; CHECK: call void @_Z10loop_startv() | ||
br label %while.cond | ||
|
||
while.cond: | ||
%0 = load i32, ptr %i, align 4 | ||
%cmp = icmp slt i32 %0, 10 | ||
br i1 %cmp, label %while.body, label %while.end | ||
|
||
while.body: | ||
%1 = load i32, ptr %i, align 4 | ||
%inc = add nsw i32 %1, 1 | ||
store i32 %inc, ptr %i, align 4 | ||
br label %while.cond | ||
|
||
while.end: | ||
; CHECK: call void @_Z8loop_endv() | ||
ret void | ||
} | ||
|
||
define dso_local void @_Z13do_while_testv() { | ||
entry: | ||
%i = alloca i32, align 4 | ||
store i32 0, ptr %i, align 4 | ||
; CHECK: call void @_Z10loop_startv() | ||
br label %do.body | ||
|
||
do.body: | ||
%0 = load i32, ptr %i, align 4 | ||
%inc = add nsw i32 %0, 1 | ||
store i32 %inc, ptr %i, align 4 | ||
br label %do.cond | ||
|
||
do.cond: | ||
%1 = load i32, ptr %i, align 4 | ||
%cmp = icmp slt i32 %1, 10 | ||
br i1 %cmp, label %do.body, label %do.end | ||
|
||
do.end: | ||
; CHECK: call void @_Z8loop_endv() | ||
ret void | ||
} | ||
|
||
define dso_local void @_Z7no_loopv() { | ||
entry: | ||
%a = alloca i32, align 4 | ||
store i32 2, ptr %a, align 4 | ||
%0 = load i32, ptr %a, align 4 | ||
; CHECK-NOT: call void @_Z10loop_startv() | ||
%cmp = icmp sgt i32 %0, 0 | ||
br i1 %cmp, label %if.then, label %if.else | ||
|
||
if.then: | ||
store i32 0, ptr %a, align 4 | ||
br label %if.end | ||
|
||
if.else: | ||
store i32 10, ptr %a, align 4 | ||
br label %if.end | ||
|
||
if.end: | ||
; CHECK-NOT: call void @_Z8loop_endv() | ||
ret void | ||
} | ||
|
||
define dso_local void @_Z15with_lopps_funcv() { | ||
entry: | ||
%i = alloca i32, align 4 | ||
store i32 0, ptr %i, align 4 | ||
; CHECK: call void @_Z10loop_startv() | ||
; CHECK-NOT: call void @_Z10loop_startv() | ||
br label %while.cond | ||
|
||
while.cond: | ||
%0 = load i32, ptr %i, align 4 | ||
%cmp = icmp slt i32 %0, 10 | ||
br i1 %cmp, label %while.body, label %while.end | ||
|
||
while.body: | ||
%1 = load i32, ptr %i, align 4 | ||
%inc = add nsw i32 %1, 1 | ||
store i32 %inc, ptr %i, align 4 | ||
br label %while.cond | ||
|
||
while.end: | ||
; CHECK: call void @_Z8loop_endv() | ||
; CHECK-NOT: call void @_Z8loop_endv() | ||
ret void | ||
} | ||
|
||
declare dso_local void @_Z10loop_startv() | ||
|
||
declare dso_local void @_Z8loop_endv() | ||
|
||
define dso_local void @_Z11LoopWithRetRi(ptr noundef nonnull align 4 dereferenceable(4) %a) { | ||
entry: | ||
%a.addr = alloca ptr, align 8 | ||
%i = alloca i32, align 4 | ||
store ptr %a, ptr %a.addr, align 8 | ||
store i32 0, ptr %i, align 4 | ||
; CHECK: call void @_Z10loop_startv() | ||
br label %while.cond | ||
|
||
while.cond: | ||
%0 = load i32, ptr %i, align 4 | ||
%cmp = icmp slt i32 %0, 100 | ||
br i1 %cmp, label %while.body, label %while.end | ||
|
||
while.body: | ||
%1 = load i32, ptr %i, align 4 | ||
%inc = add nsw i32 %1, 1 | ||
store i32 %inc, ptr %i, align 4 | ||
%2 = load i32, ptr %i, align 4 | ||
%cmp1 = icmp sgt i32 %2, 10 | ||
br i1 %cmp1, label %if.then, label %if.end | ||
|
||
if.then: | ||
; CHECK: call void @_Z8loop_endv() | ||
br label %return | ||
|
||
if.end: | ||
%3 = load ptr, ptr %a.addr, align 8 | ||
%4 = load i32, ptr %3, align 4 | ||
%5 = load i32, ptr %i, align 4 | ||
%add = add nsw i32 %4, %5 | ||
%6 = load ptr, ptr %a.addr, align 8 | ||
store i32 %add, ptr %6, align 4 | ||
br label %while.cond | ||
|
||
while.end: | ||
; CHECK: call void @_Z8loop_endv() | ||
%7 = load i32, ptr %i, align 4 | ||
%sub = sub nsw i32 %7, 1 | ||
%8 = load ptr, ptr %a.addr, align 8 | ||
%9 = load i32, ptr %8, align 4 | ||
%mul = mul nsw i32 %9, %sub | ||
store i32 %mul, ptr %8, align 4 | ||
br label %return | ||
|
||
return: | ||
ret void | ||
} |