Skip to content

Commit 55f41b7

Browse files
authored
Merge pull request #683 from glu-lang/parse-llvm
Feature: Decompile LLVM IR (Print Interface from IR)
2 parents f68a35b + dfda9a8 commit 55f41b7

20 files changed

Lines changed: 419 additions & 131 deletions

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,10 @@ build/
4444
coverage_html/
4545
*.profdata
4646
*.profraw
47+
*.profraw.*
4748
Output/
4849
*.lit*
50+
test/functional/lit.cfg
4951

5052
.idea/
5153
.vscode/

include/Basic/SourceLocation.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class FileID {
1919
friend struct llvm::DenseMapInfo<FileID>;
2020

2121
/// The opaque identifier for the file.
22-
int _id = 0;
22+
int _id = -1;
2323

2424
///
2525
/// @brief A FileID can only be created by the SourceManager (a friend
@@ -28,9 +28,10 @@ class FileID {
2828
/// @param id The opaque identifier for the file.
2929
/// @note This constructor is private to prevent clients from using it.
3030
///
31-
FileID(int id) : _id(id) { }
31+
explicit FileID(int id) : _id(id) { }
3232

3333
public:
34+
FileID() = default;
3435
FileID(FileID const &id) = default;
3536
FileID &operator=(FileID const &id) = default;
3637
FileID(FileID &&id) = default;

lib/ASTPrinter/CodePrinter.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ class CodePrinter : public ASTVisitor<CodePrinter> {
130130
/// @param node The ParamDecl node to print
131131
void visitParamDecl(ParamDecl *node)
132132
{
133-
visit(node->getAttributes());
133+
visitAttributeList(node->getAttributes());
134134
_out << node->getName() << ": ";
135135
printType(node->getType());
136136
}
@@ -171,6 +171,8 @@ class CodePrinter : public ASTVisitor<CodePrinter> {
171171

172172
void visitAttributeList(AttributeList *node)
173173
{
174+
if (!node)
175+
return;
174176
for (auto *attr : node->getAttributes()) {
175177
visit(attr);
176178
_out << " ";
@@ -197,7 +199,7 @@ class CodePrinter : public ASTVisitor<CodePrinter> {
197199
void printDeclPrefix(DeclBase *decl)
198200
{
199201
printIndent();
200-
visit(decl->getAttributes());
202+
visitAttributeList(decl->getAttributes());
201203
printVisibility(decl->getVisibility());
202204
}
203205

lib/Basic/SourceManager.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ glu::SourceManager::loadFile(llvm::StringRef filePath)
4343

4444
llvm::MemoryBuffer *glu::SourceManager::getBuffer(FileID fileId) const
4545
{
46-
if (fileId._id >= static_cast<int>(_fileLocEntries.size())) {
46+
if (static_cast<size_t>(fileId._id) >= _fileLocEntries.size()) {
4747
return nullptr;
4848
}
4949

lib/IRDec/DITypeLifter.cpp

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ DITypeLifter::handleBasicType(llvm::DIBasicType const *diBasicType) const
2222
case llvm::dwarf::DW_ATE_boolean: return arena.create<types::BoolTy>();
2323
case llvm::dwarf::DW_ATE_address:
2424
return arena.create<types::PointerTy>(arena.create<types::CharTy>());
25+
case llvm::dwarf::DW_ATE_unsigned_char:
26+
case llvm::dwarf::DW_ATE_signed_char: return arena.create<types::CharTy>();
2527
default: return nullptr;
2628
}
2729
}
@@ -35,6 +37,7 @@ DITypeLifter::handleComposedTypes(llvm::DICompositeType const *diCompositeType)
3537
auto &astArena = _context.getASTMemoryArena();
3638
auto tag = diCompositeType->getTag();
3739
switch (tag) {
40+
case llvm::dwarf::DW_TAG_class_type:
3841
case llvm::dwarf::DW_TAG_structure_type: {
3942
if (auto it = _declBindings.find(diCompositeType);
4043
it != _declBindings.end()) {
@@ -59,7 +62,7 @@ DITypeLifter::handleComposedTypes(llvm::DICompositeType const *diCompositeType)
5962
fieldDecls.push_back(astArena.create<ast::FieldDecl>(
6063
SourceLocation::invalid,
6164
copyString(fieldName.str(), astArena.getAllocator()),
62-
fieldType
65+
fieldType, nullptr, nullptr, ast::Visibility::Public
6366
));
6467
}
6568
}
@@ -69,7 +72,7 @@ DITypeLifter::handleComposedTypes(llvm::DICompositeType const *diCompositeType)
6972
copyString(
7073
diCompositeType->getName().str(), astArena.getAllocator()
7174
),
72-
fieldDecls
75+
fieldDecls, ast::Visibility::Public
7376
);
7477
_declBindings[diCompositeType] = structDecl;
7578
return typesArena.create<StructTy>(structDecl);
@@ -151,13 +154,10 @@ DITypeLifter::handleDerivedType(llvm::DIDerivedType const *diDerivedType)
151154
}
152155
return typesArena.create<PointerTy>(baseType);
153156
}
154-
case llvm::dwarf::DW_TAG_typedef: {
155-
auto *baseType = lift(diDerivedType->getBaseType());
156-
if (!baseType) {
157-
return nullptr;
158-
}
159-
return baseType;
160-
}
157+
case llvm::dwarf::DW_TAG_typedef:
158+
case llvm::dwarf::DW_TAG_const_type:
159+
case llvm::dwarf::DW_TAG_volatile_type:
160+
return lift(diDerivedType->getBaseType());
161161
default: return nullptr;
162162
}
163163
}
@@ -176,21 +176,19 @@ glu::types::TypeBase *DITypeLifter::handleSubroutineType(
176176
}
177177

178178
// First element is return type
179-
auto *returnType = lift(llvm::cast<llvm::DIType>(types[0]));
179+
auto *returnType = lift(types[0]);
180180
if (!returnType) {
181181
return nullptr;
182182
}
183183

184184
// Remaining elements are parameter types
185185
llvm::SmallVector<TypeBase *, 4> paramTypes;
186186
for (size_t i = 1; i < types.size(); ++i) {
187-
if (auto *diType = llvm::dyn_cast_if_present<llvm::DIType>(types[i])) {
188-
auto *paramType = lift(diType);
189-
if (!paramType) {
190-
return nullptr;
191-
}
192-
paramTypes.push_back(paramType);
187+
auto *paramType = lift(types[i]);
188+
if (!paramType) {
189+
return nullptr;
193190
}
191+
paramTypes.push_back(paramType);
194192
}
195193

196194
return FunctionTy::create(
@@ -201,7 +199,7 @@ glu::types::TypeBase *DITypeLifter::handleSubroutineType(
201199
glu::types::TypeBase *DITypeLifter::lift(llvm::DIType const *diType)
202200
{
203201
if (!diType) {
204-
return nullptr;
202+
return _context.getTypesMemoryArena().create<types::VoidTy>();
205203
}
206204
switch (diType->getMetadataID()) {
207205
case llvm::Metadata::MetadataKind::DIBasicTypeKind:

lib/IRDec/ModuleLifter.cpp

Lines changed: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#include "ModuleLifter.hpp"
2+
#include "AST/Exprs.hpp"
23
#include "DITypeLifter.hpp"
34
#include "GILGen/GILGen.hpp"
5+
#include "TypeLifter.hpp"
46
#include "llvm/IR/Function.h"
57

68
namespace glu::irdec {
@@ -39,35 +41,67 @@ class ModuleLifter {
3941

4042
glu::ast::ModuleDecl *detectExternalFunctions()
4143
{
42-
DITypeLifter typeLifter(_astContext);
44+
DITypeLifter diTypeLifter(_astContext);
45+
TypeLifter typeLifter(_astContext);
4346
std::vector<glu::ast::DeclBase *> decls;
47+
auto &astArena = _astContext.getASTMemoryArena();
4448

4549
for (auto &func : _llvmModule->functions()) {
4650
if (!func.isDeclaration()
4751
&& func.getLinkage() == llvm::Function::ExternalLinkage) {
48-
auto subProgram = func.getSubprogram();
49-
if (!subProgram)
52+
types::Ty type;
53+
llvm::StringRef funcName = func.getName();
54+
if (auto subprogram = func.getSubprogram()) {
55+
type = diTypeLifter.lift(subprogram->getType());
56+
funcName = subprogram->getName();
57+
} else {
58+
type = typeLifter.lift(func.getFunctionType());
59+
}
60+
auto funcType
61+
= llvm::dyn_cast_if_present<glu::types::FunctionTy>(type);
62+
if (!funcType)
5063
continue;
51-
auto type = typeLifter.lift(subProgram->getType());
52-
if (auto funcType
53-
= llvm::dyn_cast_if_present<glu::types::FunctionTy>(type)) {
54-
auto funcDecl
55-
= _astContext.getASTMemoryArena()
56-
.create<glu::ast::FunctionDecl>(
57-
SourceLocation::invalid, nullptr,
58-
func.getName(), funcType,
59-
generateParamsDecls(funcType->getParameters()
60-
),
61-
nullptr, glu::ast::Visibility::Public
62-
);
63-
decls.push_back(funcDecl);
64+
llvm::SmallVector<ast::Attribute *, 4> attrs;
65+
if (funcName != func.getName()) {
66+
auto *attr = astArena.create<ast::Attribute>(
67+
ast::AttributeKind::LinkageNameKind,
68+
SourceLocation::invalid,
69+
astArena.create<ast::LiteralExpr>(
70+
func.getName(), nullptr, SourceLocation::invalid
71+
)
72+
);
73+
attrs.push_back(attr);
74+
} else {
75+
auto *attr = astArena.create<ast::Attribute>(
76+
ast::AttributeKind::NoManglingKind,
77+
SourceLocation::invalid, nullptr
78+
);
79+
attrs.push_back(attr);
80+
}
81+
if (func.isVarArg()) {
82+
auto *attr = astArena.create<ast::Attribute>(
83+
ast::AttributeKind::CVariadicKind,
84+
SourceLocation::invalid, nullptr
85+
);
86+
attrs.push_back(attr);
6487
}
88+
ast::AttributeList *attributes
89+
= astArena.create<ast::AttributeList>(
90+
attrs, SourceLocation::invalid
91+
);
92+
auto funcDecl = astArena.create<glu::ast::FunctionDecl>(
93+
SourceLocation::invalid, nullptr, funcName, funcType,
94+
generateParamsDecls(funcType->getParameters()), nullptr,
95+
glu::ast::Visibility::Public, attributes
96+
);
97+
decls.push_back(funcDecl);
6598
}
6699
}
67100

68-
for (auto decl : typeLifter.getDeclBindings()) {
101+
for (auto decl : diTypeLifter.getDeclBindings()) {
69102
decls.push_back(decl.second);
70103
}
104+
// FIXME: Do the same with typeLifter!!!
71105
return _astContext.getASTMemoryArena().create<glu::ast::ModuleDecl>(
72106
SourceLocation::invalid, std::move(decls), &_astContext
73107
);

lib/IRGen/IRGen.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,13 @@ struct IRGenVisitor : public glu::gil::InstVisitor<IRGenVisitor> {
154154
/*Flags=*/"",
155155
/*RuntimeVersion=*/0
156156
);
157+
ctx.outModule.addModuleFlag(
158+
llvm::Module::Warning, "Debug Info Version",
159+
llvm::DEBUG_METADATA_VERSION
160+
);
161+
ctx.outModule.addModuleFlag(
162+
llvm::Module::Warning, "Dwarf Version", 4
163+
);
157164
}
158165
}
159166

test/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,5 @@ target_sources(unit_tests
6060

6161
include(GoogleTest)
6262
gtest_discover_tests(unit_tests)
63+
64+
add_subdirectory(functional)

test/IRDec/ModuleLifterTest.cpp

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -556,7 +556,7 @@ TEST_F(ModuleLifterTest, IgnoreFunctionDeclarations)
556556
); // Function declarations are ignored
557557
}
558558

559-
TEST_F(ModuleLifterTest, IgnoreFunctionsWithoutDebugInfo)
559+
TEST_F(ModuleLifterTest, LiftFunctionWithoutDebugInfo)
560560
{
561561
// Create a function with external linkage but no debug info
562562
auto *funcTy
@@ -569,9 +569,29 @@ TEST_F(ModuleLifterTest, IgnoreFunctionsWithoutDebugInfo)
569569
auto *moduleDecl = irdec::liftModule(astCtx, module.get());
570570

571571
ASSERT_NE(moduleDecl, nullptr);
572-
EXPECT_EQ(
573-
moduleDecl->getDecls().size(), 0
574-
); // Functions without debug info are ignored
572+
EXPECT_EQ(moduleDecl->getDecls().size(), 1);
573+
574+
auto *funcDecl
575+
= llvm::dyn_cast<ast::FunctionDecl>(moduleDecl->getDecls()[0]);
576+
ASSERT_NE(funcDecl, nullptr);
577+
EXPECT_EQ(funcDecl->getName(), "noDebugInfo");
578+
579+
// Verify the function type was lifted correctly
580+
auto *funcDeclType = funcDecl->getType();
581+
ASSERT_NE(funcDeclType, nullptr);
582+
auto *functionTy = llvm::dyn_cast<types::FunctionTy>(funcDeclType);
583+
ASSERT_NE(functionTy, nullptr);
584+
585+
// Verify return type is i32
586+
auto *returnType = functionTy->getReturnType();
587+
ASSERT_NE(returnType, nullptr);
588+
auto *returnIntTy = llvm::dyn_cast<types::IntTy>(returnType);
589+
ASSERT_NE(returnIntTy, nullptr);
590+
EXPECT_EQ(returnIntTy->getBitWidth(), 32);
591+
592+
// Verify no parameters
593+
EXPECT_EQ(functionTy->getParameterCount(), 0);
594+
EXPECT_EQ(funcDecl->getParams().size(), 0);
575595
}
576596

577597
#pragma GCC diagnostic pop
File renamed without changes.

0 commit comments

Comments
 (0)