Skip to content
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

Store types in ir #68

Merged
merged 5 commits into from
Jun 28, 2018
Merged
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
10 changes: 10 additions & 0 deletions bindgen/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,16 @@ add_executable(bindgen
ir/Variable.h
ir/PossibleVarDefine.cpp
ir/PossibleVarDefine.h
ir/types/Type.cpp
ir/types/Type.h
ir/types/PrimitiveType.cpp
ir/types/PrimitiveType.h
ir/types/PointerType.cpp
ir/types/PointerType.h
ir/types/FunctionPointerType.cpp
ir/types/FunctionPointerType.h
ir/types/ArrayType.cpp
ir/types/ArrayType.h
)

set_target_properties(bindgen
Expand Down
28 changes: 19 additions & 9 deletions bindgen/CycleDetection.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,35 @@ class CycleDetection {
private:
TypeTranslator &tpeTransl;

bool contains(std::string &k) { return !!dependencies.count(k); }
bool contains(const std::string &k) const {
return dependencies.count(k) != 0;
}

public:
std::map<std::string, std::set<std::string>> dependencies;
CycleDetection(TypeTranslator &tpeTransl_)

explicit CycleDetection(TypeTranslator &tpeTransl_)
: tpeTransl(tpeTransl_), dependencies{} {}

void AddDependcy(std::string name, const clang::QualType &qtpe) {
void AddDependency(const std::string &name, const clang::QualType &qtpe) {

// TODO: function pointer
if (qtpe->isFunctionPointerType()) {
// TODO: function pointer
/* type translator cannot translate function type */
return;
}

if (qtpe->isPointerType()) {
const clang::PointerType *ptr =
qtpe.getTypePtr()->getAs<clang::PointerType>();
AddDependcy(name, ptr->getPointeeType());
const auto *ptr = qtpe.getTypePtr()->getAs<clang::PointerType>();
AddDependency(name, ptr->getPointeeType());
return;
}

std::string qtpeString = tpeTransl.Translate(qtpe);
Type *type = tpeTransl.translate(qtpe);
std::string qtpeString = type->str();
if (type->canBeDeallocated()) {
delete type;
}

// Add the dependence of qtpe
if (contains(qtpeString)) {
Expand All @@ -39,7 +49,7 @@ class CycleDetection {
dependencies[name].insert(qtpeString);
}

bool isCyclic(std::string &name) {
bool isCyclic(const std::string &name) {
if (contains(name)) {
if (dependencies[name].count(name) != 0) {
return true;
Expand Down
141 changes: 65 additions & 76 deletions bindgen/TypeTranslator.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
#include "TypeTranslator.h"
#include "Utils.h"
#include "ir/types/FunctionPointerType.h"
#include "ir/types/PointerType.h"

TypeTranslator::TypeTranslator(clang::ASTContext *ctx_) : ctx(ctx_), typeMap() {
TypeTranslator::TypeTranslator(clang::ASTContext *ctx_, IR &ir)
: ctx(ctx_), ir(ir), typeMap() {

// Native Types
typeMap["void"] = "Unit";
Expand All @@ -27,38 +30,24 @@ TypeTranslator::TypeTranslator(clang::ASTContext *ctx_) : ctx(ctx_), typeMap() {
typeMap["char32_t"] = "native.CChar32";
typeMap["float"] = "native.CFloat";
typeMap["double"] = "native.CDouble";
typeMap["void*"] = "native.Ptr[Byte]";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

}

std::string
TypeTranslator::TranslateFunctionPointer(const clang::QualType &qtpe,
const std::string *avoid) {
const clang::PointerType *ptr =
qtpe.getTypePtr()->getAs<clang::PointerType>();
Type *TypeTranslator::translateFunctionPointer(const clang::QualType &qtpe,
const std::string *avoid) {
const auto *ptr = qtpe.getTypePtr()->getAs<clang::PointerType>();
const clang::QualType &inner = ptr->getPointeeType();

if (inner->isFunctionProtoType()) {
const clang::FunctionProtoType *fc =
inner->getAs<clang::FunctionProtoType>();
std::string ret = Translate(fc->getReturnType(), avoid);
std::string params = "";
int counter = 0;
const auto *fc = inner->getAs<clang::FunctionProtoType>();
Type *returnType = translate(fc->getReturnType(), avoid);
std::vector<Type *> parametersTypes;

for (const clang::QualType &param : fc->param_types()) {
params += Translate(param, avoid);
params += ", ";
counter++;
parametersTypes.push_back(translate(param, avoid));
}

std::string variad = "";

if (fc->isVariadic()) {
counter++;
variad = "native.CVararg, ";
}

return std::string("native.CFunctionPtr") + std::to_string(counter) +
"[" + params + variad + ret + "]";
return new FunctionPointerType(returnType, parametersTypes,
fc->isVariadic());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️


} else {
llvm::errs() << "Unsupported function pointer type: "
Expand All @@ -68,111 +57,111 @@ TypeTranslator::TranslateFunctionPointer(const clang::QualType &qtpe,
}
}

std::string TypeTranslator::TranslatePointer(const clang::QualType &pte,
const std::string *avoid) {
Type *TypeTranslator::translatePointer(const clang::QualType &pte,
const std::string *avoid) {

if (pte->isBuiltinType()) {
const clang::BuiltinType *as = pte->getAs<clang::BuiltinType>();

// Take care of void*
if (as->getKind() == clang::BuiltinType::Void) {
return "native.Ptr[Byte]";
return new PointerType(new PrimitiveType("Byte"));
}

// Take care of char*
if (as->getKind() == clang::BuiltinType::Char_S ||
as->getKind() == clang::BuiltinType::SChar) {
return "native.CString";
// TODO: new PointerType(new PrimitiveType("native.CChar"))
return new PrimitiveType("native.CString");
}
}

return std::string("native.Ptr[") + Translate(pte, avoid) +
std::string("]");
return new PointerType(translate(pte, avoid));
}

std::string
TypeTranslator::TranslateStructOrUnion(const clang::QualType &qtpe) {
if (qtpe->hasUnnamedOrLocalType()) {
// TODO: Verify that the local part is not a problem
uint64_t size = ctx->getTypeSize(qtpe);
return "native.CArray[Byte, " + uint64ToScalaNat(size) + "]";
}

Type *
TypeTranslator::translateStructOrUnionOrEnum(const clang::QualType &qtpe) {
std::string name = qtpe.getUnqualifiedType().getAsString();

// TODO: do it properly
size_t f = name.find(std::string("struct __dirstream"));
if (f != std::string::npos) {
return std::string("native.CArray[Byte, Digit[_3, Digit[_2, _0]]]");
}

f = name.find(" ");
if (f != std::string::npos) {
return name.replace(f, std::string(" ").length(), "_");
auto it = aliasesMap.find(name);
if (it != aliasesMap.end()) {
/* name contains space: struct <name>.
* Use type alias instead struct type */
return (*it).second;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand this branch. This is when we reference a previously declared struct right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider following example:

struct myStruct {
    int a;
};

Generated Scala code for the struct:

type struct_myStruct = native.CStruct1[native.CInt]

Then we find the function that uses out struct:

void myFunction(struct myStruct, s);

TypeTranslator would translate struct myStruct into native.CStruct1[native.CInt] but we want to use the alias struct_myStruct. We know that the alias already exists because struct was defined, so we find the alias in the map.

So we will reference a TypeDef instance generated for the struct

}
return name;
/* type has typedef alias */
return ir.getTypeDefWithName(name);
}

std::string TypeTranslator::TranslateEnum(const clang::QualType &qtpe) {
std::string name = qtpe.getUnqualifiedType().getAsString();
size_t f = name.find(" ");
if (f != std::string::npos) {
return name.replace(f, std::string(" ").length(), "_");
Type *TypeTranslator::translateStructOrUnion(const clang::QualType &qtpe) {
if (qtpe->hasUnnamedOrLocalType()) {
// TODO: Verify that the local part is not a problem
uint64_t size = ctx->getTypeSize(qtpe);
return new ArrayType(new PrimitiveType("Byte"), size);
}
return name;

return translateStructOrUnionOrEnum(qtpe);
}

std::string
TypeTranslator::TranslateConstantArray(const clang::ConstantArrayType *ar,
const std::string *avoid) {
Type *TypeTranslator::translateConstantArray(const clang::ConstantArrayType *ar,
const std::string *avoid) {
const uint64_t size = ar->getSize().getZExtValue();
const std::string nat = uint64ToScalaNat(size);
return "native.CArray[" + Translate(ar->getElementType(), avoid) + ", " +
nat + "]";
return new ArrayType(translate(ar->getElementType(), avoid), size);
}

std::string TypeTranslator::Translate(const clang::QualType &qtpe,
const std::string *avoid) {
Type *TypeTranslator::translate(const clang::QualType &qtpe,
const std::string *avoid) {

const clang::Type *tpe = qtpe.getTypePtr();

if (typeEquals(tpe, avoid)) {
// This is a type that we want to avoid the usage.
//Êxample: A struct that has a pointer to itself
// Êxample: A struct that has a pointer to itself
uint64_t size = ctx->getTypeSize(tpe);
return "native.CArray[Byte, " + uint64ToScalaNat(size) + "]";
return new ArrayType(new PrimitiveType("Byte"), size);
}

if (tpe->isFunctionPointerType()) {
return TranslateFunctionPointer(qtpe, avoid);
return translateFunctionPointer(qtpe, avoid);

} else if (tpe->isPointerType()) {
return TranslatePointer(
return translatePointer(
tpe->getAs<clang::PointerType>()->getPointeeType(), avoid);

} else if (qtpe->isStructureType() || qtpe->isUnionType()) {
return handleReservedWords(TranslateStructOrUnion(qtpe));
} else if (qtpe->isStructureType()) {
return translateStructOrUnion(qtpe);

} else if (qtpe->isUnionType()) {
return translateStructOrUnion(qtpe);

} else if (qtpe->isEnumeralType()) {
return TranslateEnum(qtpe);
return translateStructOrUnionOrEnum(qtpe);

} else if (qtpe->isConstantArrayType()) {
return TranslateConstantArray(ctx->getAsConstantArrayType(qtpe), avoid);
return translateConstantArray(ctx->getAsConstantArrayType(qtpe), avoid);
} else if (qtpe->isArrayType()) {
return TranslatePointer(ctx->getAsArrayType(qtpe)->getElementType(),
return translatePointer(ctx->getAsArrayType(qtpe)->getElementType(),
avoid);
} else {

auto found = typeMap.find(qtpe.getUnqualifiedType().getAsString());
if (found != typeMap.end()) {
return handleReservedWords(found->second);
return new PrimitiveType(found->second);
} else {
// TODO: Properly handle non-default types
return handleReservedWords(qtpe.getUnqualifiedType().getAsString());
return ir.getTypeDefWithName(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess here we don't want to go through the alias map?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, because struct myStruct will be translated above (the same for enum and union)

qtpe.getUnqualifiedType().getAsString());
}
}
}

void TypeTranslator::AddTranslation(std::string from, std::string to) {
typeMap[from] = to;
void TypeTranslator::addAlias(std::string cName, Type *type) {
aliasesMap[cName] = type;
}

std::string TypeTranslator::getTypeFromTypeMap(std::string cType) {
auto it = typeMap.find(cType);
if (it != typeMap.end()) {
return (*it).second;
}
return "";
}
50 changes: 33 additions & 17 deletions bindgen/TypeTranslator.h
Original file line number Diff line number Diff line change
@@ -1,17 +1,11 @@
#pragma once

#include <clang/AST/AST.h>
#include <clang/AST/ASTContext.h>
#include "ir/IR.h"
#include <clang/Tooling/Tooling.h>

class TypeTranslator {
private:
clang::ASTContext *ctx;
std::map<std::string, std::string> typeMap;

public:
explicit TypeTranslator(clang::ASTContext *ctx);
void AddTranslation(std::string from, std::string to);
TypeTranslator(clang::ASTContext *ctx, IR &ir);

/**
* @brief Translate the qualified type from c to a scala type
Expand All @@ -20,14 +14,36 @@ class TypeTranslator {
* structs, unions, ...
* @return the type translated
*/
std::string Translate(const clang::QualType &tpe,
const std::string * = nullptr);
std::string TranslateFunctionPointer(const clang::QualType &qtpe,
const std::string *avoid);
std::string TranslatePointer(const clang::QualType &pointee,
Type *translate(const clang::QualType &tpe, const std::string * = nullptr);

void addAlias(std::string cName, Type *type);

std::string getTypeFromTypeMap(std::string cType);

private:
clang::ASTContext *ctx;
IR &ir;

/**
* Primitive types
*/
std::map<std::string, std::string> typeMap;

/**
* Maps C struct, union or enum name to Type alias
*/
std::map<std::string, Type *> aliasesMap;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I quite liked the unification in the original typeMap. Would it make sense to change it to be defined as:

std::map<std::string, Type *> typeMap

populated with

     typeMap["void"] = new PrimitiveType("Unit");
     typeMap["bool"] = new PrimitiveType("native.CBool");
     typeMap["_Bool"] = new PrimitiveType("native.CBool");
     // ...

I assume the problem is with the deallocation?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, deallocation is the problem (well, these instances are not deallocated now, but changing type of the map will make fixing it harder)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll create an issue for deallocation

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or simply do it now, because I do not want the code that does not deallocate objects


Type *translateStructOrUnionOrEnum(const clang::QualType &qtpe);

Type *translateStructOrUnion(const clang::QualType &qtpe);

Type *translateFunctionPointer(const clang::QualType &qtpe,
const std::string *avoid);

Type *translatePointer(const clang::QualType &pointee,
const std::string *avoid);

Type *translateConstantArray(const clang::ConstantArrayType *ar,
const std::string *avoid);
std::string TranslateStructOrUnion(const clang::QualType &qtpe);
std::string TranslateEnum(const clang::QualType &qtpe);
std::string TranslateConstantArray(const clang::ConstantArrayType *ar,
const std::string *avoid);
};
12 changes: 1 addition & 11 deletions bindgen/Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <clang/AST/AST.h>

#include "ir/types/Type.h"
#include <algorithm>
#include <cctype>
#include <cinttypes>
Expand Down Expand Up @@ -94,15 +95,4 @@ static inline bool startsWith(const std::string &str,
return str.substr(0, prefix.size()) == prefix;
}

/**
* @return true if checkedType uses type
* example: checkedType = native.Ptr[struct_A], type = struct_A
*/
static inline bool typeUsesOtherType(const std::string &checkedType,
const std::string &type) {
// TODO: find better way to check it
return checkedType == type || checkedType == "native.Ptr[" + type + "]" ||
startsWith(checkedType, "native.CArray[" + type + ", ");
}

#endif // UTILS_H
Loading