Skip to content
This repository has been archived by the owner on Jan 19, 2025. It is now read-only.

Commit

Permalink
Borovkov Sergey. Lab 2. Option 4. (#146)
Browse files Browse the repository at this point in the history
Added a plugin that changes integer multiplication by bitwise shift if at least one of the operands is power of two.
  • Loading branch information
slx52 authored May 20, 2024
1 parent 794c363 commit f36d729
Show file tree
Hide file tree
Showing 3 changed files with 274 additions and 0 deletions.
11 changes: 11 additions & 0 deletions llvm/labs/lab2/borovkov_sergey/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
if (NOT WIN32 AND NOT CYGWIN)
set(PluginName MulShiftsBorovkovPlugin)

file(GLOB_RECURSE ALL_SOURCE_FILES *.cpp *.h)
add_llvm_pass_plugin(${PluginName}
${ALL_SOURCE_FILES} DEPENDS
intrinsics_gen
BUILDTREE_ONLY )

set(LLVM_TEST_DEPENDS ${PluginName} ${LLVM_TEST_DEPENDS} PARENT_SCOPE)
endif()
114 changes: 114 additions & 0 deletions llvm/labs/lab2/borovkov_sergey/MulWithShift.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/Pass.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Passes/PassPlugin.h"
#include <optional>

namespace {
struct MulShifts : llvm::PassInfoMixin<MulShifts> {
public:
llvm::PreservedAnalyses run(llvm::Function &Func,
llvm::FunctionAnalysisManager &FAM) {
std::vector<llvm::Instruction *> toRemove;

for (llvm::BasicBlock &BB : Func) {
for (llvm::Instruction &Inst : BB) {
if (!llvm::BinaryOperator::classof(&Inst)) {
continue;
}
llvm::BinaryOperator *op = llvm::cast<llvm::BinaryOperator>(&Inst);
if (op->getOpcode() != llvm::Instruction::BinaryOps::Mul) {
continue;
}

llvm::Value *lhs = op->getOperand(0);
llvm::Value *rhs = op->getOperand(1);

auto lg1 = getLogBase2(lhs);
auto lg2 = getLogBase2(rhs);
if (!lg1 && !lg2) {
continue;
}
if (lg1 < lg2) {
std::swap(lg1, lg2);
std::swap(lhs, rhs);
}

if (lg1) {
llvm::Value *lg_val = llvm::ConstantInt::get(
llvm::IntegerType::get(Func.getContext(), 32),
llvm::APInt(32, *lg1));

llvm::Value *val = llvm::BinaryOperator::Create(
llvm::Instruction::Shl, rhs, lg_val, op->getName(), op);

op->replaceAllUsesWith(val);
toRemove.push_back(op);
}
}
for (auto *I : toRemove) {
I->eraseFromParent();
}
}

auto PA = llvm::PreservedAnalyses::all();
return PA;
}

private:
std::optional<int> getLogBase2(llvm::Value *val) {
if (llvm::ConstantInt *CI = llvm::dyn_cast<llvm::ConstantInt>(val)) {
if (CI->getValue().isPowerOf2()) {
return CI->getValue().exactLogBase2();
}
}
if (auto *LI = llvm::dyn_cast<llvm::LoadInst>(val)) {
llvm::Value *Op = LI->getPointerOperand();
Op->reverseUseList();
llvm::StoreInst *StInst = nullptr;
for (auto *Inst : Op->users()) {
if (auto *SI = llvm::dyn_cast<llvm::StoreInst>(Inst)) {
StInst = SI;
}
if (Inst == LI) {
break;
}
}
Op->reverseUseList();
if (!StInst) {
return std::nullopt;
}
if (auto *CI =
llvm::dyn_cast<llvm::ConstantInt>(StInst->getValueOperand())) {
if (CI->getValue().isPowerOf2()) {
return CI->getValue().exactLogBase2();
}
}
}
return std::nullopt;
}
};
} // namespace

bool registerPlugin(llvm::StringRef Name, llvm::FunctionPassManager &FPM,
llvm::ArrayRef<llvm::PassBuilder::PipelineElement>) {
if (Name == "borovkovmulshifts") {
FPM.addPass(MulShifts());
return true;
}
return false;
}

llvm::PassPluginLibraryInfo getMulShiftsBorovkovPluginInfo() {
return {LLVM_PLUGIN_API_VERSION, "MulShifts", LLVM_VERSION_STRING,
[](llvm::PassBuilder &PB) {
PB.registerPipelineParsingCallback(registerPlugin);
}};
}

extern "C" LLVM_ATTRIBUTE_WEAK llvm::PassPluginLibraryInfo
llvmGetPassPluginInfo() {
return getMulShiftsBorovkovPluginInfo();
}
149 changes: 149 additions & 0 deletions llvm/test/lab2/borovkov_sergey/test.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
; RUN: opt -load-pass-plugin=%llvmshlibdir/MulShiftsBorovkovPlugin%shlibext -passes=borovkovmulshifts -S %s | FileCheck %s

;int f1(int a){
; int c = a + 4;
; return c;

define dso_local i32 @f1(i32 noundef %0) #0 {
%2 = alloca i32, align 4
%3 = alloca i32, align 4
store i32 %0, ptr %2, align 4
%4 = load i32, ptr %2, align 4
%5 = add nsw i32 %4, 4
store i32 %5, ptr %3, align 4
%6 = load i32, ptr %3, align 4
ret i32 %6
}

; CHECK-LABEL: @f1
; CHECK: %[[load:[0-9]+]] = load i32, ptr %2, align 4
; CHECK-NEXT: %5 = add nsw i32 %[[load]], 4
; CHECK-NEXT: store i32 %5, ptr %3, align 4
;}


;int f2(int a){
; int c = a * 4;
; return c;

define dso_local i32 @f2(i32 noundef %0) #0 {
%2 = alloca i32, align 4
%3 = alloca i32, align 4
store i32 %0, ptr %2, align 4
%4 = load i32, ptr %2, align 4
%5 = mul nsw i32 %4, 4
store i32 %5, ptr %3, align 4
%6 = load i32, ptr %3, align 4
ret i32 %6
}

; CHECK-LABEL: @f2
; CHECK: %[[load:[0-9]+]] = load i32, ptr %2, align 4
; CHECK-NEXT: %5 = shl i32 %[[load]], 2
; CHECK-NEXT: store i32 %5, ptr %3, align 4
;}


;void f3(){
; int a = 3;
; int c = a * 4;

define dso_local void @f3() #0 {
%1 = alloca i32, align 4
%2 = alloca i32, align 4
store i32 3, ptr %1, align 4
%3 = load i32, ptr %1, align 4
%4 = mul nsw i32 %3, 4
store i32 %4, ptr %2, align 4
ret void
}

; CHECK-LABEL: @f3
; CHECK: %[[load:[0-9]+]] = load i32, ptr %1, align 4
; CHECK-NEXT: %4 = shl i32 %[[load]], 2
; CHECK-NEXT: store i32 %4, ptr %2, align 4
;}


;void f4(){
; int a = 3;
; int c = 4 * a;

define dso_local void @f4() #0 {
%1 = alloca i32, align 4
%2 = alloca i32, align 4
store i32 3, ptr %1, align 4
%3 = load i32, ptr %1, align 4
%4 = mul nsw i32 4, %3
store i32 %4, ptr %2, align 4
ret void
}

; CHECK-LABEL: @f4
; CHECK: %[[load:[0-9]+]] = load i32, ptr %1, align 4
; CHECK-NEXT: %4 = shl i32 %[[load]], 2
; CHECK-NEXT: store i32 %4, ptr %2, align 4
;}


;void f5(){
; int a = 4;
; int c = a * 1;
;}

define dso_local void @f5() #0 {
%1 = alloca i32, align 4
%2 = alloca i32, align 4
store i32 4, ptr %1, align 4
%3 = load i32, ptr %1, align 4
%4 = mul nsw i32 %3, 1
store i32 %4, ptr %2, align 4
ret void
}

; CHECK-LABEL: @f5
; CHECK: %3 = load i32, ptr %1, align 4
; CHECK-NEXT: %4 = shl i32 1, 2
; CHECK-NEXT: store i32 %4, ptr %2, align 4


;void f6(){
; int a = 3;
; int c = 0 * a;
;}

define dso_local void @f6() #0 {
%1 = alloca i32, align 4
%2 = alloca i32, align 4
store i32 3, ptr %1, align 4
%3 = load i32, ptr %1, align 4
%4 = mul nsw i32 0, %3
store i32 %4, ptr %2, align 4
ret void
}

; CHECK-LABEL: @f6
; CHECK: %3 = load i32, ptr %1, align 4
; CHECK-NEXT: %4 = mul nsw i32 0, %3
; CHECK-NEXT: store i32 %4, ptr %2, align 4


;void f7(){
; int a = 4;
; int c = a * 3;
;}

define dso_local void @f7() #0 {
%1 = alloca i32, align 4
%2 = alloca i32, align 4
store i32 4, ptr %1, align 4
%3 = load i32, ptr %1, align 4
%4 = mul nsw i32 %3, 3
store i32 %4, ptr %2, align 4
ret void
}

; CHECK-LABEL: @f7
; CHECK: %3 = load i32, ptr %1, align 4
; CHECK-NEXT: %4 = shl i32 3, 2
; CHECK-NEXT: store i32 %4, ptr %2, align 4

0 comments on commit f36d729

Please sign in to comment.