further updates to atdna

This commit is contained in:
Jack Andersen 2015-06-16 14:25:48 -10:00
parent 775b51fd00
commit fb722a9f5b
8 changed files with 381 additions and 186 deletions

View File

@ -7,7 +7,7 @@ pkgdesc="Basic cross platform IO library"
arch=('i686' 'x86_64') arch=('i686' 'x86_64')
source=("${pkgname%-*}::git+https://github.com/Antidote/Athena.git") source=("${pkgname%-*}::git+https://github.com/Antidote/Athena.git")
options=(staticlibs) options=(staticlibs)
license="GPL3" license="MIT"
makedepends=('git qt5-base sed') makedepends=('git qt5-base sed')
md5sums=('SKIP') md5sums=('SKIP')
sha256sums=('SKIP') sha256sums=('SKIP')

30
atdna/PKGBUILD Normal file
View File

@ -0,0 +1,30 @@
# PKGBUILD for atdna
_pkgname=atdna
pkgname=$_pkgname-git
pkgver=v1.0.0
pkgrel=1
pkgdesc="Companion DNA utility for libAthena"
arch=('i686' 'x86_64')
source=("${pkgname%-*}::git+https://github.com/Antidote/Athena.git")
options=(staticlibs)
license="MIT"
makedepends=('git qt5-base sed clang libathena-git')
depends=('libathena-git')
md5sums=('SKIP')
sha256sums=('SKIP')
pkgver() {
cd "$srcdir/$_pkgname"
git describe --tags | sed 's|-|.|g'
}
build() {
cd "$srcdir/$_pkgname"
qmake && make
}
package() {
cd "$srcdir/$_pkgname"
qmake PREFIX="$pkgdir/usr" && make install
}

View File

@ -14,8 +14,8 @@ CONFIG(debug, debug|release) {
LIBS += -L/run/media/jacko/Extra/llvm-build/usr/lib LIBS += -L/run/media/jacko/Extra/llvm-build/usr/lib
LIBS += -g LIBS += -g
} else { } else {
INCLUDEPATH += /run/media/jacko/Extra/llvm-build/usrmin/include #INCLUDEPATH += /run/media/jacko/Extra/llvm-build/usrmin/include
LIBS += -L/run/media/jacko/Extra/llvm-build/usrmin/lib #LIBS += -L/run/media/jacko/Extra/llvm-build/usrmin/lib
LIBS += -flto LIBS += -flto
} }
@ -42,14 +42,30 @@ LIBS += -lclangFrontendTool -lclangFrontend -lclangTooling -lclangDriver \
-lLLVMARMCodeGen -lLLVMARMAsmParser -lLLVMARMDesc -lLLVMARMInfo -lLLVMARMAsmPrinter \ -lLLVMARMCodeGen -lLLVMARMAsmParser -lLLVMARMDesc -lLLVMARMInfo -lLLVMARMAsmPrinter \
-lLLVMAArch64Disassembler -lLLVMAArch64CodeGen -lLLVMAArch64AsmParser \ -lLLVMAArch64Disassembler -lLLVMAArch64CodeGen -lLLVMAArch64AsmParser \
-lLLVMAArch64Desc -lLLVMAArch64Info -lLLVMAArch64AsmPrinter -lLLVMAArch64Utils \ -lLLVMAArch64Desc -lLLVMAArch64Info -lLLVMAArch64AsmPrinter -lLLVMAArch64Utils \
-lLLVMMIRParser -lLLVMAsmParser -lLLVMLibDriver -lLLVMOption -lLLVMDebugInfoPDB -lLLVMTableGen \ -lLLVMAsmParser -lLLVMOption -lLLVMTableGen \
-lLLVMOrcJIT -lLLVMLineEditor -lLLVMInstrumentation -lLLVMX86Disassembler -lLLVMX86AsmParser \ -lLLVMLineEditor -lLLVMInstrumentation -lLLVMX86Disassembler -lLLVMX86AsmParser \
-lLLVMX86CodeGen -lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMX86Desc -lLLVMMCDisassembler \ -lLLVMX86CodeGen -lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMX86Desc -lLLVMMCDisassembler \
-lLLVMX86Info -lLLVMX86AsmPrinter -lLLVMX86Utils -lLLVMMCJIT -lLLVMDebugInfoDWARF \ -lLLVMX86Info -lLLVMX86AsmPrinter -lLLVMX86Utils -lLLVMMCJIT \
-lLLVMPasses -lLLVMipo -lLLVMVectorize -lLLVMInterpreter -lLLVMExecutionEngine \ -lLLVMipo -lLLVMVectorize -lLLVMInterpreter -lLLVMExecutionEngine \
-lLLVMRuntimeDyld -lLLVMCodeGen -lLLVMTarget -lLLVMScalarOpts -lLLVMProfileData \ -lLLVMRuntimeDyld -lLLVMCodeGen -lLLVMTarget -lLLVMScalarOpts -lLLVMProfileData \
-lLLVMObject -lLLVMMCParser -lLLVMBitReader -lLLVMInstCombine -lLLVMTransformUtils \ -lLLVMObject -lLLVMMCParser -lLLVMBitReader -lLLVMInstCombine -lLLVMTransformUtils \
-lLLVMipa -lLLVMMC -lLLVMAnalysis -lLLVMCore -lLLVMSupport -lz -lpthread -lcurses -ldl -lLLVMipa -lLLVMMC -lLLVMAnalysis -lLLVMCore -lLLVMSupport -lz -lpthread -lcurses -ldl
HEADERS += \ HEADERS += \
test.hpp test.hpp
unix {
isEmpty(PREFIX) {
PREFIX = /usr/local
}
utilFiles.path = $$PREFIX/bin
INSTALLS += utilFiles
}
win32 {
isEmpty(PREFIX) {
PREFIX = $$PWD/pkg
}
utilFiles.path = $$PREFIX/bin
INSTALLS += utilFiles
}

View File

@ -3,14 +3,13 @@
#include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendAction.h" #include "clang/Frontend/FrontendAction.h"
#include "clang/Tooling/Tooling.h" #include "clang/Tooling/Tooling.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Lex/Preprocessor.h" #include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Sema.h" #include "clang/Sema/Sema.h"
#include "clang/AST/RecordLayout.h" #include "clang/AST/RecordLayout.h"
#include "clang/AST/DeclCXX.h" #include "clang/AST/DeclCXX.h"
#include "clang/Basic/Version.h"
#include "llvm/Support/Format.h" #include "llvm/Support/Format.h"
#include "llvm/Support/CommandLine.h" #include "llvm/Support/CommandLine.h"
#include <map>
static llvm::cl::opt<bool> Help("h", llvm::cl::desc("Alias for -help"), llvm::cl::Hidden); static llvm::cl::opt<bool> Help("h", llvm::cl::desc("Alias for -help"), llvm::cl::Hidden);
@ -20,72 +19,24 @@ static llvm::cl::opt<std::string> OutputFilename("o",
llvm::cl::desc("Specify output filename"), llvm::cl::desc("Specify output filename"),
llvm::cl::value_desc("filename"), llvm::cl::value_desc("filename"),
llvm::cl::Prefix); llvm::cl::Prefix);
static llvm::cl::list<std::string> InputFilenames(llvm::cl::Positional, static llvm::cl::list<std::string> InputFilenames(llvm::cl::Positional,
llvm::cl::desc("<Input files>"), llvm::cl::desc("<Input files>"),
llvm::cl::OneOrMore); llvm::cl::OneOrMore);
class ATDNAEndianVisitor : public clang::RecursiveASTVisitor<ATDNAEndianVisitor>
{
clang::ASTContext& context;
std::map<const clang::CXXRecordDecl*, int>& declTracker;
public:
explicit ATDNAEndianVisitor(clang::ASTContext& ctxin,
std::map<const clang::CXXRecordDecl*, int>& dt)
: context(ctxin), declTracker(dt) {}
bool VisitCXXRecordDecl(clang::CXXRecordDecl* decl)
{
if (decl->isInvalidDecl() || !decl->hasDefinition())
return true;
if (!decl->getNumBases())
return true;
/* First ensure this inherits from struct Athena::io::DNA */
bool foundDNA = false;
for (const clang::CXXBaseSpecifier& base : decl->bases())
{
clang::QualType canonType = base.getType().getCanonicalType();
if (!canonType.getAsString().compare(0, 22, "struct Athena::io::DNA"))
{
foundDNA = true;
const clang::CXXRecordDecl* recordDecl = canonType.getTypePtr()->getAsCXXRecordDecl();
if (recordDecl->getTemplateSpecializationKind())
{
const clang::ClassTemplateSpecializationDecl* specDecl = (const clang::ClassTemplateSpecializationDecl*)recordDecl;
const clang::TemplateArgumentList& templateArgs = specDecl->getTemplateInstantiationArgs();
if (templateArgs.size())
{
const clang::TemplateArgument& arg = templateArgs.get(0);
if (arg.getKind() == clang::TemplateArgument::Integral)
{
llvm::APSInt endian = arg.getAsIntegral();
if (endian == 1) /* LittleEndian */
declTracker[recordDecl] = 1;
else if (endian == 2) /* BigEndian */
declTracker[recordDecl] = 2;
}
}
}
break;
}
}
return true;
}
};
class ATDNAEmitVisitor : public clang::RecursiveASTVisitor<ATDNAEmitVisitor> class ATDNAEmitVisitor : public clang::RecursiveASTVisitor<ATDNAEmitVisitor>
{ {
clang::ASTContext& context; clang::ASTContext& context;
llvm::raw_pwrite_stream& fileOut; llvm::raw_fd_ostream& fileOut;
std::map<const clang::CXXRecordDecl*, int>& declTracker;
static std::string GetOpString(clang::BuiltinType* bType, unsigned width, std::string GetOpString(const clang::Type* theType, unsigned width,
std::string fieldName, bool writerPass) std::string fieldName, bool writerPass)
{ {
if (writerPass) if (writerPass)
{ {
if (theType->isBuiltinType())
{
const clang::BuiltinType* bType = (clang::BuiltinType*)theType;
if (bType->isUnsignedInteger()) if (bType->isUnsignedInteger())
{ {
if (width == 8) if (width == 8)
@ -116,36 +67,85 @@ class ATDNAEmitVisitor : public clang::RecursiveASTVisitor<ATDNAEmitVisitor>
return "writer.writeDouble(" + fieldName + ");"; return "writer.writeDouble(" + fieldName + ");";
} }
} }
else if (theType->isRecordType())
{
const clang::RecordDecl* rDecl = ((clang::RecordType*)theType)->getDecl();
for (const clang::FieldDecl* field : rDecl->fields())
{
if (!field->getNameAsString().compare("clangVec"))
{
const clang::VectorType* vType = (clang::VectorType*)field->getType().getTypePtr();
if (vType->isVectorType())
{
const clang::BuiltinType* eType = (clang::BuiltinType*)vType->getElementType().getTypePtr();
if (!eType->isBuiltinType() || !eType->isFloatingPoint() ||
context.getTypeInfo(eType).Width != 32)
continue;
if (vType->getNumElements() == 3)
return "writer.writeVec3f(" + fieldName + ");";
else if (vType->getNumElements() == 4)
return "writer.writeVec4f(" + fieldName + ");";
}
}
}
}
}
else else
{ {
if (theType->isBuiltinType())
{
const clang::BuiltinType* bType = (clang::BuiltinType*)theType;
if (bType->isUnsignedInteger()) if (bType->isUnsignedInteger())
{ {
if (width == 8) if (width == 8)
return fieldName + " = reader.readUByte();"; return "reader.readUByte()";
else if (width == 16) else if (width == 16)
return fieldName + " = reader.readUint16();"; return "reader.readUint16()";
else if (width == 32) else if (width == 32)
return fieldName + " = reader.readUint32();"; return "reader.readUint32()";
else if (width == 64) else if (width == 64)
return fieldName + " = reader.readUint64();"; return "reader.readUint64()";
} }
else if (bType->isSignedInteger()) else if (bType->isSignedInteger())
{ {
if (width == 8) if (width == 8)
return fieldName + " = reader.readByte();"; return "reader.readByte()";
else if (width == 16) else if (width == 16)
return fieldName + " = reader.readInt16();"; return "reader.readInt16()";
else if (width == 32) else if (width == 32)
return fieldName + " = reader.readInt32();"; return "reader.readInt32()";
else if (width == 64) else if (width == 64)
return fieldName + " = reader.readInt64();"; return "reader.readInt64()";
} }
else if (bType->isFloatingPoint()) else if (bType->isFloatingPoint())
{ {
if (width == 32) if (width == 32)
return fieldName + " = reader.readFloat();"; return "reader.readFloat()";
else if (width == 64) else if (width == 64)
return fieldName + " = reader.readDouble();"; return "reader.readDouble()";
}
}
else if (theType->isRecordType())
{
const clang::RecordDecl* rDecl = ((clang::RecordType*)theType)->getDecl();
for (const clang::FieldDecl* field : rDecl->fields())
{
if (!field->getNameAsString().compare("clangVec"))
{
const clang::VectorType* vType = (clang::VectorType*)field->getType().getTypePtr();
if (vType->isVectorType())
{
const clang::BuiltinType* eType = (clang::BuiltinType*)vType->getElementType().getTypePtr();
if (!eType->isBuiltinType() || !eType->isFloatingPoint() ||
context.getTypeInfo(eType).Width != 32)
continue;
if (vType->getNumElements() == 3)
return "reader.readVec3f()";
else if (vType->getNumElements() == 4)
return "reader.readVec4f()";
}
}
}
} }
} }
return std::string(); return std::string();
@ -153,9 +153,8 @@ class ATDNAEmitVisitor : public clang::RecursiveASTVisitor<ATDNAEmitVisitor>
public: public:
explicit ATDNAEmitVisitor(clang::ASTContext& ctxin, explicit ATDNAEmitVisitor(clang::ASTContext& ctxin,
llvm::raw_pwrite_stream& fo, llvm::raw_fd_ostream& fo)
std::map<const clang::CXXRecordDecl*, int>& dt) : context(ctxin), fileOut(fo) {}
: context(ctxin), fileOut(fo), declTracker(dt) {}
bool VisitCXXRecordDecl(clang::CXXRecordDecl* decl) bool VisitCXXRecordDecl(clang::CXXRecordDecl* decl)
{ {
@ -179,44 +178,43 @@ public:
if (!foundDNA) if (!foundDNA)
return true; return true;
/* Context endian */
int contextEndian = llvm::sys::IsLittleEndianHost ? 1 : 2;
if (declTracker.find(decl) != declTracker.end())
contextEndian = declTracker[decl];
for (int p=0 ; p<2 ; ++p) for (int p=0 ; p<2 ; ++p)
{ {
if (p) if (p)
fileOut << decl->getQualifiedNameAsString() << "::write(Athena::IStreamWriter& writer)\n{\n"; fileOut << "void " << decl->getQualifiedNameAsString() << "::write(Athena::IStreamWriter& writer) const\n{\n";
else else
fileOut << decl->getQualifiedNameAsString() << "::read(Athena::IStreamReader& reader)\n{\n"; fileOut << "void " << decl->getQualifiedNameAsString() << "::read(Athena::IStreamReader& reader)\n{\n";
int currentEndian = 0; int currentEndian = -1;
for (const clang::FieldDecl* field : decl->fields()) for (const clang::FieldDecl* field : decl->fields())
{ {
clang::QualType qualType = field->getType(); clang::QualType qualType = field->getType();
clang::TypeInfo regTypeInfo = context.getTypeInfo(qualType); clang::TypeInfo regTypeInfo = context.getTypeInfo(qualType);
const clang::Type* regType = qualType.getTypePtrOrNull(); const clang::Type* regType = qualType.getTypePtrOrNull();
if (regType->getTypeClass() == clang::Type::Elaborated)
regType = regType->getUnqualifiedDesugaredType();
if (regType->getTypeClass() == clang::Type::TemplateSpecialization) if (regType->getTypeClass() == clang::Type::TemplateSpecialization)
{ {
const clang::TemplateSpecializationType* tsType = (const clang::TemplateSpecializationType*)regType; const clang::TemplateSpecializationType* tsType = (const clang::TemplateSpecializationType*)regType;
const clang::TemplateDecl* tsDecl = tsType->getTemplateName().getAsTemplateDecl(); const clang::TemplateDecl* tsDecl = tsType->getTemplateName().getAsTemplateDecl();
const clang::TemplateParameterList* classParms = tsDecl->getTemplateParameters(); const clang::TemplateParameterList* classParms = tsDecl->getTemplateParameters();
int endian = 0;
for (const clang::NamedDecl* param : *classParms)
{
if (param->getKind() == clang::Decl::NonTypeTemplateParm)
{
const clang::NonTypeTemplateParmDecl* nttParm = (clang::NonTypeTemplateParmDecl*)param;
const clang::Expr* defArg = nttParm->getDefaultArgument();
llvm::APSInt result;
if (defArg->isIntegerConstantExpr(result, context))
endian = result.getExtValue();
}
}
if (!tsDecl->getNameAsString().compare("Value")) if (!tsDecl->getNameAsString().compare("Value"))
{ {
int endian = -1;
if (classParms->size() >= 2)
{
const clang::NamedDecl* endianParm = classParms->getParam(1);
if (endianParm->getKind() == clang::Decl::NonTypeTemplateParm)
{
const clang::NonTypeTemplateParmDecl* nttParm = (clang::NonTypeTemplateParmDecl*)endianParm;
const clang::Expr* defArg = nttParm->getDefaultArgument();
llvm::APSInt result;
if (defArg->isIntegerConstantExpr(result, context))
endian = result.getSExtValue();
}
}
std::string ioOp; std::string ioOp;
const clang::TemplateArgument* typeArg = nullptr; const clang::TemplateArgument* typeArg = nullptr;
@ -225,48 +223,158 @@ public:
if (arg.getKind() == clang::TemplateArgument::Type) if (arg.getKind() == clang::TemplateArgument::Type)
{ {
typeArg = &arg; typeArg = &arg;
clang::BuiltinType* builtinType = (clang::BuiltinType*)arg.getAsType().getCanonicalType().getTypePtr(); const clang::Type* type = arg.getAsType().getCanonicalType().getTypePtr();
if (builtinType->isBuiltinType()) ioOp = GetOpString(type, regTypeInfo.Width, field->getName().str(), p);
ioOp = GetOpString(builtinType, regTypeInfo.Width, field->getName().str(), p);
} }
else if (arg.getKind() == clang::TemplateArgument::Expression) else if (arg.getKind() == clang::TemplateArgument::Expression)
{ {
llvm::APSInt value; llvm::APSInt value;
if (arg.getAsExpr()->isIntegerConstantExpr(value, context)) if (arg.getAsExpr()->isIntegerConstantExpr(value, context))
endian = value.getExtValue(); endian = value.getSExtValue();
} }
} }
if (ioOp.empty()) if (ioOp.empty())
{ {
clang::DiagnosticBuilder diag = context.getDiagnostics().Report(tsDecl->getLocation(), context.getDiagnostics().getDiagnosticIDs()->getCustomDiagID(clang::DiagnosticIDs::Fatal, "Athena error")); clang::DiagnosticBuilder diag = context.getDiagnostics().Report(tsDecl->getLocation(), context.getDiagnostics().getCustomDiagID(clang::DiagnosticsEngine::Fatal, "Athena error"));
diag.AddString("Unable to use type '" + tsDecl->getNameAsString() + "' with Athena"); diag.AddString("Unable to use type '" + tsDecl->getNameAsString() + "' with Athena");
if (typeArg) if (typeArg)
diag.AddSourceRange(clang::CharSourceRange(clang::TemplateArgumentLoc(*typeArg, clang::TemplateArgumentLocInfo()).getSourceRange(), false)); diag.AddSourceRange(clang::CharSourceRange(clang::TemplateArgumentLoc(*typeArg, clang::TemplateArgumentLocInfo()).getSourceRange(), false));
continue; continue;
} }
if (!endian) if (currentEndian != endian)
endian = contextEndian;
if (endian && currentEndian != endian)
{ {
if (endian == 1) if (endian == 0)
fileOut << (p ? " writer.setEndian(Athena::LittleEndian);\n" : " reader.setEndian(Athena::LittleEndian);\n"); fileOut << (p ? " writer.setEndian(Athena::LittleEndian);\n" : " reader.setEndian(Athena::LittleEndian);\n");
else if (endian == 2) else if (endian == 1)
fileOut << (p ? " writer.setEndian(Athena::BigEndian);\n" : " reader.setEndian(Athena::BigEndian);\n"); fileOut << (p ? " writer.setEndian(Athena::BigEndian);\n" : " reader.setEndian(Athena::BigEndian);\n");
currentEndian = endian; currentEndian = endian;
} }
if (!p)
fileOut << " " << field->getName() << " = " << ioOp << ";\n";
else
fileOut << " " << ioOp << "\n"; fileOut << " " << ioOp << "\n";
} }
else if (!tsDecl->getNameAsString().compare("Vector")) else if (!tsDecl->getNameAsString().compare("Vector"))
{ {
int endian = -1;
if (classParms->size() >= 3)
{
const clang::NamedDecl* endianParm = classParms->getParam(2);
if (endianParm->getKind() == clang::Decl::NonTypeTemplateParm)
{
const clang::NonTypeTemplateParmDecl* nttParm = (clang::NonTypeTemplateParmDecl*)endianParm;
const clang::Expr* defArg = nttParm->getDefaultArgument();
llvm::APSInt result;
if (defArg->isIntegerConstantExpr(result, context))
endian = result.getSExtValue();
}
}
std::string ioOp;
std::string sizeVar;
const clang::TemplateArgument* typeArg = nullptr;
const clang::TemplateArgument* sizeArg = nullptr;
size_t idx = 0;
for (const clang::TemplateArgument& arg : *tsType)
{
if (arg.getKind() == clang::TemplateArgument::Type)
{
typeArg = &arg;
const clang::Type* type = arg.getAsType().getCanonicalType().getTypePtr();
clang::TypeInfo typeInfo = context.getTypeInfo(arg.getAsType().getCanonicalType());
ioOp = GetOpString(type, typeInfo.Width, "*it", p);
}
else if (arg.getKind() == clang::TemplateArgument::Expression)
{
const clang::Expr* expr = arg.getAsExpr();
if (idx == 1)
{
sizeArg = &arg;
const clang::UnaryExprOrTypeTraitExpr* uExpr = (clang::UnaryExprOrTypeTraitExpr*)expr;
if (uExpr->getStmtClass() == clang::Stmt::UnaryExprOrTypeTraitExprClass &&
uExpr->getKind() == clang::UETT_SizeOf)
{
const clang::Expr* argExpr = uExpr->getArgumentExpr();
while (argExpr->getStmtClass() == clang::Stmt::ParenExprClass)
argExpr = ((clang::ParenExpr*)argExpr)->getSubExpr();
if (argExpr->getStmtClass() == clang::Stmt::DeclRefExprClass)
{
const clang::DeclRefExpr* refExpr = (clang::DeclRefExpr*)argExpr;
sizeVar = refExpr->getFoundDecl()->getNameAsString();
}
}
}
else if (idx == 2)
{
llvm::APSInt value;
if (expr->isIntegerConstantExpr(value, context))
endian = value.getSExtValue();
}
}
++idx;
}
if (ioOp.empty())
{
clang::DiagnosticBuilder diag = context.getDiagnostics().Report(tsDecl->getLocation(), context.getDiagnostics().getCustomDiagID(clang::DiagnosticsEngine::Fatal, "Athena error"));
diag.AddString("Unable to use type '" + tsDecl->getNameAsString() + "' with Athena");
if (typeArg)
diag.AddSourceRange(clang::CharSourceRange(clang::TemplateArgumentLoc(*typeArg, clang::TemplateArgumentLocInfo()).getSourceRange(), false));
continue;
}
if (sizeVar.empty())
{
clang::DiagnosticBuilder diag = context.getDiagnostics().Report(tsDecl->getLocation(), context.getDiagnostics().getCustomDiagID(clang::DiagnosticsEngine::Fatal, "Athena error"));
diag.AddString("Unable to use type '" + tsDecl->getNameAsString() + "' with Athena");
if (sizeArg)
diag.AddSourceRange(clang::CharSourceRange(clang::TemplateArgumentLoc(*sizeArg, clang::TemplateArgumentLocInfo()).getSourceRange(), false));
continue;
}
if (currentEndian != endian)
{
if (endian == 0)
fileOut << (p ? " writer.setEndian(Athena::LittleEndian);\n" : " reader.setEndian(Athena::LittleEndian);\n");
else if (endian == 1)
fileOut << (p ? " writer.setEndian(Athena::BigEndian);\n" : " reader.setEndian(Athena::BigEndian);\n");
currentEndian = endian;
}
if (!p)
{
fileOut << " " << field->getName() << ".clear();\n";
fileOut << " " << field->getName() << ".reserve(" << sizeVar << ");\n";
fileOut << " for (int i=0 ; i<" << sizeVar << " ; ++i)\n " << field->getName() << ".push_back(" << ioOp << ");\n";
}
else
fileOut << " for (int i=0, auto it=" << field->getName() << ".begin() ; i<" << sizeVar << " && it!=" << field->getName() << ".end() ; ++i, ++it)\n " << ioOp << "\n";
} }
} }
else if (regType->getTypeClass() == clang::Type::Record)
{
const clang::CXXRecordDecl* cxxRDecl = regType->getAsCXXRecordDecl();
if (cxxRDecl)
{
for (const clang::CXXBaseSpecifier& base : cxxRDecl->bases())
{
clang::QualType canonType = base.getType().getCanonicalType();
if (!canonType.getAsString().compare(0, 22, "struct Athena::io::DNA"))
{
fileOut << " " << field->getNameAsString() << (p ? ".write(writer);\n" : ".read(reader);\n");
currentEndian = -1;
break;
}
}
}
}
} }
fileOut << "}\n\n"; fileOut << "}\n\n";
@ -279,36 +387,17 @@ public:
class ATDNAConsumer : public clang::ASTConsumer class ATDNAConsumer : public clang::ASTConsumer
{ {
ATDNAEndianVisitor endianVisitor;
ATDNAEmitVisitor emitVisitor; ATDNAEmitVisitor emitVisitor;
llvm::raw_pwrite_stream& fileOut; llvm::raw_fd_ostream& fileOut;
std::map<const clang::CXXRecordDecl*, int> declTracker;
public: public:
explicit ATDNAConsumer(clang::ASTContext& context, llvm::raw_pwrite_stream& fo) explicit ATDNAConsumer(clang::ASTContext& context, llvm::raw_fd_ostream& fo)
: endianVisitor(context, declTracker), emitVisitor(context, fo, declTracker), : emitVisitor(context, fo),
fileOut(fo) {} fileOut(fo) {}
void HandleTranslationUnit(clang::ASTContext& context) void HandleTranslationUnit(clang::ASTContext& context)
{ {
/* First pass - map explicit endian specifiers */
endianVisitor.TraverseDecl(context.getTranslationUnitDecl());
/* Resolve endian specifiers */
for (auto decl : declTracker)
{
for (const clang::DeclContext* prevDecl = decl.first->getParent();
prevDecl ; prevDecl = prevDecl->getParent())
{
if (prevDecl->isRecord() &&
declTracker.find((clang::CXXRecordDecl*)prevDecl) != declTracker.end())
{
decl.second = declTracker[(clang::CXXRecordDecl*)prevDecl];
break;
}
}
}
/* Write file head */ /* Write file head */
fileOut << "/* Auto generated atdna implementation */\n" fileOut << "/* Auto generated atdna implementation */\n"
"#include <Athena/Global.hpp>\n"
"#include <Athena/IStreamReader.hpp>\n" "#include <Athena/IStreamReader.hpp>\n"
"#include <Athena/IStreamWriter.hpp>\n\n"; "#include <Athena/IStreamWriter.hpp>\n\n";
for (const std::string& inputf : InputFilenames) for (const std::string& inputf : InputFilenames)
@ -327,7 +416,7 @@ public:
std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(clang::CompilerInstance& compiler, std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(clang::CompilerInstance& compiler,
llvm::StringRef /*filename*/) llvm::StringRef /*filename*/)
{ {
llvm::raw_pwrite_stream* fileout; llvm::raw_fd_ostream* fileout;
if (OutputFilename.size()) if (OutputFilename.size())
fileout = compiler.createOutputFile(OutputFilename, false, true, "", "", true); fileout = compiler.createOutputFile(OutputFilename, false, true, "", "", true);
else else
@ -343,14 +432,22 @@ int main(int argc, const char** argv)
if (Help) if (Help)
llvm::cl::PrintHelpMessage(); llvm::cl::PrintHelpMessage();
llvm::IntrusiveRefCntPtr<clang::FileManager> fman(new clang::FileManager(clang::FileSystemOptions()));
std::vector<std::string> args = {"clang-tool", std::vector<std::string> args = {"clang-tool",
"-fsyntax-only", "-fsyntax-only",
"-std=c++11", "-std=c++11"};
"-I/run/media/jacko/Extra/llvm-build/usrmin/lib/clang/3.7.0/include",
"-I/home/jacko/Athena/include"}; llvm::IntrusiveRefCntPtr<clang::FileManager> fman(new clang::FileManager(clang::FileSystemOptions()));
const clang::FileEntry* selfEntry = fman->getFile(argv[0]);
if (selfEntry && selfEntry->isValid())
{
std::string base(selfEntry->getDir()->getName());
args.push_back("-I" + base + "/clang/" + CLANG_VERSION_STRING + "/include");
args.push_back("-I" + base);
}
for (int a=1 ; a<argc ; ++a) for (int a=1 ; a<argc ; ++a)
args.push_back(argv[a]); args.push_back(argv[a]);
clang::tooling::ToolInvocation TI(args, new ATDNAAction, fman.get()); clang::tooling::ToolInvocation TI(args, new ATDNAAction, fman.get());
if (TI.run()) if (TI.run())
return 0; return 0;

View File

@ -1,14 +1,33 @@
#include <stdint.h> #include <stdint.h>
#include <vector>
#include <Athena/DNA.hpp> #include <Athena/DNA.hpp>
using namespace Athena; using namespace Athena;
struct ANCSFile : public io::DNA<BigEndian> struct ANCSSubFile : public io::DNA<BigEndian>
{ {
Value<atUint32> var32; DECL_DNA
Value<atUint16> var16; Value<atUint32> sub1;
Vector<atUint32> vec; Value<atUint32> sub2;
};
struct ANCSFile : public io::DNA<BigEndian>
{
DECL_DNA
Value<atUint32> var32;
Value<atUint16> var16;
Value<atVec3f> vec3;
Value<atVec4f> vec4;
struct ANCSNestedSubFile : public io::DNA<BigEndian>
{
DECL_DNA
Value<atUint32> nestSub1;
Value<atUint32> nestSub2;
} nestedSubFile;
ANCSSubFile subFile;
Value<atUint32> arrCount;
Vector<atUint32, sizeof(arrCount)> array;
}; };

View File

@ -5,6 +5,7 @@
#include "IStreamReader.hpp" #include "IStreamReader.hpp"
#include "IStreamWriter.hpp" #include "IStreamWriter.hpp"
#include <vector> #include <vector>
#include <functional>
namespace Athena namespace Athena
{ {
@ -17,19 +18,24 @@ namespace io
* Athena bundles a build-tool called 'atdna'. This tool functions * Athena bundles a build-tool called 'atdna'. This tool functions
* just like the 'clang' compiler, except it emits * just like the 'clang' compiler, except it emits
*/ */
template <Endian DNAE = InheritEndian> template <Endian DNAE>
struct DNA struct DNA
{ {
template <typename T, Endian VE = DNAE> template <typename T, Endian VE = DNAE>
using Value = T; using Value = T;
template <typename T, Endian VE = DNAE> template <typename T, size_t cntVar, Endian VE = DNAE>
using Vector = std::vector<T>; using Vector = std::vector<T>;
virtual void read(IStreamReader&)=0; virtual void read(IStreamReader&)=0;
virtual void write(IStreamWriter&) const=0; virtual void write(IStreamWriter&) const=0;
}; };
/** Macro to automatically declare read/write methods in subclasses */
#define DECL_DNA \
void read(Athena::io::IStreamReader&); \
void write(Athena::io::IStreamWriter&) const; \
} }
} }

View File

@ -82,7 +82,6 @@ enum SeekOrigin
enum Endian enum Endian
{ {
InheritEndian=0,
LittleEndian, LittleEndian,
BigEndian BigEndian
}; };

View File

@ -56,6 +56,34 @@ typedef unsigned long atUint32;
typedef signed long long atInt64; typedef signed long long atInt64;
typedef unsigned long long atUint64; typedef unsigned long long atUint64;
// Vector types
#if __SSE__
#include <xmmintrin.h>
#endif
typedef union
{
#if __clang__
float clangVec __attribute__((__vector_size__(12)));
#endif
#if __SSE__
__m128 mVec128;
#endif
float vec[3];
} atVec3f;
typedef union
{
#if __clang__
float clangVec __attribute__((__vector_size__(16)));
#endif
#if __SSE__
__m128 mVec128;
#endif
float vec[4];
} atVec4f;
#ifndef NULL #ifndef NULL
#ifdef __cplusplus #ifdef __cplusplus
#define NULL 0 #define NULL 0