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

Commit be5582a

Browse files
authored
Savotina Valeria, Lab №1, var: 2. (#27)
The plugin allows all functions that don't have conditions (for example, if, do...while, etc.), add the always_inline attribute.
1 parent 352b34e commit be5582a

File tree

3 files changed

+182
-0
lines changed

3 files changed

+182
-0
lines changed
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
#include "clang/AST/ASTConsumer.h"
2+
#include "clang/AST/RecursiveASTVisitor.h"
3+
#include "clang/Frontend/CompilerInstance.h"
4+
#include "clang/Frontend/FrontendPluginRegistry.h"
5+
#include "llvm/Support/raw_ostream.h"
6+
7+
namespace {
8+
class AddAttrAlwaysInlineVisitor final
9+
: public clang::RecursiveASTVisitor<AddAttrAlwaysInlineVisitor> {
10+
public:
11+
explicit AddAttrAlwaysInlineVisitor(clang::ASTContext *context_)
12+
: context(context_) {}
13+
bool VisitFunctionDecl(clang::FunctionDecl *decl) {
14+
if (!decl->isFunctionOrFunctionTemplate())
15+
return true;
16+
if (decl->hasAttr<clang::AlwaysInlineAttr>())
17+
return true;
18+
if (auto body = decl->getBody()) {
19+
if (findСonditionalStatement(body))
20+
return true;
21+
if (auto loc = decl->getSourceRange(); loc.isValid())
22+
decl->addAttr(
23+
clang::AlwaysInlineAttr::Create(*context, loc.getBegin()));
24+
}
25+
return true;
26+
}
27+
28+
private:
29+
bool findСonditionalStatement(clang::Stmt *statement) {
30+
if (!statement)
31+
return false;
32+
33+
if (clang::isa<clang::IfStmt>(statement) ||
34+
clang::isa<clang::SwitchStmt>(statement) ||
35+
clang::isa<clang::DoStmt>(statement) ||
36+
clang::isa<clang::WhileStmt>(statement) ||
37+
clang::isa<clang::ForStmt>(statement))
38+
return true;
39+
40+
if (auto parent = clang::dyn_cast<clang::CompoundStmt>(statement)) {
41+
for (auto child : parent->body()) {
42+
if (findСonditionalStatement(child))
43+
return true;
44+
}
45+
}
46+
return false;
47+
}
48+
49+
void outStatusAttrAlwaysInline(clang::FunctionDecl *func) {
50+
llvm::outs() << "function: " << func->getNameAsString() << '\n';
51+
llvm::outs() << "attr status (always_inline): "
52+
<< (func->hasAttr<clang::AlwaysInlineAttr>() ? "true\n"
53+
: "false\n");
54+
}
55+
56+
private:
57+
clang::ASTContext *context;
58+
};
59+
60+
class AddAttrAlwaysInlineConsumer final : public clang::ASTConsumer {
61+
public:
62+
explicit AddAttrAlwaysInlineConsumer(clang::ASTContext *сontext)
63+
: visitor(сontext) {}
64+
65+
void HandleTranslationUnit(clang::ASTContext &context) override {
66+
visitor.TraverseDecl(context.getTranslationUnitDecl());
67+
}
68+
69+
private:
70+
AddAttrAlwaysInlineVisitor visitor;
71+
};
72+
73+
class AddAttrAlwaysInlineAction final : public clang::PluginASTAction {
74+
public:
75+
std::unique_ptr<clang::ASTConsumer>
76+
CreateASTConsumer(clang::CompilerInstance &ci, llvm::StringRef) override {
77+
return std::make_unique<AddAttrAlwaysInlineConsumer>(&ci.getASTContext());
78+
}
79+
80+
bool ParseArgs(const clang::CompilerInstance &ci,
81+
const std::vector<std::string> &args) override {
82+
for (const auto &arg : args) {
83+
if (arg == "--help") {
84+
llvm::outs() << "Adds the always_inline attribute to functions without "
85+
"conditions\n";
86+
}
87+
}
88+
return true;
89+
}
90+
};
91+
} // namespace
92+
93+
static clang::FrontendPluginRegistry::Add<AddAttrAlwaysInlineAction>
94+
X("add_attr_always_inline_plugin",
95+
"Adds the always_inline attribute to functions without conditions");
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
add_llvm_library(AddAttrAlwaysInlinePlugin MODULE AddAttrAlwaysInline.cpp PLUGIN_TOOL clang)
2+
3+
if(WIN32 OR CYGWIN)
4+
set(LLVM_LINK_COMPONENTS
5+
Support
6+
)
7+
clang_target_link_libraries(AddAttrAlwaysInlinePlugin PRIVATE
8+
clangAST
9+
clangBasic
10+
clangFrontend
11+
)
12+
endif()
13+
14+
set(CLANG_TEST_DEPS "AddAttrAlwaysInlinePlugin" ${CLANG_TEST_DEPS} PARENT_SCOPE)
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// RUN: %clang_cc1 -load %llvmshlibdir/AddAttrAlwaysInlinePlugin%pluginext\
2+
// RUN: -plugin add_attr_always_inline_plugin\
3+
// RUN: -plugin-arg-add_attr_always_inline_plugin --help %s 2>&1 | FileCheck %s --check-prefix=CHECK-HELP
4+
// CHECK-HELP: Adds the always_inline attribute to functions without conditions
5+
6+
// RUN: %clang_cc1 -load %llvmshlibdir/AddAttrAlwaysInlinePlugin%pluginext\
7+
// RUN: -add-plugin add_attr_always_inline_plugin %s\
8+
// RUN: -ast-dump %s -ast-dump-filter test | FileCheck %s
9+
10+
namespace {
11+
// 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]+) testSquare 'int \(int\)'}}
12+
int testSquare(int value) { return value * value; }
13+
14+
// 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]+) testDiff 'int \(int, int\)'}}
15+
int testDiff(int valueOne, int valueTwo) {
16+
{} {} {{} {}} {} {{{}} {} {}} {} {
17+
{ return valueOne - valueTwo; }
18+
}
19+
}
20+
21+
// 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 \(\)'}}
22+
void testEmptyFunc() {
23+
{} {{}} {{} {} {{{{}}}}} {}
24+
}
25+
26+
// 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\)'}}
27+
bool testIfStmt(int value) {
28+
if (value % 2)
29+
return false;
30+
return true;
31+
}
32+
// CHECK-NOT: `-AlwaysInlineAttr {{0[xX][0-9a-fA-F]+ <(line|col):([0-9]+:[0-9]|[0-9]+)> Implicit always_inline}}
33+
34+
// 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]+) testSwitchStmt 'int \(int\)'}}
35+
int testSwitchStmt(int value) {
36+
switch (value) {
37+
case 1:
38+
return value;
39+
case 2:
40+
return value;
41+
case 3:
42+
return value;
43+
default:
44+
return value;
45+
}
46+
}
47+
// CHECK-NOT: `-AlwaysInlineAttr {{0[xX][0-9a-fA-F]+ <(line|col):([0-9]+:[0-9]|[0-9]+)> Implicit always_inline}}
48+
49+
// 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]+) testWhileStmt 'void \(int\)'}}
50+
void testWhileStmt(int value) {
51+
{
52+
while (value--) {
53+
}
54+
}
55+
{} {}
56+
}
57+
// CHECK-NOT: `-AlwaysInlineAttr {{0[xX][0-9a-fA-F]+ <(line|col):([0-9]+:[0-9]|[0-9]+)> Implicit always_inline}}
58+
59+
// 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]+) testDoStmt 'void \(int\)'}}
60+
void testDoStmt(int value) {
61+
do {
62+
--value;
63+
} while (value);
64+
}
65+
// CHECK-NOT: `-AlwaysInlineAttr {{0[xX][0-9a-fA-F]+ <(line|col):([0-9]+:[0-9]|[0-9]+)> Implicit always_inline}}
66+
67+
// 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]+) testForStmt 'void \(unsigned int\)'}}
68+
void testForStmt(unsigned value) {
69+
for (unsigned i = 0; i < value; ++i) {
70+
}
71+
}
72+
// CHECK-NOT: `-AlwaysInlineAttr {{0[xX][0-9a-fA-F]+ <(line|col):([0-9]+:[0-9]|[0-9]+)> Implicit always_inline}}
73+
} // namespace

0 commit comments

Comments
 (0)