Skip to content

Commit

Permalink
thunkgen: Passthrough abi to analysis
Browse files Browse the repository at this point in the history
  • Loading branch information
Sonicadvance1 committed Sep 11, 2024
1 parent 11d3791 commit a5121ae
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 87 deletions.
6 changes: 3 additions & 3 deletions ThunkLibs/Generator/analysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ struct Annotations {
CallbackStrategy callback_strategy = CallbackStrategy::Default;
};

static Annotations GetAnnotations(clang::ASTContext& context, clang::CXXRecordDecl* decl) {
static Annotations GetAnnotations(clang::ASTContext& context, clang::CXXRecordDecl* decl, bool is_32bit) {
ErrorReporter report_error {context};
Annotations ret;

Expand All @@ -90,7 +90,7 @@ static Annotations GetAnnotations(clang::ASTContext& context, clang::CXXRecordDe
} else if (annotation == "fexgen::custom_guest_entrypoint") {
ret.custom_guest_entrypoint = true;
} else if (annotation == "fexgen::inregister_abi") {
ret.inregister_abi = true;
ret.inregister_abi = !is_32bit;
} else {
throw report_error(base.getSourceRange().getBegin(), "Unknown annotation");
}
Expand Down Expand Up @@ -342,7 +342,7 @@ void AnalysisAction::ParseInterface(clang::ASTContext& context) {
if (auto emitted_function = llvm::dyn_cast<clang::FunctionDecl>(template_args[0].getAsDecl())) {
auto return_type = emitted_function->getReturnType();

const auto annotations = GetAnnotations(context, decl);
const auto annotations = GetAnnotations(context, decl, guest_abi.pointer_size == 4);
if (return_type->isFunctionPointerType() && !annotations.returns_guest_pointer) {
throw report_error(template_arg_loc, "Function pointer return types require explicit annotation\n");
}
Expand Down
86 changes: 85 additions & 1 deletion ThunkLibs/Generator/analysis.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,89 @@
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <variant>
#include <vector>

struct SimpleTypeInfo {
uint64_t size_bits;
uint64_t alignment_bits;

bool operator==(const SimpleTypeInfo& other) const {
return size_bits == other.size_bits && alignment_bits == other.alignment_bits;
}
};

struct StructInfo : SimpleTypeInfo {
struct MemberInfo {
uint64_t size_bits; // size of this member. For arrays, total size of all elements
uint64_t offset_bits;
std::string type_name;
std::string member_name;
std::optional<uint64_t> array_size;
bool is_function_pointer;
bool is_integral;
bool is_signed_integer;

bool operator==(const MemberInfo& other) const {
return size_bits == other.size_bits && offset_bits == other.offset_bits &&
// The type name may differ for integral types if all other parameters are equal
(type_name == other.type_name || (is_integral && other.is_integral)) && member_name == other.member_name &&
array_size == other.array_size && is_function_pointer == other.is_function_pointer && is_integral == other.is_integral;
}
};

std::vector<MemberInfo> members;

bool operator==(const StructInfo& other) const {
return (const SimpleTypeInfo&)*this == (const SimpleTypeInfo&)other &&
std::equal(members.begin(), members.end(), other.members.begin(), other.members.end());
}
};

struct TypeInfo : std::variant<std::monostate, SimpleTypeInfo, StructInfo> {
using Parent = std::variant<std::monostate, SimpleTypeInfo, StructInfo>;

TypeInfo() = default;
TypeInfo(const SimpleTypeInfo& info)
: Parent(info) {}
TypeInfo(const StructInfo& info)
: Parent(info) {}

// Opaque declaration with no full definition.
// Pointers to these can still be passed along ABI boundaries assuming
// implementation details are only ever accessed on one side.
bool is_opaque() const {
return std::holds_alternative<std::monostate>(*this);
}

const StructInfo* get_if_struct() const {
return std::get_if<StructInfo>(this);
}

StructInfo* get_if_struct() {
return std::get_if<StructInfo>(this);
}

const SimpleTypeInfo* get_if_simple_or_struct() const {
auto as_struct = std::get_if<StructInfo>(this);
if (as_struct) {
return as_struct;
}
return std::get_if<SimpleTypeInfo>(this);
}
};

struct FuncPtrInfo {
std::array<uint8_t, 32> sha256;
std::string result;
std::vector<std::string> args;
};

struct ABI : std::unordered_map<std::string, TypeInfo> {
std::unordered_map<std::string, FuncPtrInfo> thunked_funcptrs;
int pointer_size; // in bytes
};

struct FunctionParams {
std::vector<clang::QualType> param_types;
};
Expand Down Expand Up @@ -112,7 +193,8 @@ struct NamespaceInfo {

class AnalysisAction : public clang::ASTFrontendAction {
public:
AnalysisAction() {
AnalysisAction(const ABI& guest_abi)
: guest_abi(guest_abi) {
decl_contexts.push_back(nullptr); // global namespace (replaced by getTranslationUnitDecl later)
}

Expand Down Expand Up @@ -165,6 +247,8 @@ class AnalysisAction : public clang::ASTFrontendAction {
RepackedType& LookupType(clang::ASTContext& context, const clang::Type* type) {
return types.at(context.getCanonicalType(type));
}

const ABI& guest_abi;
};

inline std::string get_type_name(const clang::ASTContext& context, const clang::Type* type) {
Expand Down
3 changes: 2 additions & 1 deletion ThunkLibs/Generator/data_layout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ class AnalyzeDataLayoutAction : public AnalysisAction {
};

AnalyzeDataLayoutAction::AnalyzeDataLayoutAction(ABI& abi_)
: type_abi(abi_) {}
: AnalysisAction(abi_)
, type_abi(abi_) {}

std::unordered_map<const clang::Type*, TypeInfo>
ComputeDataLayout(const clang::ASTContext& context, const std::unordered_map<const clang::Type*, AnalysisAction::RepackedType>& types) {
Expand Down
84 changes: 2 additions & 82 deletions ThunkLibs/Generator/data_layout.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,89 +8,8 @@
#include <optional>
#include <string>
#include <unordered_map>
#include <variant>
#include <vector>

struct SimpleTypeInfo {
uint64_t size_bits;
uint64_t alignment_bits;

bool operator==(const SimpleTypeInfo& other) const {
return size_bits == other.size_bits && alignment_bits == other.alignment_bits;
}
};

struct StructInfo : SimpleTypeInfo {
struct MemberInfo {
uint64_t size_bits; // size of this member. For arrays, total size of all elements
uint64_t offset_bits;
std::string type_name;
std::string member_name;
std::optional<uint64_t> array_size;
bool is_function_pointer;
bool is_integral;
bool is_signed_integer;

bool operator==(const MemberInfo& other) const {
return size_bits == other.size_bits && offset_bits == other.offset_bits &&
// The type name may differ for integral types if all other parameters are equal
(type_name == other.type_name || (is_integral && other.is_integral)) && member_name == other.member_name &&
array_size == other.array_size && is_function_pointer == other.is_function_pointer && is_integral == other.is_integral;
}
};

std::vector<MemberInfo> members;

bool operator==(const StructInfo& other) const {
return (const SimpleTypeInfo&)*this == (const SimpleTypeInfo&)other &&
std::equal(members.begin(), members.end(), other.members.begin(), other.members.end());
}
};

struct TypeInfo : std::variant<std::monostate, SimpleTypeInfo, StructInfo> {
using Parent = std::variant<std::monostate, SimpleTypeInfo, StructInfo>;

TypeInfo() = default;
TypeInfo(const SimpleTypeInfo& info)
: Parent(info) {}
TypeInfo(const StructInfo& info)
: Parent(info) {}

// Opaque declaration with no full definition.
// Pointers to these can still be passed along ABI boundaries assuming
// implementation details are only ever accessed on one side.
bool is_opaque() const {
return std::holds_alternative<std::monostate>(*this);
}

const StructInfo* get_if_struct() const {
return std::get_if<StructInfo>(this);
}

StructInfo* get_if_struct() {
return std::get_if<StructInfo>(this);
}

const SimpleTypeInfo* get_if_simple_or_struct() const {
auto as_struct = std::get_if<StructInfo>(this);
if (as_struct) {
return as_struct;
}
return std::get_if<SimpleTypeInfo>(this);
}
};

struct FuncPtrInfo {
std::array<uint8_t, 32> sha256;
std::string result;
std::vector<std::string> args;
};

struct ABI : std::unordered_map<std::string, TypeInfo> {
std::unordered_map<std::string, FuncPtrInfo> thunked_funcptrs;
int pointer_size; // in bytes
};

std::unordered_map<const clang::Type*, TypeInfo>
ComputeDataLayout(const clang::ASTContext& context, const std::unordered_map<const clang::Type*, AnalysisAction::RepackedType>& types);

Expand Down Expand Up @@ -118,7 +37,8 @@ enum class TypeCompatibility {
class DataLayoutCompareAction : public AnalysisAction {
public:
DataLayoutCompareAction(const ABI& guest_abi)
: guest_abi(guest_abi) {}
: AnalysisAction(guest_abi)
, guest_abi(guest_abi) {}

TypeCompatibility GetTypeCompatibility(const clang::ASTContext&, const clang::Type*,
const std::unordered_map<const clang::Type*, TypeInfo> host_abi,
Expand Down

0 comments on commit a5121ae

Please sign in to comment.