Skip to content

Маркин Иван. Лабораторная работа 2: LLVM. Вариант 3. #158

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: course-spring-2025
Choose a base branch
from
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
14 changes: 14 additions & 0 deletions llvm/compiler-course/llvm-ir/markin_i_fmuladd/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
set(Title "FmuladdMergePass")
set(Student "MarkinIvan")
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()
101 changes: 101 additions & 0 deletions llvm/compiler-course/llvm-ir/markin_i_fmuladd/MergePass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Support/raw_ostream.h"

namespace {

struct FmulFaddMergePass final : llvm::PassInfoMixin<FmulFaddMergePass> {
llvm::PreservedAnalyses run(llvm::Function &F,
llvm::FunctionAnalysisManager &FAM) {
bool codeChanged = false;

struct ReplaceCandidate {
llvm::BinaryOperator *faddInst;
llvm::BinaryOperator *fmulInst;
llvm::Value *otherOperand;
};

for (llvm::BasicBlock &block : F) {
std::vector<ReplaceCandidate> candidates;

auto isFMulOperand = [](llvm::Value *op,
llvm::Value *other) -> llvm::BinaryOperator * {
if (auto *fmul = llvm::dyn_cast<llvm::BinaryOperator>(op)) {
if (fmul->getOpcode() == llvm::Instruction::FMul) {
return fmul;
}
}
return nullptr;
};

// Collect potential replacements
for (llvm::Instruction &inst : block) {
if (auto *fadd = llvm::dyn_cast<llvm::BinaryOperator>(&inst)) {
if (fadd->getOpcode() == llvm::Instruction::FAdd) {
llvm::Value *op0 = fadd->getOperand(0);
llvm::Value *op1 = fadd->getOperand(1);

if (auto *fmul = isFMulOperand(op0, op1)) {
if (fmul->hasAllowContract() && fadd->hasAllowContract()) {
candidates.push_back({fadd, fmul, op1});
}
} else if (auto *fmul = isFMulOperand(op1, op0)) {
if (fmul->hasAllowContract() && fadd->hasAllowContract()) {
candidates.push_back({fadd, fmul, op0});
}
}
}
}
}

// Perform replacements
for (const auto &candidate : candidates) {
llvm::IRBuilder<> builder(candidate.faddInst);
llvm::FastMathFlags flags = candidate.faddInst->getFastMathFlags();
llvm::Value *fmuladd = builder.CreateIntrinsic(
llvm::Intrinsic::fmuladd, candidate.fmulInst->getType(),
{candidate.fmulInst->getOperand(0),
candidate.fmulInst->getOperand(1), candidate.otherOperand});

if (llvm::isa<llvm::FPMathOperator>(fmuladd)) {
llvm::FPMathOperator *fmuladdInst =
llvm::cast<llvm::FPMathOperator>(fmuladd);
}

candidate.faddInst->replaceAllUsesWith(fmuladd);
candidate.faddInst->eraseFromParent();

if (candidate.fmulInst->use_empty()) {
candidate.fmulInst->eraseFromParent();
}
codeChanged = true;
}
}

return codeChanged ? llvm::PreservedAnalyses::none()
: llvm::PreservedAnalyses::all();
}

static bool isRequired() { return true; }
};

} // namespace

extern "C" LLVM_ATTRIBUTE_WEAK ::llvm::PassPluginLibraryInfo
llvmGetPassPluginInfo() {
return {LLVM_PLUGIN_API_VERSION, "FmulFaddMergePass", "0.1",
[](llvm::PassBuilder &PB) {
PB.registerPipelineParsingCallback(
[](llvm::StringRef passName, llvm::FunctionPassManager &FPM,
llvm::ArrayRef<llvm::PassBuilder::PipelineElement>) -> bool {
if (passName == "FmulFaddMergePass") {
FPM.addPass(FmulFaddMergePass{});
return true;
}
return false;
});
}};
}
90 changes: 90 additions & 0 deletions llvm/test/compiler-course/markin_i_fmulladdmerge/test.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
; RUN: opt -load-pass-plugin %llvmshlibdir/FmuladdMergePass_MarkinIvan_FIIT2_LLVM_IR%pluginext \
; RUN: -passes="FmulFaddMergePass" -S %s | FileCheck %s

; CHECK-LABEL: @fmaDouble
; CHECK: call double @llvm.fmuladd.f64(double %A, double %B, double %C)
; CHECK-NOT: fmul
; CHECK-NOT: fadd
define dso_local noundef double @fmaDouble(double %A, double %B, double %C) {
entry:
%mul = fmul contract double %A, %B
%add = fadd contract double %mul, %C
ret double %add
}

; CHECK-LABEL: @fmaFloat
; CHECK: call float @llvm.fmuladd.f32(float %A, float %B, float %C)
; CHECK-NOT: fmul
; CHECK-NOT: fadd
define dso_local noundef float @fmaFloat(float %A, float %B, float %C) {
entry:
%mul = fmul contract float %A, %B
%add = fadd contract float %mul, %C
ret float %add
}

; CHECK-LABEL: @recursiveTest
; CHECK: call float @llvm.fmuladd.f32(float %add1, float %B, float %add)
; CHECK-NOT: fmul
; CHECK-NOT: fadd
define dso_local noundef float @recursiveTest(float %A, float %B, float %C) {
entry:
%add = fadd contract float %B, %C
%add1 = fadd contract float %A, %B
%mul = fmul contract float %add1, %B
%add2 = fadd contract float %add, %mul
ret float %add2
}

; CHECK-LABEL: @foo
; CHECK: %0 = call float @llvm.fmuladd.f32(float %A, float %B, float %C)
; CHECK: %1 = call float @llvm.fmuladd.f32(float %A, float %B, float 1.000000e+00)
; CHECK: %div = fdiv float %0, %1
; CHECK-NOT: %mul = fmul contract float %A, %B
; CHECK-NOT: fadd
define float @foo(float %A, float %B, float %C) {
entry:
%mul = fmul contract float %A, %B
%add = fadd contract float %mul, %C
%add1 = fadd contract float %mul, 1.000000e+00
%div = fdiv float %add, %add1
ret float %div
}
; CHECK-LABEL: @noContract
; CHECK: fmul float %A, %B
; CHECK: fadd float %mul, %C
define float @noContract(float %A, float %B, float %C) {
entry:
%mul = fmul float %A, %B
%add = fadd float %mul, %C
ret float %add
}
; CHECK-LABEL: @multipleFMA
; CHECK: call float @llvm.fmuladd.f32(float %A, float %B, float %C)
; CHECK: call float @llvm.fmuladd.f32(float %D, float %E, float %F)
define float @multipleFMA(float %A, float %B, float %C, float %D, float %E, float %F) {
entry:
%mul1 = fmul contract float %A, %B
%add1 = fadd contract float %mul1, %C
%mul2 = fmul contract float %D, %E
%add2 = fadd contract float %mul2, %F
ret float %add2
}
; CHECK-LABEL: @differentArduments
; CHECK: fmul contract float %A, %B
; CHECK: fadd contract float %B, %D
define float @differentArduments(float %A, float %B, float %D) {
entry:
%mul = fmul contract float %A, %B
%add = fadd contract float %B, %D
ret float %add
}
; CHECK-LABEL: @differentInstructions
; CHECK: fadd contract float %A, %B
; CHECK: fadd contract float %add1, %D
define float @differentInstructions(float %A, float %B, float %D) {
entry:
%add1 = fadd contract float %A, %B
%add = fadd contract float %add1, %D
ret float %add
}
Loading