diff --git a/clang/labs/lab1/levashov_evgeniy/AlwaysInline.cpp b/clang/labs/lab1/levashov_evgeniy/AlwaysInline.cpp new file mode 100644 index 0000000000000..b71d30b628092 --- /dev/null +++ b/clang/labs/lab1/levashov_evgeniy/AlwaysInline.cpp @@ -0,0 +1,91 @@ +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendPluginRegistry.h" +#include "llvm/Support/raw_ostream.h" + +namespace { +class AlwaysInlineVisitor + : public clang::RecursiveASTVisitor { +public: + explicit AlwaysInlineVisitor(clang::ASTContext *context_) + : context(context_) {} + bool VisitFunctionDecl(clang::FunctionDecl *decl) { + if (decl->isFunctionOrFunctionTemplate() && + !decl->hasAttr()) { + auto body = decl->getBody(); + if (body && !containsConditionalStatement(body)) { + auto loc = decl->getSourceRange(); + if (loc.isValid()) { + decl->addAttr( + clang::AlwaysInlineAttr::Create(*context, loc.getBegin())); + } + } + } + return true; + } + +private: + bool containsConditionalStatement(clang::Stmt *statement) { + if (!statement) { + return false; + } + + if (llvm::isa(statement) || llvm::isa(statement) || + llvm::isa(statement) || llvm::isa(statement) || + llvm::isa(statement)) { + return true; + } + + for (clang::Stmt *Child : statement->children()) { + if (containsConditionalStatement(Child)) { + return true; + } + } + + return false; + } + +private: + clang::ASTContext *context; +}; + +class AlwaysInlineConsumer : public clang::ASTConsumer { +public: + explicit AlwaysInlineConsumer(clang::ASTContext *сontext) + : visitor(сontext) {} + + bool HandleTopLevelDecl(clang::DeclGroupRef groupDecl) override { + for (clang::Decl *Decl : groupDecl) { + visitor.TraverseDecl(Decl); + } + return true; + } + +private: + AlwaysInlineVisitor visitor; +}; + +class AlwaysInlinePlugin final : public clang::PluginASTAction { +public: + std::unique_ptr + CreateASTConsumer(clang::CompilerInstance &ci, llvm::StringRef) override { + return std::make_unique(&ci.getASTContext()); + } + + bool ParseArgs(const clang::CompilerInstance &ci, + const std::vector &args) override { + for (const auto &arg : args) { + if (arg == "--help") { + llvm::outs() << "Applies the always_inline attribute to functions that " + "don't contain conditional statements\n"; + } + } + return true; + } +}; +} // namespace + +static clang::FrontendPluginRegistry::Add + X("always-inline", "Applies the always_inline attribute to functions that " + "don't contain conditional statements"); diff --git a/clang/labs/lab1/levashov_evgeniy/CMakeLists.txt b/clang/labs/lab1/levashov_evgeniy/CMakeLists.txt new file mode 100644 index 0000000000000..c7e45bf247b17 --- /dev/null +++ b/clang/labs/lab1/levashov_evgeniy/CMakeLists.txt @@ -0,0 +1,14 @@ +add_llvm_library(PluginAlwaysInlineLevashov MODULE AddAttrAlwaysInline.cpp PLUGIN_TOOL clang) + +if(WIN32 OR CYGWIN) + set(LLVM_LINK_COMPONENTS + Support + ) + clang_target_link_libraries(PluginAlwaysInlineLevashov PRIVATE + clangAST + clangBasic + clangFrontend + ) +endif() + +set(CLANG_TEST_DEPS "PluginAlwaysInlineLevashov" ${CLANG_TEST_DEPS} PARENT_SCOPE) diff --git a/clang/test/lab1/levashov_evgeniy/tests.cpp b/clang/test/lab1/levashov_evgeniy/tests.cpp new file mode 100644 index 0000000000000..ccc914f617144 --- /dev/null +++ b/clang/test/lab1/levashov_evgeniy/tests.cpp @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 -load %llvmshlibdir/PluginAlwaysInlineLevashov%pluginext\ +// RUN: -add-plugin always-inline %s\ +// RUN: -ast-dump %s -ast-dump-filter test | FileCheck %s + +namespace { +// CHECK: FunctionDecl {{0[xX][0-9a-fA-F]+ <.+tests\.cpp:([0-9]+:[0-9]|[0-9]+), (line|col):([0-9]+:[0-9]|[0-9]+)> (line|col):([0-9]+:[0-9]|[0-9]+) testMultiply 'int \(int, int\)'}} +// CHECK: `-AlwaysInlineAttr {{.* always_inline}} +int testMultiply(int valueOne, int valueTwo) { return valueOne * valueTwo; } + +// CHECK: FunctionDecl {{0[xX][0-9a-fA-F]+ <.+tests\.cpp:([0-9]+:[0-9]|[0-9]+), (line|col):([0-9]+:[0-9]|[0-9]+)> (line|col):([0-9]+:[0-9]|[0-9]+) testSum 'int \(int, int\)'}} +// CHECK: `-AlwaysInlineAttr {{.* always_inline}} +int testSum(int valueOne, int valueTwo) { + {} {} {{} {}} {} {{{}} {} {}} {} { + { return valueOne + valueTwo; } + } +} + +// CHECK: FunctionDecl {{0[xX][0-9a-fA-F]+ <.+tests\.cpp:([0-9]+:[0-9]|[0-9]+), (line|col):([0-9]+:[0-9]|[0-9]+)> (line|col):([0-9]+:[0-9]|[0-9]+) testEmptyFunc 'void \(\)'}} +// CHECK: `-AlwaysInlineAttr {{.* always_inline}} +void testEmptyFunc() { + {} {{}} {{} {} {{{{}}}}} {} +} + +// CHECK: FunctionDecl {{0[xX][0-9a-fA-F]+ <.+tests\.cpp:([0-9]+:[0-9]|[0-9]+), (line|col):([0-9]+:[0-9]|[0-9]+)> (line|col):([0-9]+:[0-9]|[0-9]+) testIfStmt 'bool \(int, int\)'}} +bool testIfStmt(int a, int b) { + if (a < b) + return true; + return false; +} +// CHECK-NOT: `-AlwaysInlineAttr {{0[xX][0-9a-fA-F]+ <(line|col):([0-9]+:[0-9]|[0-9]+)> Implicit always_inline}} + +// CHECK: FunctionDecl {{0[xX][0-9a-fA-F]+ <.+tests\.cpp:([0-9]+:[0-9]|[0-9]+), (line|col):([0-9]+:[0-9]|[0-9]+)> (line|col):([0-9]+:[0-9]|[0-9]+) testLoop 'void \(int\)'}} +void testLoop(int value) { + for (int i = 0; i < value; ++i) { + // do nothing + } +} +// CHECK-NOT: `-AlwaysInlineAttr {{0[xX][0-9a-fA-F]+ <(line|col):([0-9]+:[0-9]|[0-9]+)> Implicit always_inline}} +} // namespace + +// RUN: %clang_cc1 -load %llvmshlibdir/PluginAlwaysInlineLevashov%pluginext\ +// RUN: -plugin always-inline\ +// RUN: -plugin-arg-always-inline --help %s 2>&1 | FileCheck %s --check-prefix=CHECK-HELP +// CHECK-HELP: Applies the always_inline attribute to functions that don't contain conditional statements \ No newline at end of file diff --git a/llvm/labs/lab2/levashov_evgeniy/CMakeLists.txt b/llvm/labs/lab2/levashov_evgeniy/CMakeLists.txt new file mode 100644 index 0000000000000..5759348430140 --- /dev/null +++ b/llvm/labs/lab2/levashov_evgeniy/CMakeLists.txt @@ -0,0 +1,12 @@ +set(Plugin_Name "levashov_evgeniy_inline_pass") +if (NOT WIN32 AND NOT CYGWIN) + + file(GLOB_RECURSE ALL_SOURCE_FILES *.cpp *.h *.hpp) + add_llvm_pass_plugin( ${Plugin_Name} ${ALL_SOURCE_FILES} + DEPENDS intrinsics_gen BUILDTREE_ONLY) + set(LLVM_TEST_DEPENDS ${Plugin_Name} ${LLVM_TEST_DEPENDS} PARENT_SCOPE) + + message(STATUS "Plugin: ${Plugin_Name} -- BUILDED") +else() + message(STATUS "Plugin: ${Plugin_Name} -- NOT BUILT") +endif() diff --git a/llvm/labs/lab2/levashov_evgeniy/levashov_inline.cpp b/llvm/labs/lab2/levashov_evgeniy/levashov_inline.cpp new file mode 100644 index 0000000000000..2acecd6bbbe04 --- /dev/null +++ b/llvm/labs/lab2/levashov_evgeniy/levashov_inline.cpp @@ -0,0 +1,197 @@ +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/PassManager.h" +#include "llvm/Passes/PassBuilder.h" +#include "llvm/Passes/PassPlugin.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" +#include "llvm/Transforms/Utils/Cloning.h" +#include + +using namespace llvm; + +namespace { + +struct LevashovInlinePass : public PassInfoMixin { + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) { + std::vector callsToInline = findCallsToInline(F); + + if (callsToInline.empty()) + return PreservedAnalyses::all(); + + processCallSites(F, callsToInline); + + return PreservedAnalyses::none(); + } + + static bool isRequired() { return true; } + +private: + std::vector findCallsToInline(Function &F) { + std::vector callsToInline{}; + for (auto &BB : F) { + for (auto &I : BB) { + if (auto *CI = dyn_cast(&I)) { + if (Function *Callee = CI->getCalledFunction()) { + if (Callee->arg_size() == 0 && + Callee->getReturnType()->isVoidTy()) { + callsToInline.push_back(CI); + } + } + } + } + } + return callsToInline; + } + + void processCallSites(Function &F, std::vector &callsToInline) { + size_t counter_splited = 0; + size_t counter_inlined = 0; + + for (CallInst *CI : callsToInline) { + BasicBlock *InsertBB = CI->getParent(); + Instruction *InsertPt = CI->getNextNode(); + + DenseMap BlockMap; + Function *Callee = CI->getCalledFunction(); + ValueToValueMapTy VMap; + + BasicBlock *SplitBB = + splitBlockAtCallSite(InsertBB, InsertPt, counter_splited); + createNewBlocksForFunction(F, Callee, BlockMap, counter_inlined); + updateTerminatorOfInsertBB(InsertBB, Callee, BlockMap); + + copyInstructionsFromCallee(F, Callee, BlockMap, VMap); + updateBranchInstructions(F, BlockMap); + remapInstructions(Callee, BlockMap, VMap); + + handleReturnInstructions(F, SplitBB); + CI->eraseFromParent(); + moveSplitBBAfterNextBlock(F, SplitBB); + } + } + + BasicBlock *splitBlockAtCallSite(BasicBlock *InsertBB, Instruction *InsertPt, + size_t &counter_splited) { + return InsertBB->splitBasicBlock(InsertPt, + InsertBB->getName() + ".splited." + + std::to_string(counter_splited++)); + } + + void + createNewBlocksForFunction(Function &F, Function *Callee, + DenseMap &BlockMap, + size_t &counter_inlined) { + for (BasicBlock &CalleeBB : *Callee) { + BasicBlock *NewBB = BasicBlock::Create( + F.getContext(), + CalleeBB.getName() + ".inlined." + std::to_string(counter_inlined), + &F); + BlockMap[&CalleeBB] = NewBB; + } + counter_inlined++; + } + + void + updateTerminatorOfInsertBB(BasicBlock *InsertBB, Function *Callee, + DenseMap &BlockMap) { + InsertBB->getTerminator()->setSuccessor(0, + BlockMap[&Callee->getEntryBlock()]); + } + + void + copyInstructionsFromCallee(Function &F, Function *Callee, + DenseMap &BlockMap, + ValueToValueMapTy &VMap) { + for (BasicBlock &CalleeBB : *Callee) { + BasicBlock *NewBB = BlockMap[&CalleeBB]; + for (Instruction &Inst : CalleeBB) { + IRBuilder<> Builder(NewBB); + Instruction *NewInst = Inst.clone(); + Builder.Insert(NewInst); + VMap[&Inst] = NewInst; + } + } + } + + void + updateBranchInstructions(Function &F, + DenseMap &BlockMap) { + for (BasicBlock &CalleeBB : F) { + for (Instruction &Branch : CalleeBB) { + if (auto *BI = dyn_cast(&Branch)) { + for (size_t i = 0, e = BI->getNumSuccessors(); i != e; ++i) { + BasicBlock *Successor = BI->getSuccessor(i); + if (BlockMap[Successor] != nullptr) { + BI->setSuccessor(i, BlockMap[Successor]); + } + } + } + } + } + } + + void remapInstructions(Function *Callee, + DenseMap &BlockMap, + ValueToValueMapTy &VMap) { + for (BasicBlock &CalleeBB : *Callee) { + BasicBlock *NewBB = BlockMap[&CalleeBB]; + for (Instruction &Inst : *NewBB) { + RemapInstruction(&Inst, VMap, RF_IgnoreMissingLocals, nullptr, nullptr); + } + } + } + + void handleReturnInstructions(Function &F, BasicBlock *SplitBB) { + IRBuilder<> Builder(F.getContext()); + for (BasicBlock &BB : F) { + SmallVector ReturnInstructions; + for (Instruction &I : BB) { + if (auto *RI = dyn_cast(&I)) { + ReturnInstructions.push_back(RI); + } + } + + for (ReturnInst *RI : ReturnInstructions) { + if (RI->getParent() != SplitBB) { + RI->eraseFromParent(); + Builder.SetInsertPoint(&BB); + Builder.CreateBr(SplitBB); + } + } + } + } + + void moveSplitBBAfterNextBlock(Function &F, BasicBlock *SplitBB) { + Function::iterator it = F.begin(); + while (it != F.end() && &*it != SplitBB) { + ++it; + } + Function::iterator next_it{}; + while (it != F.end() && std::next(it) != F.end()) { + next_it = std::next(it++); + } + if (it != F.end()) + SplitBB->moveAfter(&*next_it); + } +}; + +} // end anonymous namespace + +extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK +llvmGetPassPluginInfo() { + return {LLVM_PLUGIN_API_VERSION, "LevashovInlinePass", "v0.1", + [](PassBuilder &PB) { + PB.registerPipelineParsingCallback( + [](StringRef Name, FunctionPassManager &FPM, + ArrayRef) { + if (Name == "levashov-inline") { + FPM.addPass(LevashovInlinePass()); + return true; + } + return false; + }); + }}; +} \ No newline at end of file diff --git a/llvm/lib/Target/X86/lab3/levashov_evgeniy/CMakeLists.txt b/llvm/lib/Target/X86/lab3/levashov_evgeniy/CMakeLists.txt new file mode 100644 index 0000000000000..f903eb4cebbe8 --- /dev/null +++ b/llvm/lib/Target/X86/lab3/levashov_evgeniy/CMakeLists.txt @@ -0,0 +1,13 @@ +set(PluginName X86LevashovPass) + +file(GLOB_RECURSE ALL_SOURCE_FILES *.cpp) +add_llvm_pass_plugin(${PluginName} + ${ALL_SOURCE_FILES} + DEPENDS + intrinsics_gen + X86 + BUILDTREE_ONLY) + +target_include_directories(${PluginName} PUBLIC ${PATH_TO_X86}) + +set(LLVM_TEST_DEPENDS ${PluginName} ${LLVM_TEST_DEPENDS} PARENT_SCOPE) diff --git a/llvm/lib/Target/X86/lab3/levashov_evgeniy/X86LevashovPass.cpp b/llvm/lib/Target/X86/lab3/levashov_evgeniy/X86LevashovPass.cpp new file mode 100644 index 0000000000000..fa99a51c6b6fe --- /dev/null +++ b/llvm/lib/Target/X86/lab3/levashov_evgeniy/X86LevashovPass.cpp @@ -0,0 +1,101 @@ +#include "X86.h" +#include "X86InstrInfo.h" +#include "X86Subtarget.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/IntrinsicsX86.h" +#include "llvm/Pass.h" +#include "llvm/Support/raw_ostream.h" + +#define PASS_NAME "x86-mul-add-levashov-pass" +#define PASS_DESC "x86-mul-add-levashov-pass" + +using namespace llvm; + +namespace { +class X86MulAddPass : public MachineFunctionPass { +public: + static char ID; + X86MulAddPass() : MachineFunctionPass(ID) {} + + bool runOnMachineFunction(MachineFunction &MF) override { + SmallVector deletedInstrPtr; + bool Changed = false; + + for (auto &MBB : MF) { + for (auto MI = MBB.begin(); MI != MBB.end(); ++MI) { + if (MI->getOpcode() == X86::MULPDrr) { + Register Reg = MI->getOperand(0).getReg(); + Changed |= processMulAddPair(MF, MBB, MI, Reg, deletedInstrPtr); + } + } + } + + for (auto it : deletedInstrPtr) + it->eraseFromParent(); + + return Changed; + } + +private: + bool processMulAddPair(MachineFunction &MF, MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, Register Reg, + SmallVectorImpl &deletedInstrPtr) { + for (auto NextMI = std::next(MI); NextMI != MBB.end(); ++NextMI) { + if (NextMI->getOpcode() == X86::ADDPDrr) { + if (NextMI->getOperand(1).getReg() == Reg || + NextMI->getOperand(2).getReg() == Reg) { + bool hasDependency = checkDependency(MBB, NextMI, Reg); + if (!hasDependency) { + createVFMADD213PDr(MF, MBB, MI, NextMI, Reg, deletedInstrPtr); + return true; + } + break; + } + } else if (hasOperand(NextMI, Reg)) { + break; + } + } + return false; + } + + bool checkDependency(const MachineBasicBlock &MBB, + MachineBasicBlock::iterator NextMI, Register Reg) { + if (NextMI->getOperand(0).getReg() != Reg) { + for (auto CheckMI = std::next(NextMI); CheckMI != MBB.end(); ++CheckMI) { + if (hasOperand(CheckMI, Reg)) + return true; + } + } + return false; + } + + bool hasOperand(MachineBasicBlock::iterator MI, Register Reg) { + for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { + if (MI->getOperand(i).getReg() == Reg) + return true; + } + return false; + } + + void createVFMADD213PDr(MachineFunction &MF, MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + MachineBasicBlock::iterator NextMI, Register Reg, + SmallVectorImpl &deletedInstrPtr) { + MachineInstrBuilder BuilderMI = + BuildMI(MBB, MI, MI->getDebugLoc(), + MF.getSubtarget().getInstrInfo()->get(X86::VFMADD213PDr)); + BuilderMI.addReg(NextMI->getOperand(0).getReg(), RegState::Define); + BuilderMI.addReg(MI->getOperand(1).getReg()); + BuilderMI.addReg(MI->getOperand(2).getReg()); + BuilderMI.addReg(NextMI->getOperand(2).getReg()); + deletedInstrPtr.push_back(&*MI); + deletedInstrPtr.push_back(&*NextMI); + } +}; +} // namespace + +char X86MulAddPass::ID = 0; +static RegisterPass X(PASS_NAME, PASS_DESC); diff --git a/llvm/test/lab2/levashov_evgeniy/test.ll b/llvm/test/lab2/levashov_evgeniy/test.ll new file mode 100644 index 0000000000000..b092dfa600182 --- /dev/null +++ b/llvm/test/lab2/levashov_evgeniy/test.ll @@ -0,0 +1,466 @@ +; RUN: opt -load-pass-plugin %llvmshlibdir/levashov_evgeniy_inline_pass%pluginext\ +; RUN: -passes=levashov-inline -S %s | FileCheck %s + + +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; COM: Expected inline + +; void func() { +; int a[] = {1, 2, 3}; +; int sum = 0; +; for (int i = 0; i < 3; ++i) { +; sum += a[i]; +; } +; } +; +; int myfoo(int a, int b) { +; a++; +; b++; +; func(); +; return a + b; +; } + +@__const._Z4funcv.a = private unnamed_addr constant [3 x i32] [i32 1, i32 2, i32 3], align 4 + +; Function Attrs: mustprogress noinline nounwind optnone uwtable +define dso_local void @_Z4funcv() #0 { +entry: + %a = alloca [3 x i32], align 4 + %sum = alloca i32, align 4 + %i = alloca i32, align 4 + call void @llvm.memcpy.p0.p0.i64(ptr align 4 %a, ptr align 4 @__const._Z4funcv.a, i64 12, i1 false) + store i32 0, ptr %sum, align 4 + store i32 0, ptr %i, align 4 + br label %for.cond + +for.cond: ; preds = %for.inc, %entry + %0 = load i32, ptr %i, align 4 + %cmp = icmp slt i32 %0, 3 + br i1 %cmp, label %for.body, label %for.end + +for.body: ; preds = %for.cond + %1 = load i32, ptr %i, align 4 + %idxprom = sext i32 %1 to i64 + %arrayidx = getelementptr inbounds [3 x i32], ptr %a, i64 0, i64 %idxprom + %2 = load i32, ptr %arrayidx, align 4 + %3 = load i32, ptr %sum, align 4 + %add = add nsw i32 %3, %2 + store i32 %add, ptr %sum, align 4 + br label %for.inc + +for.inc: ; preds = %for.body + %4 = load i32, ptr %i, align 4 + %inc = add nsw i32 %4, 1 + store i32 %inc, ptr %i, align 4 + br label %for.cond + +for.end: ; preds = %for.cond + ret void +} + +; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite) +declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg) #1 + +; Function Attrs: mustprogress noinline nounwind optnone uwtable +define dso_local noundef i32 @_Z5myfooii(i32 noundef %a, i32 noundef %b) #0 { +entry: + %a.addr = alloca i32, align 4 + %b.addr = alloca i32, align 4 + store i32 %a, ptr %a.addr, align 4 + store i32 %b, ptr %b.addr, align 4 + %0 = load i32, ptr %a.addr, align 4 + %inc = add nsw i32 %0, 1 + store i32 %inc, ptr %a.addr, align 4 + %1 = load i32, ptr %b.addr, align 4 + %inc1 = add nsw i32 %1, 1 + store i32 %inc1, ptr %b.addr, align 4 + call void @_Z4funcv() + %2 = load i32, ptr %a.addr, align 4 + %3 = load i32, ptr %b.addr, align 4 + %add = add nsw i32 %2, %3 + ret i32 %add +} + +; CHECK: define dso_local noundef i32 @_Z5myfooii(i32 noundef %a, i32 noundef %b) #0 { +; CHECK: entry: +; CHECK-NEXT: %a.addr = alloca i32, align 4 +; CHECK-NEXT: %b.addr = alloca i32, align 4 +; CHECK-NEXT: store i32 %a, ptr %a.addr, align 4 +; CHECK-NEXT: store i32 %b, ptr %b.addr, align 4 +; CHECK-NEXT: %0 = load i32, ptr %a.addr, align 4 +; CHECK-NEXT: %inc = add nsw i32 %0, 1 +; CHECK-NEXT: store i32 %inc, ptr %a.addr, align 4 +; CHECK-NEXT: %1 = load i32, ptr %b.addr, align 4 +; CHECK-NEXT: %inc1 = add nsw i32 %1, 1 +; CHECK-NEXT: store i32 %inc1, ptr %b.addr, align 4 +; CHECK-NEXT: br label %entry.inlined.0 +; CHECK-EMPTY: +; CHECK-NEXT: entry.inlined.0: ; preds = %entry +; CHECK-NEXT: %2 = alloca [3 x i32], align 4 +; CHECK-NEXT: %3 = alloca i32, align 4 +; CHECK-NEXT: %4 = alloca i32, align 4 +; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %2, ptr align 4 @__const._Z4funcv.a, i64 12, i1 false) +; CHECK-NEXT: store i32 0, ptr %3, align 4 +; CHECK-NEXT: store i32 0, ptr %4, align 4 +; CHECK-NEXT: br label %for.cond.inlined.0 +; CHECK-EMPTY: +; CHECK-NEXT: for.cond.inlined.0: ; preds = %for.inc.inlined.0, %entry.inlined.0 +; CHECK-NEXT: %5 = load i32, ptr %4, align 4 +; CHECK-NEXT: %6 = icmp slt i32 %5, 3 +; CHECK-NEXT: br i1 %6, label %for.body.inlined.0, label %for.end.inlined.0 +; CHECK-EMPTY: +; CHECK-NEXT: for.body.inlined.0: ; preds = %for.cond.inlined.0 +; CHECK-NEXT: %7 = load i32, ptr %4, align 4 +; CHECK-NEXT: %8 = sext i32 %7 to i64 +; CHECK-NEXT: %9 = getelementptr inbounds [3 x i32], ptr %2, i64 0, i64 %8 +; CHECK-NEXT: %10 = load i32, ptr %9, align 4 +; CHECK-NEXT: %11 = load i32, ptr %3, align 4 +; CHECK-NEXT: %12 = add nsw i32 %11, %10 +; CHECK-NEXT: store i32 %12, ptr %3, align 4 +; CHECK-NEXT: br label %for.inc.inlined.0 +; CHECK-EMPTY: +; CHECK-NEXT: for.inc.inlined.0: ; preds = %for.body.inlined.0 +; CHECK-NEXT: %13 = load i32, ptr %4, align 4 +; CHECK-NEXT: %14 = add nsw i32 %13, 1 +; CHECK-NEXT: store i32 %14, ptr %4, align 4 +; CHECK-NEXT: br label %for.cond.inlined.0 +; CHECK-EMPTY: +; CHECK-NEXT: for.end.inlined.0: ; preds = %for.cond.inlined.0 +; CHECK-NEXT: br label %entry.splited.0 +; CHECK-EMPTY: +; CHECK-NEXT: entry.splited.0: ; preds = %for.end.inlined.0 +; CHECK-NEXT: %15 = load i32, ptr %a.addr, align 4 +; CHECK-NEXT: %16 = load i32, ptr %b.addr, align 4 +; CHECK-NEXT: %add = add nsw i32 %15, %16 +; CHECK-NEXT: ret i32 %add +; CHECK-NEXT: } + +; ---------------------------------------------------------------------------------- + +; COM: Wasn't expected inline + +; int isEven(int num) { +; if (num % 2 == 0) { +; return true; +; } else { +; return false; +; } +; } + +; void filterEvenNumbers(int* numbers, int size, int* evenNumbers, int& evenSize) { +; evenSize = 0; +; for (int i = 0; i < size; i++) { +; if (isEven(numbers[i])) { +; evenNumbers[evenSize++] = numbers[i]; +; } +; } +; } + +; Function Attrs: mustprogress noinline nounwind optnone uwtable +define dso_local noundef i32 @_Z6isEveni(i32 noundef %num) #0 { +entry: + %retval = alloca i32, align 4 + %num.addr = alloca i32, align 4 + store i32 %num, ptr %num.addr, align 4 + %0 = load i32, ptr %num.addr, align 4 + %rem = srem i32 %0, 2 + %cmp = icmp eq i32 %rem, 0 + br i1 %cmp, label %if.then, label %if.else + +if.then: ; preds = %entry + store i32 1, ptr %retval, align 4 + br label %return + +if.else: ; preds = %entry + store i32 0, ptr %retval, align 4 + br label %return + +return: ; preds = %if.else, %if.then + %1 = load i32, ptr %retval, align 4 + ret i32 %1 +} + +; Function Attrs: mustprogress noinline nounwind optnone uwtable +define dso_local void @_Z17filterEvenNumbersPiiS_Ri(ptr noundef %numbers, i32 noundef %size, ptr noundef %evenNumbers, ptr noundef nonnull align 4 dereferenceable(4) %evenSize) #0 { +entry: + %numbers.addr = alloca ptr, align 8 + %size.addr = alloca i32, align 4 + %evenNumbers.addr = alloca ptr, align 8 + %evenSize.addr = alloca ptr, align 8 + %i = alloca i32, align 4 + store ptr %numbers, ptr %numbers.addr, align 8 + store i32 %size, ptr %size.addr, align 4 + store ptr %evenNumbers, ptr %evenNumbers.addr, align 8 + store ptr %evenSize, ptr %evenSize.addr, align 8 + %0 = load ptr, ptr %evenSize.addr, align 8 + store i32 0, ptr %0, align 4 + store i32 0, ptr %i, align 4 + br label %for.cond + +for.cond: ; preds = %for.inc, %entry + %1 = load i32, ptr %i, align 4 + %2 = load i32, ptr %size.addr, align 4 + %cmp = icmp slt i32 %1, %2 + br i1 %cmp, label %for.body, label %for.end + +for.body: ; preds = %for.cond + %3 = load ptr, ptr %numbers.addr, align 8 + %4 = load i32, ptr %i, align 4 + %idxprom = sext i32 %4 to i64 + %arrayidx = getelementptr inbounds i32, ptr %3, i64 %idxprom + %5 = load i32, ptr %arrayidx, align 4 + %call = call noundef i32 @_Z6isEveni(i32 noundef %5) + %tobool = icmp ne i32 %call, 0 + br i1 %tobool, label %if.then, label %if.end + +if.then: ; preds = %for.body + %6 = load ptr, ptr %numbers.addr, align 8 + %7 = load i32, ptr %i, align 4 + %idxprom1 = sext i32 %7 to i64 + %arrayidx2 = getelementptr inbounds i32, ptr %6, i64 %idxprom1 + %8 = load i32, ptr %arrayidx2, align 4 + %9 = load ptr, ptr %evenNumbers.addr, align 8 + %10 = load ptr, ptr %evenSize.addr, align 8 + %11 = load i32, ptr %10, align 4 + %inc = add nsw i32 %11, 1 + store i32 %inc, ptr %10, align 4 + %idxprom3 = sext i32 %11 to i64 + %arrayidx4 = getelementptr inbounds i32, ptr %9, i64 %idxprom3 + store i32 %8, ptr %arrayidx4, align 4 + br label %if.end + +if.end: ; preds = %if.then, %for.body + br label %for.inc + +for.inc: ; preds = %if.end + %12 = load i32, ptr %i, align 4 + %inc5 = add nsw i32 %12, 1 + store i32 %inc5, ptr %i, align 4 + br label %for.cond + +for.end: ; preds = %for.cond + ret void +} + +; CHECK: define dso_local void @_Z17filterEvenNumbersPiiS_Ri(ptr noundef %numbers, i32 noundef %size, ptr noundef %evenNumbers, ptr noundef nonnull align 4 dereferenceable(4) %evenSize) #0 { +; CHECK: entry: +; CHECK-NEXT: %numbers.addr = alloca ptr, align 8 +; CHECK-NEXT: %size.addr = alloca i32, align 4 +; CHECK-NEXT: %evenNumbers.addr = alloca ptr, align 8 +; CHECK-NEXT: %evenSize.addr = alloca ptr, align 8 +; CHECK-NEXT: %i = alloca i32, align 4 +; CHECK-NEXT: store ptr %numbers, ptr %numbers.addr, align 8 +; CHECK-NEXT: store i32 %size, ptr %size.addr, align 4 +; CHECK-NEXT: store ptr %evenNumbers, ptr %evenNumbers.addr, align 8 +; CHECK-NEXT: store ptr %evenSize, ptr %evenSize.addr, align 8 +; CHECK-NEXT: %0 = load ptr, ptr %evenSize.addr, align 8 +; CHECK-NEXT: store i32 0, ptr %0, align 4 +; CHECK-NEXT: store i32 0, ptr %i, align 4 +; CHECK-NEXT: br label %for.cond +; CHECK-EMPTY: +; CHECK-NEXT: for.cond: ; preds = %for.inc, %entry +; CHECK-NEXT: %1 = load i32, ptr %i, align 4 +; CHECK-NEXT: %2 = load i32, ptr %size.addr, align 4 +; CHECK-NEXT: %cmp = icmp slt i32 %1, %2 +; CHECK-NEXT: br i1 %cmp, label %for.body, label %for.end +; CHECK-EMPTY: +; CHECK-NEXT: for.body: ; preds = %for.cond +; CHECK-NEXT: %3 = load ptr, ptr %numbers.addr, align 8 +; CHECK-NEXT: %4 = load i32, ptr %i, align 4 +; CHECK-NEXT: %idxprom = sext i32 %4 to i64 +; CHECK-NEXT: %arrayidx = getelementptr inbounds i32, ptr %3, i64 %idxprom +; CHECK-NEXT: %5 = load i32, ptr %arrayidx, align 4 +; CHECK-NEXT: %call = call noundef i32 @_Z6isEveni(i32 noundef %5) +; CHECK-NEXT: %tobool = icmp ne i32 %call, 0 +; CHECK-NEXT: br i1 %tobool, label %if.then, label %if.end +; CHECK-EMPTY: +; CHECK-NEXT: if.then: ; preds = %for.body +; CHECK-NEXT: %6 = load ptr, ptr %numbers.addr, align 8 +; CHECK-NEXT: %7 = load i32, ptr %i, align 4 +; CHECK-NEXT: %idxprom1 = sext i32 %7 to i64 +; CHECK-NEXT: %arrayidx2 = getelementptr inbounds i32, ptr %6, i64 %idxprom1 +; CHECK-NEXT: %8 = load i32, ptr %arrayidx2, align 4 +; CHECK-NEXT: %9 = load ptr, ptr %evenNumbers.addr, align 8 +; CHECK-NEXT: %10 = load ptr, ptr %evenSize.addr, align 8 +; CHECK-NEXT: %11 = load i32, ptr %10, align 4 +; CHECK-NEXT: %inc = add nsw i32 %11, 1 +; CHECK-NEXT: store i32 %inc, ptr %10, align 4 +; CHECK-NEXT: %idxprom3 = sext i32 %11 to i64 +; CHECK-NEXT: %arrayidx4 = getelementptr inbounds i32, ptr %9, i64 %idxprom3 +; CHECK-NEXT: store i32 %8, ptr %arrayidx4, align 4 +; CHECK-NEXT: br label %if.end +; CHECK-EMPTY: +; CHECK-NEXT: if.end: ; preds = %if.then, %for.body +; CHECK-NEXT: br label %for.inc +; CHECK-EMPTY: +; CHECK-NEXT: for.inc: ; preds = %if.end +; CHECK-NEXT: %12 = load i32, ptr %i, align 4 +; CHECK-NEXT: %inc5 = add nsw i32 %12, 1 +; CHECK-NEXT: store i32 %inc5, ptr %i, align 4 +; CHECK-NEXT: br label %for.cond +; CHECK-EMPTY: +; CHECK-NEXT: for.end: ; preds = %for.cond +; CHECK-NEXT: ret void +; CHECK-NEXT: } + +; ---------------------------------------------------------------------------------- + +; COM: Expected inline + +; void someFun() { +; int a = 4; +; int b = 6; +; if (a < b) { +; a++; +; } else { +; b++; +; } +; } + +; int forLoop(int n) { +; int sum = 0; +; for (int i = 0; i < n; i++) { +; sum += i; +; someFun(); +; } +; return sum; +; } + +; Function Attrs: mustprogress noinline nounwind optnone uwtable +define dso_local void @_Z7someFunv() #0 { +entry: + %a = alloca i32, align 4 + %b = alloca i32, align 4 + store i32 4, ptr %a, align 4 + store i32 6, ptr %b, align 4 + %0 = load i32, ptr %a, align 4 + %1 = load i32, ptr %b, align 4 + %cmp = icmp slt i32 %0, %1 + br i1 %cmp, label %if.then, label %if.else + +if.then: ; preds = %entry + %2 = load i32, ptr %a, align 4 + %inc = add nsw i32 %2, 1 + store i32 %inc, ptr %a, align 4 + br label %if.end + +if.else: ; preds = %entry + %3 = load i32, ptr %b, align 4 + %inc1 = add nsw i32 %3, 1 + store i32 %inc1, ptr %b, align 4 + br label %if.end + +if.end: ; preds = %if.else, %if.then + ret void +} + +; Function Attrs: mustprogress noinline nounwind optnone uwtable +define dso_local noundef i32 @_Z7forLoopi(i32 noundef %n) #0 { +entry: + %n.addr = alloca i32, align 4 + %sum = alloca i32, align 4 + %i = alloca i32, align 4 + store i32 %n, ptr %n.addr, align 4 + store i32 0, ptr %sum, align 4 + store i32 0, ptr %i, align 4 + br label %for.cond + +for.cond: ; preds = %for.inc, %entry + %0 = load i32, ptr %i, align 4 + %1 = load i32, ptr %n.addr, align 4 + %cmp = icmp slt i32 %0, %1 + br i1 %cmp, label %for.body, label %for.end + +for.body: ; preds = %for.cond + %2 = load i32, ptr %i, align 4 + %3 = load i32, ptr %sum, align 4 + %add = add nsw i32 %3, %2 + store i32 %add, ptr %sum, align 4 + call void @_Z7someFunv() + br label %for.inc + +for.inc: ; preds = %for.body + %4 = load i32, ptr %i, align 4 + %inc = add nsw i32 %4, 1 + store i32 %inc, ptr %i, align 4 + br label %for.cond + +for.end: ; preds = %for.cond + %5 = load i32, ptr %sum, align 4 + ret i32 %5 +} + +; CHECK: define dso_local noundef i32 @_Z7forLoopi(i32 noundef %n) #0 { +; CHECK: entry: +; CHECK-NEXT: %n.addr = alloca i32, align 4 +; CHECK-NEXT: %sum = alloca i32, align 4 +; CHECK-NEXT: %i = alloca i32, align 4 +; CHECK-NEXT: store i32 %n, ptr %n.addr, align 4 +; CHECK-NEXT: store i32 0, ptr %sum, align 4 +; CHECK-NEXT: store i32 0, ptr %i, align 4 +; CHECK-NEXT: br label %for.cond +; CHECK-EMPTY: +; CHECK-NEXT: for.cond: ; preds = %for.inc, %entry +; CHECK-NEXT: %0 = load i32, ptr %i, align 4 +; CHECK-NEXT: %1 = load i32, ptr %n.addr, align 4 +; CHECK-NEXT: %cmp = icmp slt i32 %0, %1 +; CHECK-NEXT: br i1 %cmp, label %for.body, label %for.end +; CHECK-EMPTY: +; CHECK-NEXT: for.body: ; preds = %for.cond +; CHECK-NEXT: %2 = load i32, ptr %i, align 4 +; CHECK-NEXT: %3 = load i32, ptr %sum, align 4 +; CHECK-NEXT: %add = add nsw i32 %3, %2 +; CHECK-NEXT: store i32 %add, ptr %sum, align 4 +; CHECK-NEXT: br label %entry.inlined.0 +; CHECK-EMPTY: +; CHECK-NEXT: for.inc: ; preds = %for.body.splited.0 +; CHECK-NEXT: %4 = load i32, ptr %i, align 4 +; CHECK-NEXT: %inc = add nsw i32 %4, 1 +; CHECK-NEXT: store i32 %inc, ptr %i, align 4 +; CHECK-NEXT: br label %for.cond +; CHECK-EMPTY: +; CHECK-NEXT: for.end: ; preds = %for.cond +; CHECK-NEXT: %5 = load i32, ptr %sum, align 4 +; CHECK-NEXT: br label %for.body.splited.0 +; CHECK-EMPTY: +; CHECK-NEXT: entry.inlined.0: ; preds = %for.body +; CHECK-NEXT: %6 = alloca i32, align 4 +; CHECK-NEXT: %7 = alloca i32, align 4 +; CHECK-NEXT: store i32 4, ptr %6, align 4 +; CHECK-NEXT: store i32 6, ptr %7, align 4 +; CHECK-NEXT: %8 = load i32, ptr %6, align 4 +; CHECK-NEXT: %9 = load i32, ptr %7, align 4 +; CHECK-NEXT: %10 = icmp slt i32 %8, %9 +; CHECK-NEXT: br i1 %10, label %if.then.inlined.0, label %if.else.inlined.0 +; CHECK-EMPTY: +; CHECK-NEXT: if.then.inlined.0: ; preds = %entry.inlined.0 +; CHECK-NEXT: %11 = load i32, ptr %6, align 4 +; CHECK-NEXT: %12 = add nsw i32 %11, 1 +; CHECK-NEXT: store i32 %12, ptr %6, align 4 +; CHECK-NEXT: br label %if.end.inlined.0 +; CHECK-EMPTY: +; CHECK-NEXT: if.else.inlined.0: ; preds = %entry.inlined.0 +; CHECK-NEXT: %13 = load i32, ptr %7, align 4 +; CHECK-NEXT: %14 = add nsw i32 %13, 1 +; CHECK-NEXT: store i32 %14, ptr %7, align 4 +; CHECK-NEXT: br label %if.end.inlined.0 +; CHECK-EMPTY: +; CHECK-NEXT: if.end.inlined.0: ; preds = %if.else.inlined.0, %if.then.inlined.0 +; CHECK-NEXT: br label %for.body.splited.0 +; CHECK-EMPTY: +; CHECK-NEXT: for.body.splited.0: ; preds = %if.end.inlined.0, %for.end +; CHECK-NEXT: br label %for.inc +; CHECK-NEXT: } + +attributes #0 = { mustprogress noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #1 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) } + +!llvm.module.flags = !{!0, !1, !2, !3, !4} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 8, !"PIC Level", i32 2} +!2 = !{i32 7, !"PIE Level", i32 2} +!3 = !{i32 7, !"uwtable", i32 2} +!4 = !{i32 7, !"frame-pointer", i32 2} diff --git a/llvm/test/lab3/levashov_evgeniy/test.mir b/llvm/test/lab3/levashov_evgeniy/test.mir new file mode 100644 index 0000000000000..af82d2bbbe506 --- /dev/null +++ b/llvm/test/lab3/levashov_evgeniy/test.mir @@ -0,0 +1,407 @@ +# RUN: llc -mtriple x86_64-unknown-linux-gnu --load=%llvmshlibdir/X86LevashovPass%shlibext -run-pass=x86-mul-add-levashov-pass %s -o - | FileCheck %s + +# test.cpp + +# __m128d muladd_test1(__m128d a, __m128d b, __m128d c) { +# __m128d result = a * b + c; +# return result; +# } + +# __m128d muladd_test2(__m128d a, __m128d b, __m128d c) { +# __m128d result = a * c + b; +# return result; +# } + +# __m128d muladd_test3(__m128d a, __m128d b, __m128d c) { +# __m128d result = a * b - c; +# return result; +# } + +# __m128d muladd_test4(__m128d a, __m128d b, __m128d c) { +# __m128d result = a * b + c + b; +# return result; +# } + +# __m128d muladd_test5(__m128d a, __m128d b, __m128d c) { +# return a * c + b; +# } + +# __m128d muladd_test6(__m128d a, __m128d b, __m128d c) { +# __m128d temp = a * c; +# __m128d temp2 = b + a - c; +# return temp + c + temp2; +# } + +# __m128d muladd_test7(__m128d a, __m128d b, __m128d c) { +# __m128d temp = a * b; +# __m128d temp2 = temp - c; +# return temp + temp2; +# } +# +# __m128d muladd_test8(__m128d a, __m128d b, __m128d c) { +# __m128d temp = a * b; +# __m128d result = temp + c - a; +# return result; +# } + +# __m128d muladd_test9(__m128d a, __m128d b, __m128d c) { +# __m128d temp1 = a * b; +# __m128d temp2 = c - a; +# __m128d result = temp1 - temp2; +# return result; +# } + + + +--- | + target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + target triple = "x86_64-unknown-linux-gnu" + + ; Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none) uwtable + define dso_local noundef <2 x double> @_Z12muladd_test1Dv2_dS_S_(<2 x double> noundef %a, <2 x double> noundef %b, <2 x double> noundef %c) local_unnamed_addr #0 { + entry: + %0 = tail call <2 x double> @llvm.fmuladd.v2f64(<2 x double> %a, <2 x double> %b, <2 x double> %c) + ret <2 x double> %0 + } + + ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) + declare <2 x double> @llvm.fmuladd.v2f64(<2 x double>, <2 x double>, <2 x double>) #1 + + ; Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none) uwtable + define dso_local noundef <2 x double> @_Z12muladd_test2Dv2_dS_S_(<2 x double> noundef %a, <2 x double> noundef %b, <2 x double> noundef %c) local_unnamed_addr #0 { + entry: + %0 = tail call <2 x double> @llvm.fmuladd.v2f64(<2 x double> %a, <2 x double> %c, <2 x double> %b) + ret <2 x double> %0 + } + + ; Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none) uwtable + define dso_local noundef <2 x double> @_Z12muladd_test3Dv2_dS_S_(<2 x double> noundef %a, <2 x double> noundef %b, <2 x double> noundef %c) local_unnamed_addr #0 { + entry: + %neg = fneg <2 x double> %c + %0 = tail call <2 x double> @llvm.fmuladd.v2f64(<2 x double> %a, <2 x double> %b, <2 x double> %neg) + ret <2 x double> %0 + } + + ; Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none) uwtable + define dso_local noundef <2 x double> @_Z12muladd_test4Dv2_dS_S_(<2 x double> noundef %a, <2 x double> noundef %b, <2 x double> noundef %c) local_unnamed_addr #0 { + entry: + %0 = tail call <2 x double> @llvm.fmuladd.v2f64(<2 x double> %a, <2 x double> %b, <2 x double> %c) + %add = fadd <2 x double> %0, %b + ret <2 x double> %add + } + + ; Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none) uwtable + define dso_local noundef <2 x double> @_Z12muladd_test5Dv2_dS_S_(<2 x double> noundef %a, <2 x double> noundef %b, <2 x double> noundef %c) local_unnamed_addr #0 { + entry: + %0 = tail call <2 x double> @llvm.fmuladd.v2f64(<2 x double> %a, <2 x double> %c, <2 x double> %b) + ret <2 x double> %0 + } + + ; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable + define dso_local noundef <2 x double> @_Z12muladd_test6Dv2_dS_S_(<2 x double> noundef %a, <2 x double> noundef %b, <2 x double> noundef %c) local_unnamed_addr #2 { + entry: + %mul = fmul <2 x double> %a, %c + %add = fadd <2 x double> %a, %b + %sub = fsub <2 x double> %add, %c + %add1 = fadd <2 x double> %mul, %c + %add2 = fadd <2 x double> %sub, %add1 + ret <2 x double> %add2 + } + + ; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable + define dso_local noundef <2 x double> @_Z12muladd_test7Dv2_dS_S_(<2 x double> noundef %a, <2 x double> noundef %b, <2 x double> noundef %c) local_unnamed_addr #2 { + entry: + %mul = fmul <2 x double> %a, %b + %sub = fsub <2 x double> %mul, %c + %add = fadd <2 x double> %mul, %sub + ret <2 x double> %add + } + + ; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable + define dso_local noundef <2 x double> @_Z12muladd_test8Dv2_dS_S_(<2 x double> noundef %a, <2 x double> noundef %b, <2 x double> noundef %c) local_unnamed_addr #2 { + entry: + %mul = fmul <2 x double> %a, %b + %add = fadd <2 x double> %mul, %c + %sub = fsub <2 x double> %add, %a + ret <2 x double> %sub + } + + ; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable + define dso_local noundef <2 x double> @_Z12muladd_test9Dv2_dS_S_(<2 x double> noundef %a, <2 x double> noundef %b, <2 x double> noundef %c) local_unnamed_addr #2 { + entry: + %mul = fmul <2 x double> %a, %b + %sub = fsub <2 x double> %c, %a + %sub1 = fsub <2 x double> %mul, %sub + ret <2 x double> %sub1 + } + + attributes #0 = { mustprogress nofree nosync nounwind willreturn memory(none) uwtable "min-legal-vector-width"="128" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } + attributes #1 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } + attributes #2 = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable "min-legal-vector-width"="128" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } + + !llvm.module.flags = !{!0, !1, !2, !3} + + !0 = !{i32 1, !"wchar_size", i32 4} + !1 = !{i32 8, !"PIC Level", i32 2} + !2 = !{i32 7, !"PIE Level", i32 2} + !3 = !{i32 7, !"uwtable", i32 2} + +... +--- +name: _Z12muladd_test1Dv2_dS_S_ +alignment: 16 +tracksRegLiveness: true +debugInstrRef: true +tracksDebugUserValues: true +liveins: + - { reg: '$xmm0' } + - { reg: '$xmm1' } + - { reg: '$xmm2' } +frameInfo: + maxAlignment: 1 + maxCallFrameSize: 0 +machineFunctionInfo: {} +body: | + bb.0.entry: + liveins: $xmm0, $xmm1, $xmm2 + + renamable $xmm0 = nofpexcept MULPDrr killed renamable $xmm0, killed renamable $xmm1, implicit $mxcsr + renamable $xmm0 = nofpexcept ADDPDrr killed renamable $xmm0, killed renamable $xmm2, implicit $mxcsr + RET64 $xmm0 + + ; CHECK: $xmm0 = VFMADD213PDr $xmm0, $xmm1, $xmm2, implicit $mxcsr + ; CHECK-NEXT: RET64 $xmm0 + +... +--- +name: _Z12muladd_test2Dv2_dS_S_ +alignment: 16 +tracksRegLiveness: true +debugInstrRef: true +tracksDebugUserValues: true +liveins: + - { reg: '$xmm0' } + - { reg: '$xmm1' } + - { reg: '$xmm2' } +frameInfo: + maxAlignment: 1 + maxCallFrameSize: 0 +machineFunctionInfo: {} +body: | + bb.0.entry: + liveins: $xmm0, $xmm1, $xmm2 + + renamable $xmm0 = nofpexcept MULPDrr killed renamable $xmm0, killed renamable $xmm2, implicit $mxcsr + renamable $xmm0 = nofpexcept ADDPDrr killed renamable $xmm0, killed renamable $xmm1, implicit $mxcsr + RET64 $xmm0 + + ; CHECK: $xmm0 = VFMADD213PDr $xmm0, $xmm2, $xmm1, implicit $mxcsr + ; CHECK-NEXT: RET64 $xmm0 + +... +--- +name: _Z12muladd_test3Dv2_dS_S_ +alignment: 16 +tracksRegLiveness: true +debugInstrRef: true +tracksDebugUserValues: true +liveins: + - { reg: '$xmm0' } + - { reg: '$xmm1' } + - { reg: '$xmm2' } +frameInfo: + maxAlignment: 1 + maxCallFrameSize: 0 +machineFunctionInfo: {} +body: | + bb.0.entry: + liveins: $xmm0, $xmm1, $xmm2 + + renamable $xmm0 = nofpexcept MULPDrr killed renamable $xmm0, killed renamable $xmm1, implicit $mxcsr + renamable $xmm0 = nofpexcept SUBPDrr killed renamable $xmm0, killed renamable $xmm2, implicit $mxcsr + RET64 $xmm0 + + ; CHECK: renamable $xmm0 = nofpexcept MULPDrr killed renamable $xmm0, killed renamable $xmm1, implicit $mxcsr + ; CHECK-NEXT: renamable $xmm0 = nofpexcept SUBPDrr killed renamable $xmm0, killed renamable $xmm2, implicit $mxcsr + ; CHECK-NEXT: RET64 $xmm0 + +... +--- +name: _Z12muladd_test4Dv2_dS_S_ +alignment: 16 +tracksRegLiveness: true +debugInstrRef: true +tracksDebugUserValues: true +liveins: + - { reg: '$xmm0' } + - { reg: '$xmm1' } + - { reg: '$xmm2' } +frameInfo: + maxAlignment: 1 + maxCallFrameSize: 0 +machineFunctionInfo: {} +body: | + bb.0.entry: + liveins: $xmm0, $xmm1, $xmm2 + + renamable $xmm0 = nofpexcept MULPDrr killed renamable $xmm0, renamable $xmm1, implicit $mxcsr + renamable $xmm0 = nofpexcept ADDPDrr killed renamable $xmm0, killed renamable $xmm2, implicit $mxcsr + renamable $xmm0 = nofpexcept ADDPDrr killed renamable $xmm0, killed renamable $xmm1, implicit $mxcsr + RET64 $xmm0 + + ; CHECK: $xmm0 = VFMADD213PDr $xmm0, $xmm1, $xmm2, implicit $mxcsr + ; CHECK-NEXT: renamable $xmm0 = nofpexcept ADDPDrr killed renamable $xmm0, killed renamable $xmm1, implicit $mxcsr + ; CHECK-NEXT: RET64 $xmm0 + +... +--- +name: _Z12muladd_test5Dv2_dS_S_ +alignment: 16 +tracksRegLiveness: true +debugInstrRef: true +tracksDebugUserValues: true +liveins: + - { reg: '$xmm0' } + - { reg: '$xmm1' } + - { reg: '$xmm2' } +frameInfo: + maxAlignment: 1 + maxCallFrameSize: 0 +machineFunctionInfo: {} +body: | + bb.0.entry: + liveins: $xmm0, $xmm1, $xmm2 + + renamable $xmm0 = nofpexcept MULPDrr killed renamable $xmm0, killed renamable $xmm2, implicit $mxcsr + renamable $xmm0 = nofpexcept ADDPDrr killed renamable $xmm0, killed renamable $xmm1, implicit $mxcsr + RET64 $xmm0 + + ; CHECK: $xmm0 = VFMADD213PDr $xmm0, $xmm2, $xmm1, implicit $mxcsr + ; CHECK-NEXT: RET64 $xmm0 + +... +--- +name: _Z12muladd_test6Dv2_dS_S_ +alignment: 16 +tracksRegLiveness: true +debugInstrRef: true +tracksDebugUserValues: true +liveins: + - { reg: '$xmm0' } + - { reg: '$xmm1' } + - { reg: '$xmm2' } +frameInfo: + maxAlignment: 1 + maxCallFrameSize: 0 +machineFunctionInfo: {} +body: | + bb.0.entry: + liveins: $xmm0, $xmm1, $xmm2 + + $xmm3 = MOVAPDrr $xmm0 + renamable $xmm3 = nofpexcept MULPDrr killed renamable $xmm3, renamable $xmm2, implicit $mxcsr + renamable $xmm0 = nofpexcept ADDPDrr killed renamable $xmm0, killed renamable $xmm1, implicit $mxcsr + renamable $xmm0 = nofpexcept SUBPDrr killed renamable $xmm0, renamable $xmm2, implicit $mxcsr + renamable $xmm3 = nofpexcept ADDPDrr killed renamable $xmm3, killed renamable $xmm2, implicit $mxcsr + renamable $xmm0 = nofpexcept ADDPDrr killed renamable $xmm0, killed renamable $xmm3, implicit $mxcsr + RET64 $xmm0 + + ; CHECK: $xmm3 = MOVAPDrr $xmm0 + ; CHECK-NEXT: $xmm3 = VFMADD213PDr $xmm3, $xmm2, $xmm2, implicit $mxcsr + ; CHECK-NEXT: renamable $xmm0 = nofpexcept ADDPDrr killed renamable $xmm0, killed renamable $xmm1, implicit $mxcsr + ; CHECK-NEXT: renamable $xmm0 = nofpexcept SUBPDrr killed renamable $xmm0, renamable $xmm2, implicit $mxcsr + ; CHECK-NEXT: renamable $xmm0 = nofpexcept ADDPDrr killed renamable $xmm0, killed renamable $xmm3, implicit $mxcsr + ; CHECK-NEXT: RET64 $xmm0 + +... +--- +name: _Z12muladd_test7Dv2_dS_S_ +alignment: 16 +tracksRegLiveness: true +debugInstrRef: true +tracksDebugUserValues: true +liveins: + - { reg: '$xmm0' } + - { reg: '$xmm1' } + - { reg: '$xmm2' } +frameInfo: + maxAlignment: 1 + maxCallFrameSize: 0 +machineFunctionInfo: {} +body: | + bb.0.entry: + liveins: $xmm0, $xmm1, $xmm2 + + renamable $xmm0 = nofpexcept MULPDrr killed renamable $xmm0, killed renamable $xmm1, implicit $mxcsr + $xmm1 = MOVAPDrr $xmm0 + renamable $xmm1 = nofpexcept SUBPDrr killed renamable $xmm1, killed renamable $xmm2, implicit $mxcsr + renamable $xmm0 = nofpexcept ADDPDrr killed renamable $xmm0, killed renamable $xmm1, implicit $mxcsr + RET64 $xmm0 + + ; CHECK: renamable $xmm0 = nofpexcept MULPDrr killed renamable $xmm0, killed renamable $xmm1, implicit $mxcsr + ; CHECK-NEXT: $xmm1 = MOVAPDrr $xmm0 + ; CHECK-NEXT: renamable $xmm1 = nofpexcept SUBPDrr killed renamable $xmm1, killed renamable $xmm2, implicit $mxcsr + ; CHECK-NEXT: renamable $xmm0 = nofpexcept ADDPDrr killed renamable $xmm0, killed renamable $xmm1, implicit $mxcsr + ; CHECK-NEXT: RET64 $xmm0 + +... +--- +name: _Z12muladd_test8Dv2_dS_S_ +alignment: 16 +tracksRegLiveness: true +debugInstrRef: true +tracksDebugUserValues: true +liveins: + - { reg: '$xmm0' } + - { reg: '$xmm1' } + - { reg: '$xmm2' } +frameInfo: + maxAlignment: 1 + maxCallFrameSize: 0 +machineFunctionInfo: {} +body: | + bb.0.entry: + liveins: $xmm0, $xmm1, $xmm2 + + renamable $xmm1 = nofpexcept MULPDrr killed renamable $xmm1, renamable $xmm0, implicit $mxcsr + renamable $xmm1 = nofpexcept ADDPDrr killed renamable $xmm1, killed renamable $xmm2, implicit $mxcsr + renamable $xmm1 = nofpexcept SUBPDrr killed renamable $xmm1, killed renamable $xmm0, implicit $mxcsr + $xmm0 = MOVAPDrr killed $xmm1 + RET64 $xmm0 + + ; CHECK: $xmm1 = VFMADD213PDr $xmm1, $xmm0, $xmm2, implicit $mxcsr + ; CHECK-NEXT: renamable $xmm1 = nofpexcept SUBPDrr killed renamable $xmm1, killed renamable $xmm0, implicit $mxcsr + ; CHECK-NEXT: $xmm0 = MOVAPDrr killed $xmm1 + ; CHECK-NEXT: RET64 $xmm0 + +... +--- +name: _Z12muladd_test9Dv2_dS_S_ +alignment: 16 +tracksRegLiveness: true +debugInstrRef: true +tracksDebugUserValues: true +liveins: + - { reg: '$xmm0' } + - { reg: '$xmm1' } + - { reg: '$xmm2' } +frameInfo: + maxAlignment: 1 + maxCallFrameSize: 0 +machineFunctionInfo: {} +body: | + bb.0.entry: + liveins: $xmm0, $xmm1, $xmm2 + + renamable $xmm1 = nofpexcept MULPDrr killed renamable $xmm1, renamable $xmm0, implicit $mxcsr + renamable $xmm2 = nofpexcept SUBPDrr killed renamable $xmm2, killed renamable $xmm0, implicit $mxcsr + renamable $xmm1 = nofpexcept SUBPDrr killed renamable $xmm1, killed renamable $xmm2, implicit $mxcsr + $xmm0 = MOVAPDrr killed $xmm1 + RET64 $xmm0 + + ; CHECK: renamable $xmm1 = nofpexcept MULPDrr killed renamable $xmm1, renamable $xmm0, implicit $mxcsr + ; CHECK-NEXT: renamable $xmm2 = nofpexcept SUBPDrr killed renamable $xmm2, killed renamable $xmm0, implicit $mxcsr + ; CHECK-NEXT: renamable $xmm1 = nofpexcept SUBPDrr killed renamable $xmm1, killed renamable $xmm2, implicit $mxcsr + ; CHECK-NEXT: $xmm0 = MOVAPDrr killed $xmm1 + ; CHECK-NEXT: RET64 $xmm0 +... diff --git a/mlir/lib/Transforms/lab4/levashov_evgeniy/CMakeLists.txt b/mlir/lib/Transforms/lab4/levashov_evgeniy/CMakeLists.txt new file mode 100644 index 0000000000000..7aa75f6f7490f --- /dev/null +++ b/mlir/lib/Transforms/lab4/levashov_evgeniy/CMakeLists.txt @@ -0,0 +1,12 @@ +set(PluginName LevashovDiv) + +file(GLOB_RECURSE ALL_SOURCE_FILES *.cpp *.h) +add_llvm_pass_plugin(${PluginName} + ${ALL_SOURCE_FILES} + DEPENDS + intrinsics_gen + MLIRBuiltinLocationAttributesIncGen + BUILDTREE_ONLY + ) + +set(MLIR_TEST_DEPENDS ${PluginName} ${MLIR_TEST_DEPENDS} PARENT_SCOPE) \ No newline at end of file diff --git a/mlir/lib/Transforms/lab4/levashov_evgeniy/Div.cpp b/mlir/lib/Transforms/lab4/levashov_evgeniy/Div.cpp new file mode 100644 index 0000000000000..8a4dbbc01e4ac --- /dev/null +++ b/mlir/lib/Transforms/lab4/levashov_evgeniy/Div.cpp @@ -0,0 +1,65 @@ +#include "mlir/Dialect/Arith/IR/Arith.h" +#include "mlir/IR/PatternMatch.h" +#include "mlir/Pass/Pass.h" +#include "mlir/Tools/Plugins/PassPlugin.h" + +using namespace mlir; + +namespace { +enum OpType { SignedOp, UnsignedOp }; + +class LevashovDiv : public PassWrapper> { +public: + StringRef getArgument() const final { return "levashov_div_pass"; } + StringRef getDescription() const final { + return "splits the arith.ceildivui and arith.ceildivsi into arith " + "operations"; + } + + void runOnOperation() override { + getOperation()->walk([&](Operation *op) { + if (auto ceilDivUI = dyn_cast(op)) { + replaceCeilDiv(ceilDivUI, OpType::UnsignedOp); + } else if (auto ceilDivSI = dyn_cast(op)) { + replaceCeilDiv(ceilDivSI, OpType::SignedOp); + } + }); + } + +private: + template + void replaceCeilDiv(CeilDivOpType op, OpType type) { + OpBuilder builder(op); + Location loc = op.getLoc(); + Value a = op.getLhs(); + Value b = op.getRhs(); + + Value one = + builder.create(loc, 1, builder.getI32Type()); + Value add = builder.create(loc, a, b); + Value sub = builder.create(loc, add, one); + Value div; + + if (type == OpType::SignedOp) { + div = builder.create(loc, sub, b); + } else { + div = builder.create(loc, sub, b); + } + + op.replaceAllUsesWith(div); + op.erase(); + } +}; +} // anonymous namespace + +MLIR_DECLARE_EXPLICIT_TYPE_ID(LevashovDiv) +MLIR_DEFINE_EXPLICIT_TYPE_ID(LevashovDiv) + +PassPluginLibraryInfo getsCeilDivPassPluginInfo() { + return {MLIR_PLUGIN_API_VERSION, "levashov_div_pass", LLVM_VERSION_STRING, + []() { PassRegistration(); }}; +} + +extern "C" LLVM_ATTRIBUTE_WEAK PassPluginLibraryInfo mlirGetPassPluginInfo() { + return getsCeilDivPassPluginInfo(); +} \ No newline at end of file diff --git a/mlir/test/Transforms/lab4/levashov_evgeniy/test.mlir b/mlir/test/Transforms/lab4/levashov_evgeniy/test.mlir new file mode 100644 index 0000000000000..9ad9af86735dc --- /dev/null +++ b/mlir/test/Transforms/lab4/levashov_evgeniy/test.mlir @@ -0,0 +1,30 @@ +// RUN: mlir-opt -load-pass-plugin=%mlir_lib_dir/LevashovDiv%shlibext --pass-pipeline="builtin.module(levashov_div_pass)" %s | FileCheck %s + +module { + llvm.func @ceildivsi(%arg0: i32, %arg1: i32) -> i32 attributes {llvm.linkage = #llvm.linkage} { + // CHECK: llvm.func @ceildivsi(%arg0: i32, %arg1: i32) -> i32 attributes {llvm.linkage = #llvm.linkage} { + // CHECK-NEXT: %c1_i32 = arith.constant 1 : i32 + // CHECK-NEXT: %[[add:.*]] = arith.addi %arg0, %arg1 : i32 + // CHECK-NEXT: %[[sub:.*]] = arith.subi %[[add:.*]], %c1_i32 : i32 + // CHECK-NEXT: %[[div:.*]] = arith.divsi %[[sub]], %arg1 : i32 + // CHECK-NOT: %0 = arith.ceildivsi %arg0, %arg1 : i32 + %0 = arith.ceildivsi %arg0, %arg1 : i32 + llvm.return %0 : i32 + } + llvm.func @ceildivui(%arg0: i32, %arg1: i32) -> i32 attributes {llvm.linkage = #llvm.linkage} { + // CHECK: llvm.func @ceildivui(%arg0: i32, %arg1: i32) -> i32 attributes {llvm.linkage = #llvm.linkage} { + // CHECK-NEXT: %c1_i32 = arith.constant 1 : i32 + // CHECK-NEXT: %[[add:.*]] = arith.addi %arg0, %arg1 : i32 + // CHECK-NEXT: %[[sub:.*]] = arith.subi %[[add]], %c1_i32 : i32 + // CHECK-NEXT: %[[div:.*]] = arith.divui %[[sub]], %arg1 : i32 + // CHECK-NOT: %0 = arith.ceildivui %arg0, %arg1 : i32 + %0 = arith.ceildivui %arg0, %arg1 : i32 + llvm.return %0 : i32 + } + llvm.func @example(%arg0: i32, %arg1: i32, %arg2: i32, %arg3: i32) -> i32 attributes {llvm.linkage = #llvm.linkage} { + %0 = llvm.call @ceildivsi(%arg0, %arg1) : (i32, i32) -> i32 + %1 = llvm.call @ceildivui(%arg2, %arg3) : (i32, i32) -> i32 + %2 = arith.addi %0, %1 : i32 + llvm.return %2 : i32 + } +} \ No newline at end of file