diff --git a/clang/lab1/plugin/.clang-format b/clang/lab1/plugin/.clang-format new file mode 100644 index 00000000000000..f170fa67ff2aa5 --- /dev/null +++ b/clang/lab1/plugin/.clang-format @@ -0,0 +1,66 @@ +# Generated from CLion C/C++ Code Style settings +BasedOnStyle: LLVM +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: None +AlignOperands: Align +AllowAllArgumentsOnNextLine: false +AllowAllConstructorInitializersOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: Always +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Always +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterReturnType: None +AlwaysBreakTemplateDeclarations: Yes +BreakBeforeBraces: Custom +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: true +BreakBeforeBinaryOperators: None +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeColon +BreakInheritanceList: BeforeColon +ColumnLimit: 0 +CompactNamespaces: false +ContinuationIndentWidth: 8 +IndentCaseLabels: true +IndentPPDirectives: None +IndentWidth: 4 +KeepEmptyLinesAtTheStartOfBlocks: true +MaxEmptyLinesToKeep: 2 +NamespaceIndentation: All +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PointerAlignment: Right +ReflowComments: false +SpaceAfterCStyleCast: true +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 0 +SpacesInAngles: false +SpacesInCStyleCastParentheses: false +SpacesInContainerLiterals: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +TabWidth: 4 +UseTab: Never diff --git a/clang/lab1/plugin/AlwaysInlineNoCondition.cpp b/clang/lab1/plugin/AlwaysInlineNoCondition.cpp new file mode 100644 index 00000000000000..d09c54b358d8e2 --- /dev/null +++ b/clang/lab1/plugin/AlwaysInlineNoCondition.cpp @@ -0,0 +1,66 @@ +#include "llvm/Passes/PassPlugin.h" +#include "llvm/IR/PassManager.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Attributes.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Passes/PassBuilder.h" + +using namespace llvm; + +namespace { + class AlwaysInlineNoConditionPass : public PassInfoMixin { + public: + PreservedAnalyses run(Function &func, FunctionAnalysisManager &) { + errs() << "Running pass on function: " << func.getName() << "\n"; + bool hasCondition = false; + + for (BasicBlock &basicBlock : func) { + for (Instruction &inst : basicBlock) { + if (isa(&inst) || isa(&inst)) { + if (auto *branchInst = dyn_cast(&inst)) { + errs() << "Found conditional branch in function: " << func.getName() << "\n"; + hasCondition = true; + break; + } else if (isa(&inst)) { + errs() << "Found switch instruction in function: " << func.getName() << "\n"; + hasCondition = true; + break; + } + } + } + if (hasCondition) { + break; + } + } + + if (!hasCondition) { + func.addFnAttr(Attribute::AlwaysInline); + errs() << "Added always_inline to function: " << func.getName() << "\n"; + } else { + errs() << "Did not add always_inline to function: " << func.getName() << " because it has conditions\n"; + func.addFnAttr(Attribute::NoInline); + } + + return PreservedAnalyses::all(); + } + }; + +} + +extern "C" LLVM_ATTRIBUTE_WEAK PassPluginLibraryInfo llvmGetPassPluginInfo() { + return { + LLVM_PLUGIN_API_VERSION, "AlwaysInlineNoConditionPass", LLVM_VERSION_STRING, + [](PassBuilder &passBuilder) { + passBuilder.registerPipelineParsingCallback( + [](StringRef name, FunctionPassManager &functionPassManager, + ArrayRef) { + if (name == "always-inline-no-condition") { + functionPassManager.addPass(AlwaysInlineNoConditionPass()); + return true; + } + return false; + }); + } + }; +} diff --git a/clang/lab1/plugin/CMakeLists.txt b/clang/lab1/plugin/CMakeLists.txt new file mode 100644 index 00000000000000..a3cfb4cd1c8865 --- /dev/null +++ b/clang/lab1/plugin/CMakeLists.txt @@ -0,0 +1,24 @@ +cmake_minimum_required(VERSION 3.13) +project(AlwaysInlineNoConditionPass) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED YES) +set(CMAKE_CXX_EXTENSIONS NO) + +find_package(LLVM REQUIRED CONFIG) +list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") +include(AddLLVM) + +include_directories(${LLVM_INCLUDE_DIRS}) +link_directories(${LLVM_LIBRARY_DIRS}) + +add_definitions(${LLVM_DEFINITIONS}) + +set(CMAKE_SHARED_MODULE_SUFFIX ".so") + +add_llvm_library(AlwaysInlineNoConditionPass MODULE + AlwaysInlineNoCondition.cpp + + PLUGIN_TOOL + opt +) diff --git a/clang/lab1/plugin/Dockerfile b/clang/lab1/plugin/Dockerfile new file mode 100644 index 00000000000000..b101f939cbd872 --- /dev/null +++ b/clang/lab1/plugin/Dockerfile @@ -0,0 +1,8 @@ +FROM ubuntu:latest + +RUN apt-get update && apt-get install -y \ + build-essential \ + cmake \ + clang \ + llvm \ + && rm -rf /var/lib/apt/lists/* \ diff --git a/clang/lab1/plugin/build.sh b/clang/lab1/plugin/build.sh new file mode 100755 index 00000000000000..c1ae24d45b0dbd --- /dev/null +++ b/clang/lab1/plugin/build.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +mkdir -p build +cd build + +cmake .. +make diff --git a/clang/lab1/plugin/run.sh b/clang/lab1/plugin/run.sh new file mode 100755 index 00000000000000..a58d1d88fe7552 --- /dev/null +++ b/clang/lab1/plugin/run.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +/usr/bin/clang++ -O1 -S -emit-llvm -o test/test.ll test/test.cpp + +/usr/bin/opt -load-pass-plugin ./build/AlwaysInlineNoConditionPass.so -passes=always-inline-no-condition -debug-pass-manager -S test/test.ll -o test/testOpt.ll + +echo "Compilation and plugin application completed. Executable created: testOpt.ll" + +echo "Run tests...(By default - OK)" +/usr/bin/FileCheck-18 --dump-input=fail test/test.cpp < test/testOpt.ll diff --git a/clang/lab1/plugin/test/test.cpp b/clang/lab1/plugin/test/test.cpp new file mode 100644 index 00000000000000..1c2c93d8e76529 --- /dev/null +++ b/clang/lab1/plugin/test/test.cpp @@ -0,0 +1,59 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s | opt -load /plugin/build/AlwaysInlineNoConditionPass.so -passes=always-inline-no-condition -S | FileCheck %s + + +// CHECK:; Function Attrs: alwaysinline mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) uwtable +// CHECK-NEXT:define dso_local void @_Z10inlineFuncRi(ptr nocapture noundef nonnull align 4 dereferenceable(4) %0) local_unnamed_addr #0 { + +void inlineFunc(int &var) { + ++var; +} + + +// CHECK:; Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable +// CHECK-NEXT:define dso_local noundef i1 @_Z15notInlineFunc_1i(i32 noundef %0) local_unnamed_addr #1 { + +bool notInlineFunc_1(int var) { + if (var == 2 || var == 22) { + return false; + } else { + return true; + } +} + + +// CHECK:; Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable +// CHECK-NEXT:define dso_local noundef i32 @_Z15notInlineFunc_2b(i1 noundef %0) local_unnamed_addr #1 { + +int notInlineFunc_2(const bool var) { + int a = var ? 3 : 0; + return a; +} + + +// CHECK:; Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable +// CHECK-NEXT:define dso_local noundef i32 @_Z15notInlineFunc_3i(i32 noundef %0) local_unnamed_addr #1 { + +int notInlineFunc_3(int var) { + switch (var) { + case 1: + return true; + default: + return false; + } +} + + +// CHECK:; Function Attrs: alwaysinline mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable +// CHECK-NEXT:define dso_local noundef i32 @main() local_unnamed_addr #2 { + +int main() { + int a = 4; + inlineFunc(a); + notInlineFunc_1(12); + notInlineFunc_2(true); + notInlineFunc_3(a); +} + +// CHECK:attributes #0 = { alwaysinline mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) uwtable "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+fp-armv8,+neon,+outline-atomics,+v8a,-fmv" } +// CHECK-NEXT:attributes #1 = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+fp-armv8,+neon,+outline-atomics,+v8a,-fmv" } +// CHECK-NEXT:attributes #2 = { alwaysinline mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+fp-armv8,+neon,+outline-atomics,+v8a,-fmv" }