diff --git a/llvm/compiler-course/llvm-ir/plekhanov_pass_pure/CMakeLists.txt b/llvm/compiler-course/llvm-ir/plekhanov_pass_pure/CMakeLists.txt new file mode 100644 index 0000000000000..d6be29c33b99b --- /dev/null +++ b/llvm/compiler-course/llvm-ir/plekhanov_pass_pure/CMakeLists.txt @@ -0,0 +1,14 @@ +set(Title "PureFunc") +set(Student "Plekhanov_Daniil") +set(Group "FIIT2") +set(TARGET_NAME "${Title}_${Student}_${Group}_LLVM_IR") + +if (NOT WIN32 AND NOT CYGWIN) + file(GLOB_RECURSE SOURCES *.cpp *.h *.hpp) + add_llvm_pass_plugin(${TARGET_NAME} ${SOURCES} + DEPENDS + intrinsics_gen + BUILDTREE_ONLY + ) + set(LLVM_TEST_DEPENDS ${TARGET_NAME} ${LLVM_TEST_DEPENDS} PARENT_SCOPE) +endif() diff --git a/llvm/compiler-course/llvm-ir/plekhanov_pass_pure/plekhanov.cpp b/llvm/compiler-course/llvm-ir/plekhanov_pass_pure/plekhanov.cpp new file mode 100644 index 0000000000000..d68a27e426f22 --- /dev/null +++ b/llvm/compiler-course/llvm-ir/plekhanov_pass_pure/plekhanov.cpp @@ -0,0 +1,37 @@ +#include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" +#include "llvm/Passes/PassBuilder.h" +#include "llvm/Passes/PassPlugin.h" + +namespace { +struct PureFunctionPass : llvm::PassInfoMixin { + llvm::PreservedAnalyses run(llvm::Function &F, + llvm::FunctionAnalysisManager &) { + for (auto &BB : F) + for (auto &I : BB) + if (I.mayReadOrWriteMemory()) + return llvm::PreservedAnalyses::none(); + + F.addFnAttr("pure"); + return llvm::PreservedAnalyses::none(); + } + + static bool isRequired() { return true; } +}; +} // namespace + +extern "C" LLVM_ATTRIBUTE_WEAK llvm::PassPluginLibraryInfo +llvmGetPassPluginInfo() { + return {LLVM_PLUGIN_API_VERSION, "PureFunctionPass", "0.1", + [](llvm::PassBuilder &PB) { + PB.registerPipelineParsingCallback( + [](llvm::StringRef Name, llvm::FunctionPassManager &FPM, + llvm::ArrayRef) { + if (Name == "pure-func-pass") { + FPM.addPass(PureFunctionPass{}); + return true; + } + return false; + }); + }}; +} \ No newline at end of file diff --git a/llvm/test/compiler-course/plekhanov_pass_pure/test.ll b/llvm/test/compiler-course/plekhanov_pass_pure/test.ll new file mode 100644 index 0000000000000..b34d05e934793 --- /dev/null +++ b/llvm/test/compiler-course/plekhanov_pass_pure/test.ll @@ -0,0 +1,66 @@ +; RUN: opt -load-pass-plugin %llvmshlibdir/PureFunc_Plekhanov_Daniil_FIIT2_LLVM_IR%pluginext\ +; RUN: -passes=pure-func-pass -S %s | FileCheck %s + +; int mul(int a, int b) { return a * b; } +; CHECK: define i32 @_Z3muli(i32 %a, i32 %b) #0 +define i32 @_Z3muli(i32 %a, i32 %b) { +entry: + %res = mul i32 %a, %b + ret i32 %res +} + +@counter = global i32 0 + +; void inc() { counter++; } +; CHECK: define void @_Z3incv() +; CHECK-NOT: #0 +define void @_Z3incv() { +entry: + %val = load i32, ptr @counter + %inc = add i32 %val, 1 + store i32 %inc, ptr @counter + ret void +} + +; int identity(int x) { return x; } +; CHECK: define i32 @_Z8identityi(i32 %x) #0 +define i32 @_Z8identityi(i32 %x) { +entry: + ret i32 %x +} + +declare void @external_impure() + +; void wrapper() { external_impure(); } +; CHECK: define void @_Z7wrapperv() +; CHECK-NOT: #0 +define void @_Z7wrapperv() { +entry: + call void @external_impure() + ret void +} + +; int abs(int x) { return x < 0 ? -x : x; } +; CHECK: define i32 @_Z3absi(i32 %x) #0 +define i32 @_Z3absi(i32 %x) { +entry: + %cmp = icmp slt i32 %x, 0 + %neg = sub i32 0, %x + %res = select i1 %cmp, i32 %neg, i32 %x + ret i32 %res +} + +@gptr = global ptr null + +; int read_gptr() { return ptrtoint(ptr @gptr to i32); } +; CHECK: define i32 @_Z9read_gptrv() +; CHECK-NOT: #0 +define i32 @_Z9read_gptrv() { +entry: + %p = load ptr, ptr @gptr + %i = ptrtoint ptr %p to i32 + ret i32 %i +} + +; CHECK: attributes #0 = { "pure" } +attributes #0 = { "pure" }