Skip to content

Instantly share code, notes, and snippets.

@mingodad
Last active April 17, 2016 20:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mingodad/99d34ad93f59def5ad0ee809681be0e1 to your computer and use it in GitHub Desktop.
Save mingodad/99d34ad93f59def5ad0ee809681be0e1 to your computer and use it in GitHub Desktop.
LLVM-CLANG Parser/CodeGenerator/JIT based on https://github.com/Keno/Cxx.jl
/*
#!/bin/sh
CLANGSRC=$LLVM_HOME/llvm-3.8.0.src
clang++ -fno-rtti -std=c++1y main.cpp \
-I$CLANGSRC/tools/clang/lib \
-lclangCodeGen \
-lclangFrontendTool \
-lclangFrontend \
-lclangParse \
-lclangSema \
-lclangAST \
-lclangASTMatchers \
-lclangEdit \
-lclangAnalysis \
-lclangRewriteFrontend \
-lclangRewrite \
-lclangSerialization \
-lclangStaticAnalyzerCheckers \
-lclangStaticAnalyzerCore \
-lclangStaticAnalyzerFrontend \
-lclangTooling \
-lclangToolingCore \
-lclangARCMigrate \
-lclangDriver \
-lclangLex \
-lclangBasic \
$(llvm-config --cxxflags --ldflags --libs) \
-lpthread -ldl -lcurses -lz
*/
#undef B0 //rom termios
#define __STDC_LIMIT_MACROS
#define __STDC_CONSTANT_MACROS
#include <iostream>
#include <dlfcn.h>
#ifdef NDEBUG
#define OLD_NDEBUG
#endif
#ifdef LLVM_NDEBUG
#define NDEBUG 1
#else
#undef NDEBUG
#endif
// LLVM includes
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Host.h"
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include "llvm/IR/ValueMap.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Verifier.h"
// Clang includes
#include "clang/Sema/ScopeInfo.h"
#include "clang/AST/ASTContext.h"
// Well, yes this is cheating
#define private public
#include "clang/Parse/Parser.h"
#undef private
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/DeclCXX.h"
#include "clang/Sema/SemaConsumer.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Parse/ParseAST.h"
#include "clang/Lex/Lexer.h"
#include "clang/Sema/Sema.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Sema/SemaDiagnostic.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/PrettyDeclStackTrace.h"
#include "clang/Serialization/ASTWriter.h"
#include "clang/Frontend/MultiplexConsumer.h"
#include "Sema/TypeLocBuilder.h"
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/CodeGenOptions.h>
#include <clang/AST/Type.h>
#include <clang/AST/ASTContext.h>
#include <clang/AST/DeclTemplate.h>
#include <clang/Basic/Specifiers.h>
#include "Parse/RAIIObjectsForParser.h"
#include "CodeGen/CodeGenModule.h"
#include <CodeGen/CodeGenTypes.h>
#define private public
#include <CodeGen/CodeGenFunction.h>
#undef private
#include "CodeGen/CGCXXABI.h"
//#include "dtypes.h"
//#include "platform.h"
#if defined(LLVM_VERSION_MAJOR) && LLVM_VERSION_MAJOR == 3
#if LLVM_VERSION_MINOR >= 8
#define LLVM38 1
#elif LLVM_VERSION_MINOR >= 7
#define LLVM37 1
#elif LLVM_VERSION_MINOR >= 6
#define LLVM36 1
#elif LLVM_VERSION_MINOR >= 5
#define LLVM35 1
#endif
#endif
#ifndef OLD_NDEBUG
#undef NDEBUG
#endif
//using namespace std;
//using namespace llvm;
//extern llvm::LLVMContext &jl_LLVMContext;
//static llvm::Type *T_pvalue_llvmt;
llvm::LLVMContext jl_LLVMContext;
class JuliaCodeGenerator;
//static llvm::Type *(*f_julia_type_to_llvm)(void *jt, bool *isboxed);
typedef llvm::Type *(*f_julia_type_to_llvm_t)(void *jt, bool *isboxed);
struct CxxInstance {
llvm::Module *shadow;
clang::CompilerInstance *CI;
clang::CodeGen::CodeGenModule *CGM;
clang::CodeGen::CodeGenFunction *CGF;
clang::Parser *Parser;
JuliaCodeGenerator *JCodeGen;
clang::PCHGenerator *PCHGenerator;
f_julia_type_to_llvm_t julia_type_to_llvm;
llvm::Type *T_pvalue_llvmt;
//llvm::LLVMContext /*&*/jl_LLVMContext;
};
#define JL_DLLEXPORT
#define C CxxInstance *Cxx
//extern "C" {
#define TYPE_ACCESS(EX,IN) \
JL_DLLEXPORT const clang::Type *EX(C) \
{ \
return Cxx->CI->getASTContext().IN.getTypePtrOrNull(); \
}
TYPE_ACCESS(cT_char,CharTy)
TYPE_ACCESS(cT_cchar,CharTy)
TYPE_ACCESS(cT_int1,BoolTy)
TYPE_ACCESS(cT_int8,SignedCharTy)
TYPE_ACCESS(cT_uint8,UnsignedCharTy)
TYPE_ACCESS(cT_int16,ShortTy)
TYPE_ACCESS(cT_uint16,UnsignedShortTy)
TYPE_ACCESS(cT_int32,IntTy)
TYPE_ACCESS(cT_uint32,UnsignedIntTy)
#ifdef _P32
TYPE_ACCESS(cT_int64,LongLongTy)
TYPE_ACCESS(cT_uint64,UnsignedLongLongTy)
#else
TYPE_ACCESS(cT_int64,LongTy)
TYPE_ACCESS(cT_uint64,UnsignedLongTy)
#endif
TYPE_ACCESS(cT_size,getSizeType())
TYPE_ACCESS(cT_int128,Int128Ty)
TYPE_ACCESS(cT_uint128,UnsignedInt128Ty)
TYPE_ACCESS(cT_complex64,FloatComplexTy)
TYPE_ACCESS(cT_complex128,DoubleComplexTy)
TYPE_ACCESS(cT_float32,FloatTy)
TYPE_ACCESS(cT_float64,DoubleTy)
TYPE_ACCESS(cT_void,VoidTy)
TYPE_ACCESS(cT_wint,WIntTy)
//}
// Utilities
clang::SourceLocation getTrivialSourceLocation(C)
{
clang::SourceManager &sm = Cxx->CI->getSourceManager();
return sm.getLocForStartOfFile(sm.getMainFileID());
}
//extern "C" {
/*extern*/ void jl_error(const char *str){};
void jl_(void*){};
void *jl_pchar_to_string(const char *str, unsigned long len){};
void jl_throw(void *theexception){};
// For initialization.jl
JL_DLLEXPORT void add_directory(C, int kind, int isFramework, const char *dirname)
{
clang::SrcMgr::CharacteristicKind flag = (clang::SrcMgr::CharacteristicKind)kind;
clang::FileManager &fm = Cxx->CI->getFileManager();
clang::Preprocessor &pp = Cxx->Parser->getPreprocessor();
auto dir = fm.getDirectory(dirname);
if (dir == nullptr)
std::cout << "WARNING: Could not add directory " << dirname << " to clang search path!\n";
else
pp.getHeaderSearchInfo().AddSearchPath(clang::DirectoryLookup(dir,flag,isFramework),flag == clang::SrcMgr::C_System || flag == clang::SrcMgr::C_ExternCSystem);
}
JL_DLLEXPORT int _cxxparse(C)
{
clang::Sema &S = Cxx->CI->getSema();
clang::ASTConsumer *Consumer = &S.getASTConsumer();
clang::Parser::DeclGroupPtrTy ADecl;
while (!Cxx->Parser->ParseTopLevelDecl(ADecl)) {
// If we got a null return and something *was* parsed, ignore it. This
// is due to a top-level semicolon, an action override, or a parse error
// skipping something.
if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get()))
return 0;
}
S.DefineUsedVTables();
S.PerformPendingInstantiations(false);
Cxx->CGM->Release();
Cxx->CI->getDiagnostics().Reset();
return 1;
}
JL_DLLEXPORT void *ParseDeclaration(C, clang::DeclContext *DCScope)
{
auto *P = Cxx->Parser;
auto *S = &Cxx->CI->getSema();
if (P->getPreprocessor().isIncrementalProcessingEnabled() &&
P->getCurToken().is(clang::tok::eof))
P->ConsumeToken();
clang::ParsingDeclSpec DS(*P);
clang::AccessSpecifier AS;
P->ParseDeclarationSpecifiers(DS, clang::Parser::ParsedTemplateInfo(), AS, clang::Parser::DSC_top_level);
clang::ParsingDeclarator D(*P, DS, clang::Declarator::FileContext);
P->ParseDeclarator(D);
D.setFunctionDefinitionKind(clang::FDK_Definition);
clang::Scope *TheScope = DCScope ? S->getScopeForContext(DCScope) : P->getCurScope();
assert(TheScope);
return S->HandleDeclarator(TheScope, D, clang::MultiTemplateParamsArg());
}
JL_DLLEXPORT void ParseParameterList(C, void **params, size_t nparams)
{
auto *P = Cxx->Parser;
//auto *S = &Cxx->CI->getSema();
if (P->getPreprocessor().isIncrementalProcessingEnabled() &&
P->getCurToken().is(clang::tok::eof))
P->ConsumeToken();
clang::ParsingDeclSpec DS(*P);
clang::AccessSpecifier AS;
clang::ParsingDeclarator D(*P, DS, clang::Declarator::FileContext);
clang::ParsedAttributes FirstArgAttrs(P->getAttrFactory());
clang::SmallVector<clang::DeclaratorChunk::ParamInfo, 16> ParamInfo;
clang::SourceLocation EllipsisLoc;
clang::Parser::ParseScope PrototypeScope(P,
clang::Scope::FunctionPrototypeScope |
clang::Scope::FunctionDeclarationScope |
clang::Scope::DeclScope);
P->ParseParameterDeclarationClause(D,FirstArgAttrs,ParamInfo,EllipsisLoc);
assert(ParamInfo.size() == nparams);
for (size_t i = 0; i < nparams; ++i)
params[i] = ParamInfo[i].Param;
}
JL_DLLEXPORT void *ParseTypeName(C, int ParseAlias = false)
{
if (Cxx->Parser->getPreprocessor().isIncrementalProcessingEnabled() &&
Cxx->Parser->getCurToken().is(clang::tok::eof))
Cxx->Parser->ConsumeToken();
auto result = Cxx->Parser->ParseTypeName(nullptr, ParseAlias ?
clang::Declarator::AliasTemplateContext : clang::Declarator::TypeNameContext);
if (result.isInvalid())
return 0;
clang::QualType QT = clang::Sema::GetTypeFromParser(result.get());
return (void*)QT.getAsOpaquePtr();
}
JL_DLLEXPORT int cxxinclude(C, char *fname, int isAngled)
{
const clang::DirectoryLookup *CurDir;
//clang::FileManager &fm = Cxx->CI->getFileManager();
clang::Preprocessor &P = Cxx->CI->getPreprocessor();
const clang::FileEntry *File = P.LookupFile(
getTrivialSourceLocation(Cxx), fname,
isAngled, P.GetCurDirLookup(), nullptr, CurDir, nullptr,nullptr, nullptr);
if(!File)
return 0;
clang::SourceManager &sm = Cxx->CI->getSourceManager();
clang::FileID FID = sm.createFileID(File, sm.getLocForStartOfFile(sm.getMainFileID()), P.getHeaderSearchInfo().getFileDirFlavor(File));
P.EnterSourceFile(FID, CurDir, sm.getLocForStartOfFile(sm.getMainFileID()));
return _cxxparse(Cxx);
}
/*
* Collect all global initializers into one llvm::Function, which
* we can then call.
*/
JL_DLLEXPORT llvm::Function *CollectGlobalConstructors(C)
{
clang::CodeGen::CodeGenModule::CtorList &ctors = Cxx->CGM->getGlobalCtors();
if (ctors.empty()) {
return nullptr;
}
// First create the function into which to collect
llvm::Function *InitF = llvm::Function::Create(
llvm::FunctionType::get(
llvm::Type::getVoidTy(jl_LLVMContext),
false),
llvm::GlobalValue::ExternalLinkage,
"",
Cxx->shadow
);
llvm::IRBuilder<true> builder(llvm::BasicBlock::Create(jl_LLVMContext, "top", InitF));
for (auto ctor : ctors) {
builder.CreateCall(ctor.Initializer, {});
}
builder.CreateRetVoid();
ctors.clear();
return InitF;
}
JL_DLLEXPORT void EnterSourceFile(C, const char *data, size_t length)
{
const clang::DirectoryLookup *CurDir = nullptr;
//clang::FileManager &fm = Cxx->CI->getFileManager();
clang::SourceManager &sm = Cxx->CI->getSourceManager();
clang::FileID FID = sm.createFileID(llvm::MemoryBuffer::getMemBufferCopy(llvm::StringRef(data,length)),clang::SrcMgr::C_User,
0,0,sm.getLocForStartOfFile(sm.getMainFileID()));
clang::Preprocessor &P = Cxx->Parser->getPreprocessor();
P.EnterSourceFile(FID, CurDir, sm.getLocForStartOfFile(sm.getMainFileID()));
}
JL_DLLEXPORT void EnterVirtualFile(C, const char *data, size_t length, char *VirtualPath, size_t PathLength)
{
const clang::DirectoryLookup *CurDir = nullptr;
clang::FileManager &fm = Cxx->CI->getFileManager();
clang::SourceManager &sm = Cxx->CI->getSourceManager();
llvm::StringRef FileName(VirtualPath, PathLength);
llvm::StringRef Code(data,length);
std::unique_ptr<llvm::MemoryBuffer> Buf =
llvm::MemoryBuffer::getMemBufferCopy(Code, FileName);
const clang::FileEntry *Entry =
fm.getVirtualFile(FileName, Buf->getBufferSize(), 0);
sm.overrideFileContents(Entry, std::move(Buf));
clang::FileID FID = sm.createFileID(Entry,sm.getLocForStartOfFile(sm.getMainFileID()),clang::SrcMgr::C_User);
clang::Preprocessor &P = Cxx->Parser->getPreprocessor();
P.EnterSourceFile(FID, CurDir, sm.getLocForStartOfFile(sm.getMainFileID()));
}
JL_DLLEXPORT int cxxparse(C, const char *data, size_t length)
{
EnterSourceFile(Cxx, data, length);
return _cxxparse(Cxx);
}
JL_DLLEXPORT void defineMacro(C,const char *Name)
{
clang::Preprocessor &PP = Cxx->Parser->getPreprocessor();
// Get the identifier.
clang::IdentifierInfo *Id = PP.getIdentifierInfo(Name);
clang::MacroInfo *MI = PP.AllocateMacroInfo(getTrivialSourceLocation(Cxx));
PP.appendDefMacroDirective(Id, MI);
}
// For typetranslation.jl
JL_DLLEXPORT bool BuildNNS(C, clang::CXXScopeSpec *spec, const char *Name)
{
clang::Preprocessor &PP = Cxx->CI->getPreprocessor();
// Get the identifier.
clang::IdentifierInfo *Id = PP.getIdentifierInfo(Name);
return Cxx->CI->getSema().BuildCXXNestedNameSpecifier(
nullptr, *Id,
getTrivialSourceLocation(Cxx),
getTrivialSourceLocation(Cxx),
clang::QualType(),
false,
*spec,
nullptr,
false,
nullptr
);
}
JL_DLLEXPORT void *lookup_name(C, char *name, clang::DeclContext *ctx)
{
clang::SourceManager &sm = Cxx->CI->getSourceManager();
clang::CXXScopeSpec spec;
spec.setBeginLoc(sm.getLocForStartOfFile(sm.getMainFileID()));
spec.setEndLoc(sm.getLocForStartOfFile(sm.getMainFileID()));
clang::DeclarationName DName(&Cxx->CI->getASTContext().Idents.get(name));
clang::Sema &cs = Cxx->CI->getSema();
cs.RequireCompleteDeclContext(spec,ctx);
//return dctx->lookup(DName).front();
clang::LookupResult R(cs, DName, getTrivialSourceLocation(Cxx), clang::Sema::LookupAnyName);
cs.LookupQualifiedName(R, ctx, false);
return R.empty() ? nullptr : R.getRepresentativeDecl();
}
JL_DLLEXPORT void *SpecializeClass(C, clang::ClassTemplateDecl *tmplt, void **types, uint64_t *integralValues,int8_t *integralValuePresent, size_t nargs)
{
clang::TemplateArgument *targs = new clang::TemplateArgument[nargs];
for (size_t i = 0; i < nargs; ++i) {
if (integralValuePresent[i] == 1) {
clang::QualType IntT = clang::QualType::getFromOpaquePtr(types[i]);
size_t BitWidth = Cxx->CI->getASTContext().getTypeSize(IntT);
llvm::APSInt Value(llvm::APInt(64,integralValues[i]));
if (Value.getBitWidth() != BitWidth)
Value = Value.extOrTrunc(BitWidth);
Value.setIsSigned(IntT->isSignedIntegerOrEnumerationType());
targs[i] = clang::TemplateArgument(Cxx->CI->getASTContext(),Value,IntT);
} else {
targs[i] = clang::TemplateArgument(clang::QualType::getFromOpaquePtr(types[i]));
}
targs[i] = Cxx->CI->getASTContext().getCanonicalTemplateArgument(targs[i]);
}
void *InsertPos;
clang::ClassTemplateSpecializationDecl *ret =
tmplt->findSpecialization(clang::ArrayRef<clang::TemplateArgument>(targs,nargs),
InsertPos);
if (!ret)
{
ret = clang::ClassTemplateSpecializationDecl::Create(Cxx->CI->getASTContext(),
tmplt->getTemplatedDecl()->getTagKind(),
tmplt->getDeclContext(),
tmplt->getTemplatedDecl()->getLocStart(),
tmplt->getLocation(),
tmplt,
targs,
nargs, nullptr);
tmplt->AddSpecialization(ret, InsertPos);
if (tmplt->isOutOfLine())
ret->setLexicalDeclContext(tmplt->getLexicalDeclContext());
}
delete[] targs;
return ret;
}
JL_DLLEXPORT void *typeForDecl(clang::Decl *D)
{
clang::TypeDecl *ty = clang::dyn_cast<clang::TypeDecl>(D);
if (ty == nullptr)
return nullptr;
return (void *)ty->getTypeForDecl();
}
JL_DLLEXPORT void *withConst(void *T)
{
return clang::QualType::getFromOpaquePtr(T).withConst().getAsOpaquePtr();
}
JL_DLLEXPORT void *withVolatile(void *T)
{
return clang::QualType::getFromOpaquePtr(T).withVolatile().getAsOpaquePtr();
}
JL_DLLEXPORT void *withRestrict(void *T)
{
return clang::QualType::getFromOpaquePtr(T).withRestrict().getAsOpaquePtr();
}
JL_DLLEXPORT char *decl_name(clang::NamedDecl *decl)
{
const clang::IdentifierInfo *II = decl->getIdentifier();
const clang::TagDecl *TagD;
if (!II && (TagD = clang::dyn_cast<clang::TagDecl>(decl))) {
decl = TagD->getTypedefNameForAnonDecl();
if (!decl)
return nullptr;
}
std::string str = decl->getQualifiedNameAsString().data();
char * cstr = (char*)malloc(str.length()+1);
std::strcpy (cstr, str.c_str());
return cstr;
}
JL_DLLEXPORT char *simple_decl_name(clang::NamedDecl *decl)
{
std::string str = decl->getNameAsString().data();
char * cstr = (char*)malloc(str.length()+1);
std::strcpy (cstr, str.c_str());
return cstr;
}
// For cxxstr
JL_DLLEXPORT void *createNamespace(C,char *name)
{
clang::IdentifierInfo *Id = Cxx->CI->getPreprocessor().getIdentifierInfo(name);
return (void*)clang::NamespaceDecl::Create(
Cxx->CI->getASTContext(),
Cxx->CI->getASTContext().getTranslationUnitDecl(),
false,
getTrivialSourceLocation(Cxx),
getTrivialSourceLocation(Cxx),
Id,
nullptr
);
}
JL_DLLEXPORT void SetDeclInitializer(C, clang::VarDecl *D, llvm::Constant *CI)
{
llvm::Constant *Const = Cxx->CGM->GetAddrOfGlobalVar(D);
if (!clang::isa<llvm::GlobalVariable>(Const))
jl_error("Clang did not create a global variable for the given VarDecl");
llvm::GlobalVariable *GV = clang::cast<llvm::GlobalVariable>(Const);
GV->setInitializer(llvm::ConstantExpr::getBitCast(CI, GV->getType()->getElementType()));
GV->setConstant(true);
}
JL_DLLEXPORT void *GetAddrOfFunction(C, clang::FunctionDecl *D)
{
return (void*)Cxx->CGM->GetAddrOfFunction(D);
}
size_t cxxsizeofType(C, void *t);
typedef struct cppcall_state {
// Save previous globals
llvm::Module *module;
llvm::Function *func;
llvm::Function *CurFn;
llvm::BasicBlock *block;
llvm::BasicBlock::iterator point;
llvm::Instruction *prev_alloca_bb_ptr;
// Current state
llvm::Instruction *alloca_bb_ptr;
} cppcall_state_t;
void *setup_cpp_env(C, void *jlfunc);
void cleanup_cpp_env(C, cppcall_state_t *);
//extern void jl_(void*);
static llvm::Function *CloneFunctionAndAdjust(C, llvm::Function *F, llvm::FunctionType *FTy,
bool ModuleLevelChanges,
llvm::ClonedCodeInfo *CodeInfo,
const clang::CodeGen::CGFunctionInfo &FI,
clang::FunctionDecl *FD,
bool specsig, bool firstIsEnv,
bool *needsbox, void **juliatypes)
{
std::vector<llvm::Type*> ArgTypes;
llvm::ValueToValueMapTy VMap;
// Create the new function...
llvm::Function *NewF = llvm::Function::Create(FTy, F->getLinkage(), F->getName(), Cxx->shadow);
llvm::IRBuilder<true> builder(jl_LLVMContext);
llvm::CallInst *Call;
llvm::PointerType *T_pint8 = llvm::Type::getInt8PtrTy(jl_LLVMContext,0);
llvm::Type *T_int32 = llvm::Type::getInt32Ty(jl_LLVMContext);
llvm::Type *T_int64 = llvm::Type::getInt64Ty(jl_LLVMContext);
if (needsbox) {
// Ok, we need to go through and box the arguments.
// Let's first let's clang take care of the function prologue.
cppcall_state_t *state = (cppcall_state_t *)setup_cpp_env(Cxx,NewF);
builder.SetInsertPoint(Cxx->CGF->Builder.GetInsertBlock(),
Cxx->CGF->Builder.GetInsertPoint());
Cxx->CGF->CurGD = clang::GlobalDecl(FD);
clang::CodeGen::FunctionArgList Args;
const clang::CXXMethodDecl *MD = clang::dyn_cast<clang::CXXMethodDecl>(FD);
if (MD && MD->isInstance()) {
Cxx->CGM->getCXXABI().buildThisParam(*Cxx->CGF, Args);
}
for (auto *PVD : FD->params()) {
Args.push_back(PVD);
}
size_t n_roots = 0;
for (size_t i = 0; i < Args.size(); ++i)
n_roots += needsbox[i] | !specsig;
Cxx->CGF->EmitFunctionProlog(FI, NewF, Args);
builder.SetInsertPoint(Cxx->CGF->Builder.GetInsertBlock(),
Cxx->CGF->Builder.GetInsertBlock()->begin());
Cxx->CGF->ReturnValue = Cxx->CGF->CreateIRTemp(FD->getReturnType(), "retval");
llvm::Value *gcframe = nullptr, *envroot = nullptr, *envptr = nullptr;
bool first = true;
// Construct the GC frame
llvm::Function *ConstructFrame = clang::cast<llvm::Function>(Cxx->shadow->getOrInsertFunction("julia.jlcall_frame_decl",
llvm::FunctionType::get(llvm::PointerType::get(Cxx->T_pvalue_llvmt,0),{T_int32},false)));
llvm::Function *RootDecl = clang::cast<llvm::Function>(Cxx->shadow->getOrInsertFunction("julia.gc_root_decl",
llvm::FunctionType::get(llvm::PointerType::get(Cxx->T_pvalue_llvmt,0),{})));
llvm::Function *PTLSStates = clang::cast<llvm::Function>(Cxx->shadow->getOrInsertFunction("jl_get_ptls_states",
llvm::FunctionType::get(llvm::PointerType::get(llvm::PointerType::get(Cxx->T_pvalue_llvmt,0),0),{})));
assert(ConstructFrame);
llvm::BasicBlock *InsertBlock = builder.GetInsertBlock();
if (n_roots != 0) {
envroot = builder.CreateCall(RootDecl, {});
if (n_roots-firstIsEnv != 0)
gcframe = builder.CreateCall(ConstructFrame, {llvm::ConstantInt::get(T_int32,n_roots-firstIsEnv)});
builder.CreateCall(PTLSStates, {});
builder.SetInsertPoint(InsertBlock);
InsertBlock = llvm::BasicBlock::Create(Cxx->shadow->getContext(), "main", InsertBlock->getParent());
builder.CreateBr(InsertBlock);
builder.SetInsertPoint(InsertBlock);
}
size_t i = 0;
std::vector<llvm::Value*> CallArgs;
llvm::Function::arg_iterator DestI = F->arg_begin();
size_t cur_root = 0;
for (auto *PVD : Args) {
#ifdef LLVM38
llvm::Value *ArgPtr = Cxx->CGF->GetAddrOfLocalVar(PVD).getPointer()
#else
llvm::Value *ArgPtr = Cxx->CGF->GetAddrOfLocalVar(PVD)
#endif
;
if (needsbox[i]) {
llvm::Function *AllocFunc = Cxx->shadow->getFunction("jl_gc_allocobj");
assert(AllocFunc);
llvm::Value *Box = builder.CreateBitCast(builder.CreateCall(AllocFunc,
{llvm::ConstantInt::get(T_int64,cxxsizeofType(Cxx,(void*)PVD->getType().getTypePtr()))}),
llvm::PointerType::get(T_pint8,0));
jl_(juliatypes[i]);
builder.CreateStore(llvm::Constant::getIntegerValue(T_pint8,llvm::APInt(8*sizeof(void*),(uint64_t)juliatypes[i++])),
builder.CreateConstGEP1_32(Box,-1));
builder.CreateStore(builder.CreateBitCast(Box,Cxx->T_pvalue_llvmt),builder.CreateConstGEP1_32(gcframe,cur_root++));
llvm::Value *Replacement = builder.CreateBitCast(Box,ArgPtr->getType());
ArgPtr->replaceAllUsesWith(Replacement);
CallArgs.push_back(Replacement);
} else {
bool isboxed;
if (Cxx->julia_type_to_llvm(juliatypes[i], &isboxed)->isVoidTy())
continue;
llvm::IRBuilderBase::InsertPoint IP = builder.saveIP();
// Go to end of block
builder.SetInsertPoint(builder.GetInsertBlock());
if (specsig) {
if (DestI->getType()->isPointerTy() && !clang::cast<llvm::PointerType>(ArgPtr->getType())->getElementType()->isPointerTy())
CallArgs.push_back(builder.CreateBitCast(ArgPtr,DestI->getType()));
else
CallArgs.push_back(builder.CreateLoad(builder.CreateBitCast(ArgPtr,llvm::PointerType::get(DestI->getType(),0))));
} else {
// Assume this is already a box. All we need to do is store it in the callframe
if (first && firstIsEnv) {
envptr = builder.CreateBitCast(builder.CreateLoad(ArgPtr),Cxx->T_pvalue_llvmt);
builder.CreateStore(envptr, envroot);
} else {
assert(gcframe);
builder.CreateStore(builder.CreateBitCast(builder.CreateLoad(ArgPtr),Cxx->T_pvalue_llvmt),
builder.CreateConstGEP1_32(gcframe,cur_root++));
}
first = false;
}
builder.restoreIP(IP);
}
DestI++;
}
builder.SetInsertPoint(InsertBlock,
InsertBlock->end());
if (specsig) {
Call = builder.CreateCall(F,CallArgs);
} else {
auto it = F->arg_begin();
llvm::Argument *First = &*(it++);
llvm::Argument *Second = &*(it++);
Call = builder.CreateCall(F,{
envroot ? envptr :
builder.CreateBitCast(llvm::ConstantPointerNull::get(T_pint8),First->getType()),
cur_root == 0 ? llvm::ConstantPointerNull::get(clang::cast<llvm::PointerType>(Second->getType())) :
builder.CreateBitCast(gcframe,Second->getType()), llvm::ConstantInt::get(T_int32,cur_root)});
}
Cxx->CGF->Builder.SetInsertPoint(builder.GetInsertBlock(),
builder.GetInsertPoint());
if (Call->getType()->isPointerTy() &&
clang::cast<llvm::PointerType>(Call->getType())->getElementType()->isAggregateType()) {
Cxx->CGF->EmitAggregateCopy(Cxx->CGF->ReturnValue,
#ifdef LLVM38
clang::CodeGen::Address(Call,clang::CharUnits::fromQuantity(sizeof(void*))),
#else
Call,
#endif
FD->getReturnType());
Cxx->CGF->EmitFunctionEpilog(FI, false, clang::SourceLocation());
} else {
llvm::Value *Ret = Call;
// Adjust the return value
if (F->getReturnType() != FTy->getReturnType()) {
assert(!F->hasStructRetAttr());
llvm::Value *A = builder.CreateAlloca(FTy->getReturnType());
builder.CreateStore(Call,builder.CreateBitCast(A,llvm::PointerType::get(Call->getType(),0)));
Ret = builder.CreateLoad(A);
}
if (Call->getType()->isVoidTy())
builder.CreateRetVoid();
else
builder.CreateRet(Ret);
}
cleanup_cpp_env(Cxx,state);
} else {
llvm::BasicBlock *BB = llvm::BasicBlock::Create(NewF->getContext(), "entry", NewF);
builder.SetInsertPoint(BB);
// Loop over the arguments, copying the names of the mapped arguments over...
std::vector<llvm::Value*> args;
assert(NewF->getFunctionType()->getNumParams() ==
F->getFunctionType()->getNumParams());
llvm::Function::arg_iterator DestI = NewF->arg_begin();
for (llvm::Function::const_arg_iterator I = F->arg_begin(), E = F->arg_end();
I != E; ++I) {
DestI->setName(I->getName()); // Copy the name over...
if (DestI->getType() != I->getType()) {
assert(I->getType()->isPointerTy());
llvm::Value *A = builder.CreateAlloca(clang::cast<llvm::PointerType>(I->getType())->getElementType());
builder.CreateStore(&*DestI,builder.CreateBitCast(A,llvm::PointerType::get(DestI->getType(),0)));
args.push_back(A);
}
else {
args.push_back(&*DestI);
}
DestI++;
}
Call = builder.CreateCall(F,args);
llvm::Value *Ret = Call;
// Adjust the return value
if (F->getReturnType() != FTy->getReturnType()) {
assert(!F->hasStructRetAttr());
llvm::Value *A = builder.CreateAlloca(FTy->getReturnType());
builder.CreateStore(Call,builder.CreateBitCast(A,llvm::PointerType::get(Call->getType(),0)));
Ret = builder.CreateLoad(A);
}
if (Ret->getType()->isVoidTy())
builder.CreateRetVoid();
else
builder.CreateRet(Ret);
}
llvm::InlineFunctionInfo IFI;
llvm::InlineFunction(Call,IFI);
return NewF;
}
JL_DLLEXPORT void ReplaceFunctionForDecl(C,clang::FunctionDecl *D, llvm::Function *F, bool DoInline, bool specsig, bool firstIsEnv, bool *needsbox, void **juliatypes)
{
const clang::CodeGen::CGFunctionInfo &FI = Cxx->CGM->getTypes().arrangeGlobalDeclaration(D);
llvm::FunctionType *Ty = Cxx->CGM->getTypes().GetFunctionType(FI);
llvm::Constant *Const = Cxx->CGM->GetAddrOfFunction(D,Ty);
if (!Const || !clang::isa<llvm::Function>(Const))
jl_error("Clang did not create function for the given FunctionDecl");
assert(F);
llvm::Function *OF = clang::cast<llvm::Function>(Const);
llvm::ValueToValueMapTy VMap;
llvm::ClonedCodeInfo CCI;
llvm::Function *NF = CloneFunctionAndAdjust(Cxx,F,Ty,true,&CCI,FI,D,specsig,firstIsEnv,needsbox,juliatypes);
// TODO: Ideally we would delete the cloned function
// once we're done with the inlineing, but clang delays
// emitting some functions (e.g. constructors) until
// they're used.
StringRef Name = OF->getName();
//OF->dump();
//NF->dump();
OF->replaceAllUsesWith(NF);
OF->removeFromParent();
NF->setName(Name);
if (DoInline) {
while (true)
{
if (NF->getNumUses() == 0)
return;
llvm::Value::user_iterator I = NF->user_begin();
if (llvm::isa<llvm::CallInst>(*I)) {
llvm::InlineFunctionInfo IFI;
llvm::InlineFunction(clang::cast<llvm::CallInst>(*I),IFI,
# ifdef LLVM38
nullptr,
# endif
true);
} else {
I->dump();
jl_error("Tried to do something other than calling it to a julia expression");
}
}
}
}
JL_DLLEXPORT void *ActOnStartOfFunction(C, clang::FunctionDecl *D, bool ScopeIsNull = false)
{
clang::Sema &sema = Cxx->CI->getSema();
//ContextRAII SavedContext(sema, DC);
return (void*)sema.ActOnStartOfFunctionDef(ScopeIsNull ? nullptr : Cxx->Parser->getCurScope(), D);
}
JL_DLLEXPORT bool ParseFunctionStatementBody(C, clang::Decl *D)
{
clang::Parser::ParseScope BodyScope(Cxx->Parser, clang::Scope::FnScope|clang::Scope::DeclScope);
Cxx->Parser->ConsumeToken();
clang::Sema &sema = Cxx->CI->getSema();
// Slightly modified
assert(Cxx->Parser->getCurToken().is(clang::tok::l_brace));
clang::SourceLocation LBraceLoc = Cxx->Parser->getCurToken().getLocation();
clang::PrettyDeclStackTraceEntry CrashInfo(sema, D, LBraceLoc,
"parsing function body");
// Do not enter a scope for the brace, as the arguments are in the same scope
// (the function body) as the body itself. Instead, just read the statement
// list and put it into a CompoundStmt for safe keeping.
clang::StmtResult FnBody(Cxx->Parser->ParseCompoundStatementBody(true));
// If the function body could not be parsed, return an error
if (!FnBody.isUsable()) {
sema.ActOnFinishFunctionBody(D, nullptr);
return false;
}
clang::CompoundStmt *Body = clang::cast<clang::CompoundStmt>(FnBody.get());
if (Body->body_empty()) {
sema.ActOnFinishFunctionBody(D, nullptr);
return false;
}
// If we don't yet have a return statement, implicitly return
// the result of the last statement
if (clang::cast<clang::FunctionDecl>(D)->getReturnType()->isUndeducedType())
{
clang::Stmt *last = nullptr;
// Ignore any trailing null statements in accordance with what
// julia does. This still triggers a warning in parsing above,
// but there isn't really a good way to get around that, so
// we'll live with the warning and have it work anyway
for (auto lit = Body->body_rbegin(); lit != Body->body_rend(); ++lit) {
if (!clang::isa<clang::NullStmt>(*lit)) {
last = *lit;
break;
}
}
if (last && clang::isa<clang::Expr>(last)) {
clang::StmtResult RetStmt(sema.BuildReturnStmt(getTrivialSourceLocation(Cxx), clang::cast<clang::Expr>(last)));
if (!RetStmt.isUsable()) {
sema.ActOnFinishFunctionBody(D, nullptr);
return false;
}
Body->setLastStmt(RetStmt.get());
}
}
BodyScope.Exit();
sema.ActOnFinishFunctionBody(D, Body);
return true;
}
JL_DLLEXPORT void *ActOnStartNamespaceDef(C, char *name)
{
Cxx->Parser->EnterScope(clang::Scope::DeclScope);
clang::ParsedAttributes attrs(Cxx->Parser->getAttrFactory());
clang::UsingDirectiveDecl *ImplicitUsingDirectiveDecl = nullptr;
return Cxx->CI->getSema().ActOnStartNamespaceDef(
Cxx->Parser->getCurScope(),
getTrivialSourceLocation(Cxx),
getTrivialSourceLocation(Cxx),
getTrivialSourceLocation(Cxx),
Cxx->Parser->getPreprocessor().getIdentifierInfo(name),
getTrivialSourceLocation(Cxx),
attrs.getList(),
ImplicitUsingDirectiveDecl
);
}
JL_DLLEXPORT void ActOnFinishNamespaceDef(C, clang::Decl *D)
{
Cxx->Parser->ExitScope();
Cxx->CI->getSema().ActOnFinishNamespaceDef(
D, getTrivialSourceLocation(Cxx)
);
}
// For codegen.jl
JL_DLLEXPORT int typeconstruct(C,void *type, clang::Expr **rawexprs, size_t nexprs, void **ret)
{
clang::QualType Ty = clang::QualType::getFromOpaquePtr(type);
clang::MultiExprArg Exprs(rawexprs,nexprs);
clang::Sema &sema = Cxx->CI->getSema();
clang::TypeSourceInfo *TInfo = Cxx->CI->getASTContext().getTrivialTypeSourceInfo(Ty);
if (Ty->isDependentType() || clang::CallExpr::hasAnyTypeDependentArguments(Exprs)) {
*ret = clang::CXXUnresolvedConstructExpr::Create(Cxx->CI->getASTContext(), TInfo,
getTrivialSourceLocation(Cxx),
Exprs,
getTrivialSourceLocation(Cxx));
return true;
}
clang::ExprResult Result;
if (Exprs.size() == 1) {
clang::Expr *Arg = Exprs[0];
Result = sema.BuildCXXFunctionalCastExpr(TInfo, getTrivialSourceLocation(Cxx),
Arg, getTrivialSourceLocation(Cxx));
if (Result.isInvalid())
return false;
*ret = Result.get();
return true;
}
if (!Ty->isVoidType() &&
sema.RequireCompleteType(getTrivialSourceLocation(Cxx), Ty,
clang::diag::err_invalid_incomplete_type_use)) {
return false;
}
if (sema.RequireNonAbstractType(getTrivialSourceLocation(Cxx), Ty,
clang::diag::err_allocation_of_abstract_type)) {
return false;
}
clang::InitializedEntity Entity = clang::InitializedEntity::InitializeTemporary(TInfo);
clang::InitializationKind Kind =
Exprs.size() ? clang::InitializationKind::CreateDirect(getTrivialSourceLocation(Cxx),
getTrivialSourceLocation(Cxx), getTrivialSourceLocation(Cxx))
: clang::InitializationKind::CreateValue(getTrivialSourceLocation(Cxx),
getTrivialSourceLocation(Cxx), getTrivialSourceLocation(Cxx));
clang::InitializationSequence InitSeq(sema, Entity, Kind, Exprs);
Result = InitSeq.Perform(sema, Entity, Kind, Exprs);
if (Result.isInvalid())
return false;
*ret = Result.get();
return true;
}
JL_DLLEXPORT void *BuildCXXNewExpr(C, clang::Type *type, clang::Expr **exprs, size_t nexprs)
{
clang::QualType Ty = clang::QualType::getFromOpaquePtr(type);
clang::SourceManager &sm = Cxx->CI->getSourceManager();
return (void*) Cxx->CI->getSema().BuildCXXNew(clang::SourceRange(),
false, getTrivialSourceLocation(Cxx),
clang::MultiExprArg(), getTrivialSourceLocation(Cxx), clang::SourceRange(),
Ty, Cxx->CI->getASTContext().getTrivialTypeSourceInfo(Ty),
nullptr, clang::SourceRange(sm.getLocForStartOfFile(sm.getMainFileID()),
sm.getLocForStartOfFile(sm.getMainFileID())),
new (Cxx->CI->getASTContext()) clang::ParenListExpr(Cxx->CI->getASTContext(),getTrivialSourceLocation(Cxx),
clang::ArrayRef<clang::Expr*>(exprs, nexprs), getTrivialSourceLocation(Cxx)), false).get();
//return (clang_astcontext) new clang::CXXNewExpr(clang_astcontext, false, nE, dE, )
}
JL_DLLEXPORT void *EmitCXXNewExpr(C, clang::Expr *E)
{
assert(clang::isa<clang::CXXNewExpr>(E));
return (void*)Cxx->CGF->EmitCXXNewExpr(clang::cast<clang::CXXNewExpr>(E));
}
JL_DLLEXPORT void *build_call_to_member(C, clang::Expr *MemExprE,clang::Expr **exprs, size_t nexprs)
{
if (MemExprE->getType() == Cxx->CI->getASTContext().BoundMemberTy ||
MemExprE->getType() == Cxx->CI->getASTContext().OverloadTy)
return (void*)Cxx->CI->getSema().BuildCallToMemberFunction(nullptr,
MemExprE,getTrivialSourceLocation(Cxx),clang::MultiExprArg(exprs,nexprs),getTrivialSourceLocation(Cxx)).get();
else if(clang::isa<clang::TypoExpr>(MemExprE)) {
return nullptr;
}
else {
return (void*) new (&Cxx->CI->getASTContext()) clang::CXXMemberCallExpr(Cxx->CI->getASTContext(),
MemExprE,clang::ArrayRef<clang::Expr*>(exprs,nexprs),
clang::cast<clang::CXXMethodDecl>(clang::cast<clang::MemberExpr>(MemExprE)->getMemberDecl())->getReturnType(),
clang::VK_RValue,getTrivialSourceLocation(Cxx));
}
}
JL_DLLEXPORT void *PerformMoveOrCopyInitialization(C, void *rt, clang::Expr *expr)
{
clang::InitializedEntity Entity = clang::InitializedEntity::InitializeTemporary(
clang::QualType::getFromOpaquePtr(rt));
return (void*)Cxx->CI->getSema().PerformMoveOrCopyInitialization(Entity, nullptr,
clang::QualType::getFromOpaquePtr(rt), expr, true).get();
}
// For CxxREPL
JL_DLLEXPORT void *clang_compiler(C)
{
return (void*)Cxx->CI;
}
JL_DLLEXPORT void *clang_parser(C)
{
return (void*)Cxx->Parser;
}
// Legacy
static llvm::Type *T_int32;
static bool in_cpp = false;
//}
class ValidatingASTVisitor : public clang::DeclVisitor<ValidatingASTVisitor>,
public clang::StmtVisitor<ValidatingASTVisitor>
{
private:
bool FoundInvalid;
clang::Decl *CurrentDecl;
public:
ValidatingASTVisitor() : FoundInvalid(false), CurrentDecl(0) {}
operator bool() { return FoundInvalid; }
void reset() { FoundInvalid = false; }
typedef ValidatingASTVisitor ImplClass;
typedef ValidatingASTVisitor Base;
typedef clang::DeclVisitor<ImplClass> BaseDeclVisitor;
typedef clang::StmtVisitor<ImplClass> BaseStmtVisitor;
using BaseStmtVisitor::Visit;
//===--------------------------------------------------------------------===//
// DeclVisitor
//===--------------------------------------------------------------------===//
void Visit(clang::Decl *D){
clang::Decl *PrevDecl = CurrentDecl;
CurrentDecl = D;
BaseDeclVisitor::Visit(D);
CurrentDecl = PrevDecl;
}
void VisitFunctionDecl(clang::FunctionDecl *D){
BaseDeclVisitor::VisitFunctionDecl(D);
if (D->doesThisDeclarationHaveABody())
Visit(D->getBody());
}
void VisitObjCMethodDecl(clang::ObjCMethodDecl *D){
BaseDeclVisitor::VisitObjCMethodDecl(D);
if (D->getBody())
Visit(D->getBody());
}
void VisitBlockDecl(clang::BlockDecl *D){
BaseDeclVisitor::VisitBlockDecl(D);
Visit(D->getBody());
}
void VisitVarDecl(clang::VarDecl *D){
BaseDeclVisitor::VisitVarDecl(D);
if (clang::Expr *Init = D->getInit())
Visit(Init);
}
void VisitDecl(clang::Decl *D){
if (D->isInvalidDecl())
FoundInvalid = true;
if (clang::isa<clang::FunctionDecl>(D) || clang::isa<clang::ObjCMethodDecl>(D) || clang::isa<clang::BlockDecl>(D))
return;
if (clang::DeclContext *DC = clang::dyn_cast<clang::DeclContext>(D))
static_cast<ImplClass*>(this)->VisitDeclContext(DC);
}
void VisitDeclContext(clang::DeclContext *DC){
for (clang::DeclContext::decl_iterator
I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I)
Visit(*I);
}
//===--------------------------------------------------------------------===//
// StmtVisitor
//===--------------------------------------------------------------------===//
void VisitDeclStmt(clang::DeclStmt *Node){
for (clang::DeclStmt::decl_iterator
I = Node->decl_begin(), E = Node->decl_end(); I != E; ++I)
Visit(*I);
}
void VisitBlockExpr(clang::BlockExpr *Node){
// The BlockDecl is also visited by 'VisitDeclContext()'. No need to visit it twice.
}
void VisitStmt(clang::Stmt *Node){
#ifdef LLVM38
for (clang::StmtIterator I = Node->children().begin(); I != Node->children().end(); ++I)
#else
for (clang::Stmt::child_range I = Node->children(); I; ++I)
#endif
if (*I)
Visit(*I);
}
};
class JuliaCodeGenerator : public clang::ASTConsumer {
public:
JuliaCodeGenerator(C) : Cxx(*Cxx) {}
CxxInstance Cxx;
ValidatingASTVisitor Visitor;
virtual ~JuliaCodeGenerator() {}
virtual void HandleCXXStaticMemberVarInstantiation(clang::VarDecl *VD){
Cxx.CGM->HandleCXXStaticMemberVarInstantiation(VD);
}
bool EmitTopLevelDecl(clang::Decl *D)
{
Visitor.Visit(D);
bool HadErrors = (bool)Visitor;
if (!HadErrors)
Cxx.CGM->EmitTopLevelDecl(D);
Visitor.reset();
return HadErrors;
}
virtual bool HandleTopLevelDecl(clang::DeclGroupRef DG){
// Make sure to emit all elements of a Decl.
for (clang::DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
EmitTopLevelDecl(*I);
return true;
}
/// HandleTagDeclDefinition - This callback is invoked each time a TagDecl
/// to (e.g. struct, union, enum, class) is completed. This allows the
/// client hack on the type, which can occur at any point in the file
/// (because these can be defined in declspecs).
virtual void HandleTagDeclDefinition(clang::TagDecl *D){
Cxx.CGM->UpdateCompletedType(D);
// In C++, we may have member functions that need to be emitted at this
// point.
if (Cxx.CI->getASTContext().getLangOpts().CPlusPlus && !D->isDependentContext()) {
for (clang::DeclContext::decl_iterator M = D->decls_begin(),
MEnd = D->decls_end();
M != MEnd; ++M)
if (clang::CXXMethodDecl *Method = clang::dyn_cast<clang::CXXMethodDecl>(*M))
if (Method->doesThisDeclarationHaveABody() &&
(Method->hasAttr<clang::UsedAttr>() ||
Method->hasAttr<clang::ConstructorAttr>()))
Cxx.CGM->EmitTopLevelDecl(Method);
}
}
virtual void CompleteTentativeDefinition(clang::VarDecl *D){
Cxx.CGM->EmitTentativeDefinition(D);
}
virtual void HandleVTable(clang::CXXRecordDecl *RD){
Cxx.CGM->EmitVTable(RD);
}
};
//extern "C" {
JL_DLLEXPORT void *julia_namespace = 0;
//}
class JuliaSemaSource : public clang::ExternalSemaSource
{
public:
JuliaSemaSource() {}
virtual ~JuliaSemaSource() {}
virtual bool LookupUnqualified (clang::LookupResult &R, clang::Scope *S)
{
if (R.getLookupName().getAsString() == "__julia" && julia_namespace != nullptr) {
R.addDecl((clang::NamespaceDecl*)julia_namespace);
return true;
}
return false;
}
};
class JuliaPCHGenerator : public clang::PCHGenerator
{
public:
JuliaPCHGenerator(
const clang::Preprocessor &PP, StringRef OutputFile,
clang::Module *Module, StringRef isysroot,
std::shared_ptr<clang::PCHBuffer> Buffer,
#ifdef LLVM38
clang::ArrayRef<llvm::IntrusiveRefCntPtr<clang::ModuleFileExtension>> Extensions,
bool IncludeTimestamps = true,
#endif
bool AllowASTWithErrors = false) :
PCHGenerator(PP,OutputFile,Module,isysroot,Buffer,
#ifdef LLVM38
Extensions,
#endif
AllowASTWithErrors
#ifdef LLVM38
, IncludeTimestamps
#endif
) {}
void HandleTranslationUnit(clang::ASTContext &Ctx){
PCHGenerator::HandleTranslationUnit(Ctx);
std::error_code EC;
llvm::raw_fd_ostream OS("Cxx.pch",EC,llvm::sys::fs::F_None);
OS << getPCH();
OS.flush();
OS.close();
}
};
//extern "C" {
JL_DLLEXPORT void init_clang_instance(C, const char *Triple, const char *SysRoot, bool EmitPCH,
const char *UsePCH, llvm::Type *_T_pvalue_llvmt, f_julia_type_to_llvm_t f_julia_type_to_llvm) {
Cxx->T_pvalue_llvmt = _T_pvalue_llvmt;
//copied from http://www.ibm.com/developerworks/library/os-createcompilerllvm2/index.html
Cxx->CI = new clang::CompilerInstance;
Cxx->CI->getDiagnosticOpts().ShowColors = 1;
Cxx->CI->getDiagnosticOpts().ShowPresumedLoc = 1;
Cxx->CI->createDiagnostics();
Cxx->CI->getLangOpts().CPlusPlus = 1;
Cxx->CI->getLangOpts().CPlusPlus11 = 1;
Cxx->CI->getLangOpts().CPlusPlus14 = 1;
Cxx->CI->getLangOpts().LineComment = 1;
Cxx->CI->getLangOpts().Bool = 1;
Cxx->CI->getLangOpts().WChar = 1;
Cxx->CI->getLangOpts().C99 = 1;
Cxx->CI->getLangOpts().RTTI = 1;
Cxx->CI->getLangOpts().RTTIData = 1;
Cxx->CI->getLangOpts().ImplicitInt = 0;
Cxx->CI->getLangOpts().PICLevel = 2;
Cxx->CI->getLangOpts().Exceptions = 1; // exception handling
Cxx->CI->getLangOpts().ObjCExceptions = 1; // Objective-C exceptions
Cxx->CI->getLangOpts().CXXExceptions = 1; // C++ exceptions
Cxx->CI->getLangOpts().CXXOperatorNames = 1;
// TODO: Decide how we want to handle this
// clang_compiler->getLangOpts().AccessControl = 0;
Cxx->CI->getPreprocessorOpts().UsePredefines = 1;
Cxx->CI->getHeaderSearchOpts().UseBuiltinIncludes = 1;
Cxx->CI->getHeaderSearchOpts().UseLibcxx = 1;
Cxx->CI->getHeaderSearchOpts().UseStandardSystemIncludes = 1;
Cxx->CI->getHeaderSearchOpts().UseStandardCXXIncludes = 1;
if (SysRoot)
Cxx->CI->getHeaderSearchOpts().Sysroot = SysRoot;
Cxx->CI->getCodeGenOpts().setDebugInfo(clang::CodeGenOptions::NoDebugInfo);
Cxx->CI->getCodeGenOpts().DwarfVersion = 2;
Cxx->CI->getCodeGenOpts().StackRealignment = 1;
Cxx->CI->getTargetOpts().Triple = Triple == nullptr ? llvm::Triple::normalize(llvm::sys::getProcessTriple()) : Triple;
Cxx->CI->getTargetOpts().CPU = llvm::sys::getHostCPUName ();
llvm::StringMap< bool > ActiveFeatures;
std::vector< std::string > Features;
if (llvm::sys::getHostCPUFeatures(ActiveFeatures)) {
for (auto &F : ActiveFeatures)
Features.push_back(std::string(F.second ? "+" : "-") +
std::string(F.first()));
Cxx->CI->getTargetOpts().Features = Features;
}
Cxx->CI->setTarget(clang::TargetInfo::CreateTargetInfo(
Cxx->CI->getDiagnostics(),
std::make_shared<clang::TargetOptions>(Cxx->CI->getTargetOpts())));
clang::TargetInfo &tin = Cxx->CI->getTarget();
Cxx->CI->createFileManager();
Cxx->CI->createSourceManager(Cxx->CI->getFileManager());
Cxx->CI->createPreprocessor(clang::TU_Prefix);
Cxx->CI->createASTContext();
Cxx->shadow = new llvm::Module("clangShadow",jl_LLVMContext);
#ifdef LLVM38
Cxx->shadow->setDataLayout(tin.getDataLayoutString());
#else
Cxx->shadow->setDataLayout(tin.getTargetDescription());
#endif
Cxx->CGM = new clang::CodeGen::CodeGenModule(
Cxx->CI->getASTContext(),
Cxx->CI->getHeaderSearchOpts(),
Cxx->CI->getPreprocessorOpts(),
Cxx->CI->getCodeGenOpts(),
*Cxx->shadow,
#ifndef LLVM38
Cxx->shadow->getDataLayout(),
#endif
Cxx->CI->getDiagnostics());
Cxx->CGF = new clang::CodeGen::CodeGenFunction(*Cxx->CGM);
Cxx->CGF->CurFuncDecl = nullptr;
Cxx->CGF->CurCodeDecl = nullptr;
// Cxx isn't fully initialized yet, but that's fine since JuliaCodeGenerator does
// not need the parser
Cxx->JCodeGen = new JuliaCodeGenerator(Cxx);
if (EmitPCH) {
assert(&Cxx->CI->getPreprocessor() != NULL);
assert(&Cxx->CI->getPreprocessor().getModuleLoader() != NULL);
StringRef OutputFile = "Cxx.pch";
auto Buffer = std::make_shared<clang::PCHBuffer>();
Cxx->PCHGenerator = new JuliaPCHGenerator(
Cxx->CI->getPreprocessor(), OutputFile, nullptr,
Cxx->CI->getHeaderSearchOpts().Sysroot,
Buffer,
#ifdef LLVM38
Cxx->CI->getFrontendOpts().ModuleFileExtensions,
#endif
true);
std::vector<std::unique_ptr<clang::ASTConsumer>> Consumers;
Consumers.push_back(std::unique_ptr<clang::ASTConsumer>(Cxx->JCodeGen));
Consumers.push_back(std::unique_ptr<clang::ASTConsumer>(Cxx->PCHGenerator));
Cxx->CI->setASTConsumer(
llvm::make_unique<clang::MultiplexConsumer>(std::move(Consumers)));
} else {
Cxx->CI->setASTConsumer(std::unique_ptr<clang::ASTConsumer>(Cxx->JCodeGen));
}
if (UsePCH) {
clang::ASTDeserializationListener *DeserialListener =
Cxx->CI->getASTConsumer().GetASTDeserializationListener();
bool DeleteDeserialListener = false;
Cxx->CI->createPCHExternalASTSource(
UsePCH,
Cxx->CI->getPreprocessorOpts().DisablePCHValidation,
Cxx->CI->getPreprocessorOpts().AllowPCHWithCompilerErrors, DeserialListener,
DeleteDeserialListener);
}
Cxx->CI->createSema(clang::TU_Prefix,nullptr);
Cxx->CI->getSema().addExternalSource(new JuliaSemaSource());
T_int32 = llvm::Type::getInt32Ty(jl_LLVMContext);
clang::Sema &sema = Cxx->CI->getSema();
clang::Preprocessor &pp = Cxx->CI->getPreprocessor();
Cxx->Parser = new clang::Parser(pp, sema, false);
Cxx->CI->getDiagnosticClient().BeginSourceFile(Cxx->Parser->getLangOpts(), 0);
#ifdef LLVM38
pp.getBuiltinInfo().initializeBuiltins(pp.getIdentifierTable(),
Cxx->Parser->getLangOpts());
#else
pp.getBuiltinInfo().InitializeBuiltins(pp.getIdentifierTable(),
Cxx->Parser->getLangOpts());
#endif
pp.enableIncrementalProcessing();
clang::SourceManager &sm = Cxx->CI->getSourceManager();
sm.setMainFileID(sm.createFileID(llvm::MemoryBuffer::getNewMemBuffer(0), clang::SrcMgr::C_User));
sema.getPreprocessor().EnterMainSourceFile();
Cxx->Parser->Initialize();
//Cxx->julia_type_to_llvm = (llvm::Type *(*)(void *, bool *))dlsym(RTLD_DEFAULT, "julia_type_to_llvm");
Cxx->julia_type_to_llvm = f_julia_type_to_llvm;
assert(Cxx->julia_type_to_llvm);
}
void decouple_pch(C)
{
Cxx->PCHGenerator->HandleTranslationUnit(Cxx->CI->getASTContext());
Cxx->JCodeGen = new JuliaCodeGenerator(Cxx);
Cxx->CI->setASTConsumer(std::unique_ptr<clang::ASTConsumer>(Cxx->JCodeGen));
Cxx->CI->getSema().Consumer = Cxx->CI->getASTConsumer();
Cxx->PCHGenerator = nullptr;
}
static llvm::Module *cur_module = nullptr;
static llvm::Function *cur_func = nullptr;
JL_DLLEXPORT void *setup_cpp_env(C, void *jlfunc)
{
//assert(in_cpp == false);
//in_cpp = true;
assert(Cxx->CGF != nullptr);
cppcall_state_t *state = new cppcall_state_t;
state->module = nullptr;
state->func = cur_func;
state->CurFn = Cxx->CGF->CurFn;
state->block = Cxx->CGF->Builder.GetInsertBlock();
state->point = Cxx->CGF->Builder.GetInsertPoint();
state->prev_alloca_bb_ptr = Cxx->CGF->AllocaInsertPt;
llvm::Function *w = (llvm::Function *)jlfunc;
assert(w != nullptr);
cur_module = nullptr;
cur_func = w;
llvm::Function *ShadowF = (llvm::Function *)jlfunc;
llvm::BasicBlock *b0 = llvm::BasicBlock::Create(Cxx->shadow->getContext(), "top", ShadowF);
Cxx->CGF->ReturnBlock = Cxx->CGF->getJumpDestInCurrentScope("return");
// setup the environment to clang's expecations
Cxx->CGF->Builder.SetInsertPoint( b0 );
// clang expects to alloca memory before the AllocaInsertPt
// typically, clang would create this pointer when it started emitting the function
// instead, we create a dummy reference here
// for efficiency, we avoid creating a new placehold instruction if possible
llvm::Instruction *alloca_bb_ptr = nullptr;
if (b0->empty()) {
llvm::Value *Undef = llvm::UndefValue::get(T_int32);
Cxx->CGF->AllocaInsertPt = alloca_bb_ptr = new llvm::BitCastInst(Undef, T_int32, "", b0);
} else {
Cxx->CGF->AllocaInsertPt = &(b0->front());
}
Cxx->CGF->PrologueCleanupDepth = Cxx->CGF->EHStack.stable_begin();
Cxx->CGF->CurFn = ShadowF;
state->alloca_bb_ptr = alloca_bb_ptr;
return state;
}
JL_DLLEXPORT bool EmitTopLevelDecl(C, clang::Decl *D)
{
return Cxx->JCodeGen->EmitTopLevelDecl(D);
}
JL_DLLEXPORT void cleanup_cpp_env(C, cppcall_state_t *state)
{
//assert(in_cpp == true);
//in_cpp = false;
#ifdef LLVM38
Cxx->CGF->ReturnValue = clang::CodeGen::Address(nullptr,clang::CharUnits());
#else
Cxx->CGF->ReturnValue = nullptr;
#endif
Cxx->CGF->Builder.ClearInsertionPoint();
Cxx->CGF->FinishFunction(getTrivialSourceLocation(Cxx));
Cxx->CGF->ReturnBlock.getBlock()->eraseFromParent();
Cxx->CGF->ReturnBlock = Cxx->CGF->getJumpDestInCurrentScope(
Cxx->CGF->createBasicBlock("return"));
Cxx->CI->getSema().DefineUsedVTables();
Cxx->CI->getSema().PerformPendingInstantiations(false);
Cxx->CGM->Release();
// Set all functions and globals to external linkage (MCJIT needs this ugh)
//for(Module::global_iterator I = jl_Module->global_begin(),
// E = jl_Module->global_end(); I != E; ++I) {
// I->setLinkage(llvm::GlobalVariable::ExternalLinkage);
//}
//llvm::Function *F = Cxx->CGF->CurFn;
// cleanup the environment
Cxx->CGF->EHResumeBlock = nullptr;
Cxx->CGF->TerminateLandingPad = nullptr;
Cxx->CGF->TerminateHandler = nullptr;
Cxx->CGF->UnreachableBlock = nullptr;
Cxx->CGF->ExceptionSlot = nullptr;
Cxx->CGF->EHSelectorSlot = nullptr;
//copy_into(F,cur_func);
//F->eraseFromParent();
// Hack: MaybeBindToTemporary can cause this to be
// set if the allocated type has a constructor.
// For now, ignore.
Cxx->CI->getSema().ExprNeedsCleanups = false;
cur_module = state->module;
cur_func = state->func;
Cxx->CGF->CurFn = state->CurFn;
if (state->block != nullptr)
Cxx->CGF->Builder.SetInsertPoint(state->block,state->point);
Cxx->CGF->AllocaInsertPt = state->prev_alloca_bb_ptr;
delete state;
}
/*
ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc,
04467 MultiExprArg ArgExprs, SourceLocation RParenLoc,
04468 Expr *ExecConfig, bool IsExecConfig) {}
04469 // Since this might be a postfix expression, get rid of Pare
#endif
*/
JL_DLLEXPORT void *CreateCallExpr(C, clang::Expr *Fn,clang::Expr **exprs, size_t nexprs)
{
return Cxx->CI->getSema().ActOnCallExpr(nullptr, Fn, getTrivialSourceLocation(Cxx),
clang::MultiExprArg(exprs,nexprs), getTrivialSourceLocation(Cxx), nullptr, false).get();
}
JL_DLLEXPORT void *CreateVarDecl(C, void *DC, char* name, void *type)
{
clang::QualType T = clang::QualType::getFromOpaquePtr(type);
clang::VarDecl *D = clang::VarDecl::Create(Cxx->CI->getASTContext(), (clang::DeclContext *)DC,
getTrivialSourceLocation(Cxx), getTrivialSourceLocation(Cxx),
Cxx->CI->getPreprocessor().getIdentifierInfo(name),
T, Cxx->CI->getASTContext().getTrivialTypeSourceInfo(T), clang::SC_Extern);
return D;
}
JL_DLLEXPORT void *CreateFunctionDecl(C, void *DC, char* name, void *type, int isextern)
{
clang::QualType T = clang::QualType::getFromOpaquePtr(type);
clang::FunctionDecl *D = clang::FunctionDecl::Create(Cxx->CI->getASTContext(), (clang::DeclContext *)DC,
getTrivialSourceLocation(Cxx), getTrivialSourceLocation(Cxx),
clang::DeclarationName(Cxx->CI->getPreprocessor().getIdentifierInfo(name)),
T, Cxx->CI->getASTContext().getTrivialTypeSourceInfo(T), isextern ? clang::SC_Extern : clang::SC_None);
return D;
}
JL_DLLEXPORT void *CreateCxxCallMethodDecl(C, clang::CXXRecordDecl *TheClass, void *QT)
{
clang::DeclarationName MethodName
= Cxx->CI->getASTContext().DeclarationNames.getCXXOperatorName(clang::OO_Call);
clang::DeclarationNameLoc MethodNameLoc;
clang::QualType T = clang::QualType::getFromOpaquePtr(QT);
clang::CXXMethodDecl *Method
= clang::CXXMethodDecl::Create(Cxx->CI->getASTContext(), TheClass,
clang::SourceLocation(),
clang::DeclarationNameInfo(MethodName,
clang::SourceLocation(),
MethodNameLoc),
T, Cxx->CI->getASTContext().getTrivialTypeSourceInfo(T),
clang::SC_None,
/*isInline=*/true,
/*isConstExpr=*/false,
clang::SourceLocation());
Method->setAccess(clang::AS_public);
return Method;
}
JL_DLLEXPORT void *CreateParmVarDecl(C, void *type, char *name)
{
clang::QualType T = clang::QualType::getFromOpaquePtr(type);
clang::ParmVarDecl *d = clang::ParmVarDecl::Create(
Cxx->CI->getASTContext(),
Cxx->CI->getASTContext().getTranslationUnitDecl(), // This is wrong, hopefully it doesn't matter
getTrivialSourceLocation(Cxx),
getTrivialSourceLocation(Cxx),
&Cxx->CI->getPreprocessor().getIdentifierTable().getOwn(name),
T,
Cxx->CI->getASTContext().getTrivialTypeSourceInfo(T),
clang::SC_None,nullptr);
d->setIsUsed();
return (void*)d;
}
JL_DLLEXPORT void *CreateTypeDefDecl(C, clang::DeclContext *DC, char *name, void *type)
{
clang::QualType T = clang::QualType::getFromOpaquePtr(type);
return (void*)clang::TypedefDecl::Create(Cxx->CI->getASTContext(),DC,getTrivialSourceLocation(Cxx),
getTrivialSourceLocation(Cxx),
&Cxx->CI->getPreprocessor().getIdentifierTable().getOwn(name),
Cxx->CI->getASTContext().getTrivialTypeSourceInfo(T));
}
JL_DLLEXPORT void SetFDParams(clang::FunctionDecl *FD, clang::ParmVarDecl **PVDs, size_t npvds)
{
FD->setParams(clang::ArrayRef<clang::ParmVarDecl*>(PVDs,npvds));
clang::TypeSourceInfo *TInfo = FD->getTypeSourceInfo();
if (clang::FunctionProtoTypeLoc Proto =
TInfo->getTypeLoc().IgnoreParens().getAs<clang::FunctionProtoTypeLoc>()) {
for (size_t i = 0; i < npvds; ++i) {
Proto.setParam(i, PVDs[i]);
PVDs[i]->setScopeInfo(0,i);
}
}
}
JL_DLLEXPORT void AssociateValue(C, clang::Decl *d, void *type, llvm::Value *V)
{
clang::VarDecl *vd = clang::dyn_cast<clang::VarDecl>(d);
clang::QualType T = clang::QualType::getFromOpaquePtr(type);
llvm::Type *Ty = Cxx->CGF->ConvertTypeForMem(T);
#if 0
if (type == cT_int1(Cxx))
V = Cxx->CGF->Builder.CreateZExt(V, Ty);
// Associate the value with this decl
#ifdef LLVM38
Cxx->CGF->EmitParmDecl(*vd,
clang::CodeGen::CodeGenFunction::ParamValue::forDirect(Cxx->CGF->Builder.CreateBitCast(V, Ty)), 0);
#else
Cxx->CGF->EmitParmDecl(*vd, Cxx->CGF->Builder.CreateBitCast(V, Ty), false, 0);
#endif
#endif
}
JL_DLLEXPORT void AddDeclToDeclCtx(clang::DeclContext *DC, clang::Decl *D)
{
DC->addDecl(D);
}
JL_DLLEXPORT void *CreateDeclRefExpr(C,clang::ValueDecl *D, clang::CXXScopeSpec *scope, int islvalue)
{
clang::QualType T = D->getType();
return (void*)clang::DeclRefExpr::Create(Cxx->CI->getASTContext(), scope ?
scope->getWithLocInContext(Cxx->CI->getASTContext()) : clang::NestedNameSpecifierLoc(nullptr,nullptr),
getTrivialSourceLocation(Cxx), D, false, getTrivialSourceLocation(Cxx),
T.getNonReferenceType(), islvalue ? clang::VK_LValue : clang::VK_RValue);
}
JL_DLLEXPORT void *DeduceReturnType(clang::Expr *expr)
{
return expr->getType().getAsOpaquePtr();
}
JL_DLLEXPORT void *CreateFunction(C, llvm::Type *rt, llvm::Type** argt, size_t nargs)
{
llvm::FunctionType *ft = llvm::FunctionType::get(rt,llvm::ArrayRef<llvm::Type*>(argt,nargs),false);
return (void*)llvm::Function::Create(ft, llvm::GlobalValue::ExternalLinkage, "cxxjl", Cxx->shadow);
}
JL_DLLEXPORT void *tovdecl(clang::Decl *D)
{
return clang::dyn_cast<clang::ValueDecl>(D);
}
JL_DLLEXPORT void *cxxtmplt(clang::Decl *D)
{
return clang::dyn_cast<clang::ClassTemplateDecl>(D);
}
JL_DLLEXPORT void *extractTypePtr(void *QT)
{
return (void*)clang::QualType::getFromOpaquePtr(QT).getTypePtr();
}
JL_DLLEXPORT unsigned extractCVR(void *QT)
{
return clang::QualType::getFromOpaquePtr(QT).getCVRQualifiers();
}
JL_DLLEXPORT void *emitcallexpr(C, clang::Expr *E, llvm::Value *rslot)
{
if (clang::isa<clang::CXXBindTemporaryExpr>(E))
E = clang::cast<clang::CXXBindTemporaryExpr>(E)->getSubExpr();
clang::CallExpr *CE = clang::dyn_cast<clang::CallExpr>(E);
assert(CE != nullptr);
clang::CodeGen::RValue ret = Cxx->CGF->EmitCallExpr(CE,clang::CodeGen::ReturnValueSlot(
#ifdef LLVM38
clang::CodeGen::Address(rslot,clang::CharUnits::One()),
#else
rslot,
#endif
false));
if (ret.isScalar())
return ret.getScalarVal();
else
#ifdef LLVM38
return ret.getAggregateAddress().getPointer();
#else
return ret.getAggregateAddr();
#endif
}
JL_DLLEXPORT void emitexprtomem(C,clang::Expr *E, llvm::Value *addr, int isInit)
{
Cxx->CGF->EmitAnyExprToMem(E,
#ifdef LLVM38
clang::CodeGen::Address(addr,clang::CharUnits::One()),
#else
addr,
#endif
clang::Qualifiers(), isInit);
}
JL_DLLEXPORT void *EmitAnyExpr(C, clang::Expr *E, llvm::Value *rslot)
{
clang::CodeGen::RValue ret = Cxx->CGF->EmitAnyExpr(E);
if (ret.isScalar())
return ret.getScalarVal();
else
#ifdef LLVM38
return ret.getAggregateAddress().getPointer();
#else
return ret.getAggregateAddr();
#endif
}
JL_DLLEXPORT void *get_nth_argument(llvm::Function *f, size_t n)
{
size_t i = 0;
llvm::Function::arg_iterator AI = f->arg_begin();
for (; AI != f->arg_end(); ++i, ++AI)
{
if (i == n)
return (void*)((llvm::Value*)&*AI++);
}
return nullptr;
}
JL_DLLEXPORT void *create_extract_value(C, llvm::Value *agg, size_t idx)
{
//dad//return Cxx->CGF->Builder.CreateExtractValue(agg,clang::ArrayRef<unsigned>((unsigned)idx));
}
JL_DLLEXPORT void *create_insert_value(llvm::IRBuilder<false> *builder, llvm::Value *agg, llvm::Value *val, size_t idx)
{
return builder->CreateInsertValue(agg,val,clang::ArrayRef<unsigned>((unsigned)idx));
}
JL_DLLEXPORT void *CreateIntToPtr(llvm::IRBuilder<false> *builder, llvm::Value *TheInt, llvm::Type *Ty)
{
return builder->CreateIntToPtr(TheInt, Ty);
}
JL_DLLEXPORT void *CreatePtrToInt(llvm::IRBuilder<false> *builder, llvm::Value *TheInt, llvm::Type *Ty)
{
return builder->CreatePtrToInt(TheInt, Ty);
}
JL_DLLEXPORT void *tu_decl(C)
{
return Cxx->CI->getASTContext().getTranslationUnitDecl();
}
JL_DLLEXPORT void *get_primary_dc(clang::DeclContext *dc)
{
return dc->getPrimaryContext();
}
JL_DLLEXPORT void *decl_context(clang::Decl *decl)
{
if(clang::isa<clang::TypedefNameDecl>(decl))
{
decl = clang::dyn_cast<clang::TypedefNameDecl>(decl)->getUnderlyingType().getTypePtr()->getAsCXXRecordDecl();
}
if (decl == nullptr)
return decl;
if(clang::isa<clang::ClassTemplateSpecializationDecl>(decl))
{
auto ptr = clang::cast<clang::ClassTemplateSpecializationDecl>(decl)->getSpecializedTemplateOrPartial();
if (ptr.is<clang::ClassTemplateDecl*>())
decl = ptr.get<clang::ClassTemplateDecl*>();
else
decl = ptr.get<clang::ClassTemplatePartialSpecializationDecl*>();
}
return clang::dyn_cast<clang::DeclContext>(decl);
}
JL_DLLEXPORT void *to_decl(clang::DeclContext *decl)
{
return clang::dyn_cast<clang::Decl>(decl);
}
JL_DLLEXPORT void *to_cxxdecl(clang::Decl *decl)
{
return clang::dyn_cast<clang::CXXRecordDecl>(decl);
}
JL_DLLEXPORT void *GetFunctionReturnType(clang::FunctionDecl *FD)
{
return FD->getReturnType().getAsOpaquePtr();
}
JL_DLLEXPORT void *BuildDecltypeType(C, clang::Expr *E)
{
clang::QualType T = Cxx->CI->getSema().BuildDecltypeType(E,E->getLocStart());
return Cxx->CI->getASTContext().getCanonicalType(T).getAsOpaquePtr();
}
JL_DLLEXPORT void *getTemplateArgs(clang::ClassTemplateSpecializationDecl *tmplt)
{
return (void*)&tmplt->getTemplateArgs();
}
JL_DLLEXPORT size_t getTargsSize(clang::TemplateArgumentList *targs)
{
return targs->size();
}
JL_DLLEXPORT size_t getTSTTargsSize(clang::TemplateSpecializationType *TST)
{
return TST->getNumArgs();
}
JL_DLLEXPORT size_t getTDNumParameters(clang::TemplateDecl *TD)
{
return TD->getTemplateParameters()->size();
}
JL_DLLEXPORT void *getTargsPointer(clang::TemplateArgumentList *targs)
{
return (void*)targs->data();
}
JL_DLLEXPORT void *getTargType(const clang::TemplateArgument *targ)
{
return (void*)targ->getAsType().getAsOpaquePtr();
}
JL_DLLEXPORT void *getTDParamAtIdx(clang::TemplateDecl *TD, int i)
{
return (void*)TD->getTemplateParameters()->getParam(i);
}
JL_DLLEXPORT void *getTargTypeAtIdx(clang::TemplateArgumentList *targs, size_t i)
{
return getTargType(&targs->get(i));
}
JL_DLLEXPORT void *getTSTTargTypeAtIdx(clang::TemplateSpecializationType *targs, size_t i)
{
return getTargType(&targs->getArg(i));
}
JL_DLLEXPORT void *getTargIntegralType(const clang::TemplateArgument *targ)
{
return targ->getIntegralType().getAsOpaquePtr();
}
JL_DLLEXPORT void *getTargIntegralTypeAtIdx(clang::TemplateArgumentList *targs, size_t i)
{
return getTargIntegralType(&targs->get(i));
}
JL_DLLEXPORT int getTargKind(const clang::TemplateArgument *targ)
{
return targ->getKind();
}
JL_DLLEXPORT int getTargKindAtIdx(clang::TemplateArgumentList *targs, size_t i)
{
return getTargKind(&targs->get(i));
}
JL_DLLEXPORT int getTSTTargKindAtIdx(clang::TemplateSpecializationType *TST, size_t i)
{
return getTargKind(&TST->getArg(i));
}
JL_DLLEXPORT size_t getTargPackAtIdxSize(clang::TemplateArgumentList *targs, size_t i)
{
return targs->get(i).getPackAsArray().size();
}
JL_DLLEXPORT void *getTargPackAtIdxTargAtIdx(clang::TemplateArgumentList *targs, size_t i, size_t j)
{
return (void*)&targs->get(i).getPackAsArray()[j];
}
JL_DLLEXPORT int64_t getTargAsIntegralAtIdx(clang::TemplateArgumentList *targs, size_t i)
{
return targs->get(i).getAsIntegral().getSExtValue();
}
void *getTargPackBegin(clang::TemplateArgument *targ)
{
return (void*)targ->pack_begin();
}
size_t getTargPackSize(clang::TemplateArgument *targ)
{
return targ->pack_size();
}
JL_DLLEXPORT void *getPointeeType(clang::Type *t)
{
return t->getPointeeType().getAsOpaquePtr();
}
JL_DLLEXPORT void *getArrayElementType(clang::Type *t)
{
return clang::cast<clang::ArrayType>(t)->getElementType().getAsOpaquePtr();
}
JL_DLLEXPORT void *getOriginalType(clang::ParmVarDecl *d)
{
return (void*)d->getOriginalType().getAsOpaquePtr();
}
JL_DLLEXPORT void *getPointerTo(C, void *T)
{
return Cxx->CI->getASTContext().getPointerType(clang::QualType::getFromOpaquePtr(T)).getAsOpaquePtr();
}
JL_DLLEXPORT void *getReferenceTo(C, void *T)
{
return Cxx->CI->getASTContext().getLValueReferenceType(clang::QualType::getFromOpaquePtr(T)).getAsOpaquePtr();
}
JL_DLLEXPORT void *getRvalueReferenceTo(C, void *T)
{
return Cxx->CI->getASTContext().getRValueReferenceType(clang::QualType::getFromOpaquePtr(T)).getAsOpaquePtr();
}
JL_DLLEXPORT void *getIncompleteArrayType(C, void *T)
{
return Cxx->CI->getASTContext().getIncompleteArrayType(
clang::QualType::getFromOpaquePtr(T),
clang::ArrayType::Normal, 0).getAsOpaquePtr();
}
JL_DLLEXPORT void *createDerefExpr(C, clang::Expr *expr)
{
return (void*)Cxx->CI->getSema().CreateBuiltinUnaryOp(getTrivialSourceLocation(Cxx),clang::UO_Deref,expr).get();
}
JL_DLLEXPORT void *createAddrOfExpr(C, clang::Expr *expr)
{
return (void*)Cxx->CI->getSema().CreateBuiltinUnaryOp(getTrivialSourceLocation(Cxx),clang::UO_AddrOf,expr).get();
}
JL_DLLEXPORT void *createCast(C,clang::Expr *expr, clang::Type *t, int kind)
{
return clang::ImplicitCastExpr::Create(Cxx->CI->getASTContext(),clang::QualType(t,0),
(clang::CastKind)kind,expr,nullptr,clang::VK_RValue);
}
JL_DLLEXPORT void *CreateBinOp(C, clang::Scope *S, int opc, clang::Expr *LHS, clang::Expr *RHS)
{
return (void*)Cxx->CI->getSema().BuildBinOp(S,clang::SourceLocation(),(clang::BinaryOperatorKind)opc,LHS,RHS).get();
}
JL_DLLEXPORT void *BuildMemberReference(C, clang::Expr *base, clang::Type *t, int IsArrow, char *name)
{
clang::DeclarationName DName(&Cxx->CI->getASTContext().Idents.get(name));
clang::Sema &sema = Cxx->CI->getSema();
clang::CXXScopeSpec scope;
return (void*)sema.BuildMemberReferenceExpr(base,clang::QualType(t,0), getTrivialSourceLocation(Cxx), IsArrow, scope,
getTrivialSourceLocation(Cxx), nullptr, clang::DeclarationNameInfo(DName, getTrivialSourceLocation(Cxx)), nullptr, nullptr).get();
}
JL_DLLEXPORT void *BuildDeclarationNameExpr(C, char *name, clang::DeclContext *ctx)
{
clang::Sema &sema = Cxx->CI->getSema();
clang::SourceManager &sm = Cxx->CI->getSourceManager();
clang::CXXScopeSpec spec;
spec.setBeginLoc(sm.getLocForStartOfFile(sm.getMainFileID()));
spec.setEndLoc(sm.getLocForStartOfFile(sm.getMainFileID()));
clang::DeclarationName DName(&Cxx->CI->getASTContext().Idents.get(name));
sema.RequireCompleteDeclContext(spec,ctx);
clang::LookupResult R(sema, DName, getTrivialSourceLocation(Cxx), clang::Sema::LookupAnyName);
sema.LookupQualifiedName(R, ctx, false);
return (void*)sema.BuildDeclarationNameExpr(spec,R,false).get();
}
JL_DLLEXPORT void *clang_get_builder(C)
{
return (void*)&Cxx->CGF->Builder;
}
JL_DLLEXPORT void *jl_get_llvmc()
{
return &jl_LLVMContext;
}
JL_DLLEXPORT void cdump(void *decl)
{
((clang::Decl*) decl)->dump();
}
JL_DLLEXPORT void dcdump(clang::DeclContext *DC)
{
DC->dumpDeclContext();
}
JL_DLLEXPORT void exprdump(void *expr)
{
((clang::Expr*) expr)->dump();
}
JL_DLLEXPORT void typedump(void *t)
{
((clang::Type*) t)->dump();
}
JL_DLLEXPORT void llvmdump(void *t)
{
((llvm::Value*) t)->dump();
}
JL_DLLEXPORT void llvmtdump(void *t)
{
((llvm::Type*) t)->dump();
}
JL_DLLEXPORT void *createLoad(llvm::IRBuilder<false> *builder, llvm::Value *val)
{
return builder->CreateLoad(val);
}
JL_DLLEXPORT void *CreateConstGEP1_32(llvm::IRBuilder<false> *builder, llvm::Value *val, uint32_t idx)
{
return (void*)builder->CreateConstGEP1_32(val,idx);
}
#define TMember(s) \
JL_DLLEXPORT int s(clang::Type *t) \
{ \
return t->s(); \
}
TMember(isVoidType)
TMember(isBooleanType)
TMember(isPointerType)
TMember(isFunctionPointerType)
TMember(isFunctionType)
TMember(isFunctionProtoType)
TMember(isMemberFunctionPointerType)
TMember(isReferenceType)
TMember(isCharType)
TMember(isIntegerType)
TMember(isEnumeralType)
TMember(isFloatingType)
TMember(isDependentType)
TMember(isTemplateTypeParmType)
TMember(isArrayType)
JL_DLLEXPORT int isTemplateSpecializationType(clang::Type *t)
{
return clang::isa<clang::TemplateSpecializationType>(t);
}
JL_DLLEXPORT int isElaboratedType(clang::Type *t)
{
return clang::isa<clang::ElaboratedType>(t);
}
JL_DLLEXPORT void *isIncompleteType(clang::Type *t)
{
clang::NamedDecl *ND = nullptr;
t->isIncompleteType(&ND);
return ND;
}
#define W(M,ARG) \
JL_DLLEXPORT void *M(ARG *p) \
{ \
return (void *)p->M(); \
}
W(getPointeeCXXRecordDecl, clang::Type)
W(getAsCXXRecordDecl, clang::Type)
#define ISAD(NS,T,ARGT) \
JL_DLLEXPORT int isa ## T(ARGT *p) \
{ \
return llvm::isa<NS::T>(p); \
} \
JL_DLLEXPORT void *dcast ## T(ARGT *p) \
{ \
return llvm::dyn_cast<NS::T>(p); \
}
ISAD(clang,ClassTemplateSpecializationDecl,clang::Decl)
ISAD(clang,CXXRecordDecl,clang::Decl)
ISAD(clang,NamespaceDecl,clang::Decl)
ISAD(clang,VarDecl,clang::Decl)
ISAD(clang,ValueDecl,clang::Decl)
ISAD(clang,FunctionDecl,clang::Decl)
ISAD(clang,TypeDecl,clang::Decl)
ISAD(clang,CXXMethodDecl,clang::Decl)
ISAD(clang,CXXConstructorDecl,clang::Decl)
JL_DLLEXPORT int isVoidTy(llvm::Type *t)
{
return t->isVoidTy();
}
JL_DLLEXPORT void *getUndefValue(llvm::Type *t)
{
return (void*)llvm::UndefValue::get(t);
}
JL_DLLEXPORT void *getStructElementType(llvm::Type *t, uint32_t i)
{
return (void*)t->getStructElementType(i);
}
JL_DLLEXPORT void *CreateRet(llvm::IRBuilder<false> *builder, llvm::Value *ret)
{
return (void*)builder->CreateRet(ret);
}
JL_DLLEXPORT void *CreateRetVoid(llvm::IRBuilder<false> *builder)
{
return (void*)builder->CreateRetVoid();
}
JL_DLLEXPORT void *CreateBitCast(llvm::IRBuilder<false> *builder, llvm::Value *val, llvm::Type *type)
{
return (void*)builder->CreateBitCast(val,type);
}
JL_DLLEXPORT void *getConstantIntToPtr(llvm::Constant *CC, llvm::Type *type)
{
return (void*)llvm::ConstantExpr::getIntToPtr(CC,type);
}
JL_DLLEXPORT size_t cxxsizeof(C, clang::CXXRecordDecl *decl)
{
clang::CodeGen::CodeGenTypes *cgt = &Cxx->CGM->getTypes();
#ifdef LLVM38
auto dl = Cxx->shadow->getDataLayout();
#else
auto dl = Cxx->shadow->getDataLayout();
#endif
Cxx->CI->getSema().RequireCompleteType(getTrivialSourceLocation(Cxx),
clang::QualType(decl->getTypeForDecl(),0),0);
auto t = cgt->ConvertRecordDeclType(decl);
return dl.getTypeSizeInBits(t)/8;
}
JL_DLLEXPORT size_t cxxsizeofType(C, void *t)
{
auto dl = Cxx->shadow->getDataLayout();
clang::CodeGen::CodeGenTypes *cgt = &Cxx->CGM->getTypes();
return dl.getTypeSizeInBits(
cgt->ConvertTypeForMem(clang::QualType::getFromOpaquePtr(t)))/8;
}
JL_DLLEXPORT void *ConvertTypeForMem(C, void *t)
{
return (void*)Cxx->CGM->getTypes().ConvertTypeForMem(clang::QualType::getFromOpaquePtr(t));
}
JL_DLLEXPORT void *getValueType(llvm::Value *val)
{
return (void*)val->getType();
}
JL_DLLEXPORT int isLLVMPointerType(llvm::Type *t)
{
return t->isPointerTy();
}
JL_DLLEXPORT void *getLLVMPointerTo(llvm::Type *t)
{
return (void*)t->getPointerTo();
}
JL_DLLEXPORT void *getContext(clang::Decl *d)
{
return (void*)d->getDeclContext();
}
JL_DLLEXPORT void *getParentContext(clang::DeclContext *DC)
{
return (void*)DC->getParent();
}
JL_DLLEXPORT void *getCxxMDParent(clang::CXXMethodDecl *CxxMD)
{
return CxxMD->getParent();
}
JL_DLLEXPORT uint64_t getDCDeclKind(clang::DeclContext *DC)
{
return (uint64_t)DC->getDeclKind();
}
JL_DLLEXPORT void *getDirectCallee(clang::CallExpr *e)
{
return (void*)e->getDirectCallee();
}
JL_DLLEXPORT void *getCalleeReturnType(clang::CallExpr *e)
{
clang::FunctionDecl *fd = e->getDirectCallee();
if (fd == nullptr)
return nullptr;
return (void*)fd->getReturnType().getAsOpaquePtr();
}
JL_DLLEXPORT void *newCXXScopeSpec(C)
{
clang::CXXScopeSpec *scope = new clang::CXXScopeSpec();
scope->MakeGlobal(Cxx->CI->getASTContext(),getTrivialSourceLocation(Cxx));
return (void*)scope;
}
JL_DLLEXPORT void deleteCXXScopeSpec(clang::CXXScopeSpec *spec)
{
delete spec;
}
JL_DLLEXPORT void ExtendNNS(C,clang::NestedNameSpecifierLocBuilder *builder, clang::NamespaceDecl *d)
{
builder->Extend(Cxx->CI->getASTContext(),d,getTrivialSourceLocation(Cxx),getTrivialSourceLocation(Cxx));
}
JL_DLLEXPORT void ExtendNNSIdentifier(C,clang::NestedNameSpecifierLocBuilder *builder, const char *Name)
{
clang::Preprocessor &PP = Cxx->Parser->getPreprocessor();
// Get the identifier.
clang::IdentifierInfo *Id = PP.getIdentifierInfo(Name);
builder->Extend(Cxx->CI->getASTContext(),Id,getTrivialSourceLocation(Cxx),getTrivialSourceLocation(Cxx));
}
JL_DLLEXPORT void ExtendNNSType(C,clang::NestedNameSpecifierLocBuilder *builder, void *t)
{
clang::TypeLocBuilder TLBuilder;
clang::QualType T = clang::QualType::getFromOpaquePtr(t);
TLBuilder.push<clang::QualifiedTypeLoc>(T);
builder->Extend(Cxx->CI->getASTContext(),clang::SourceLocation(),
TLBuilder.getTypeLocInContext(
Cxx->CI->getASTContext(),
T),
getTrivialSourceLocation(Cxx));
}
JL_DLLEXPORT void *makeFunctionType(C, void *rt, void **argts, size_t nargs)
{
clang::QualType T;
if (rt == nullptr) {
T = Cxx->CI->getASTContext().getAutoType(clang::QualType(),
#ifdef LLVM38
clang::AutoTypeKeyword::DecltypeAuto,
#else
/*decltype(auto)*/true,
#endif
/*IsDependent*/ false);
} else {
T = clang::QualType::getFromOpaquePtr(rt);
}
clang::QualType *qargs = (clang::QualType *)__builtin_alloca(nargs*sizeof(clang::QualType));
for (size_t i = 0; i < nargs; ++i)
qargs[i] = clang::QualType::getFromOpaquePtr(argts[i]);
clang::FunctionProtoType::ExtProtoInfo EPI;
return Cxx->CI->getASTContext().getFunctionType(T, llvm::ArrayRef<clang::QualType>(qargs, nargs), EPI).getAsOpaquePtr();
}
JL_DLLEXPORT void *makeMemberFunctionType(C, void *FT, clang::Type *cls)
{
return Cxx->CI->getASTContext().getMemberPointerType(clang::QualType::getFromOpaquePtr(FT), cls).getAsOpaquePtr();
}
JL_DLLEXPORT void *getMemberPointerClass(clang::Type *mptr)
{
return (void*)clang::cast<clang::MemberPointerType>(mptr)->getClass();
}
JL_DLLEXPORT void *getMemberPointerPointee(clang::Type *mptr)
{
return clang::cast<clang::MemberPointerType>(mptr)->getPointeeType().getAsOpaquePtr();
}
JL_DLLEXPORT void *getFPTReturnType(clang::FunctionProtoType *fpt)
{
return fpt->getReturnType().getAsOpaquePtr();
}
JL_DLLEXPORT void *getFDReturnType(clang::FunctionDecl *FD)
{
return FD->getReturnType().getAsOpaquePtr();
}
JL_DLLEXPORT size_t getFPTNumParams(clang::FunctionProtoType *fpt)
{
return fpt->getNumParams();
}
JL_DLLEXPORT size_t getFDNumParams(clang::FunctionDecl *FD)
{
return FD->getNumParams();
}
JL_DLLEXPORT void *getFPTParam(clang::FunctionProtoType *fpt, size_t idx)
{
return fpt->getParamType(idx).getAsOpaquePtr();
}
JL_DLLEXPORT void *getLLVMStructType(llvm::Type **ts, size_t nts)
{
return (void*)llvm::StructType::get(jl_LLVMContext,clang::ArrayRef<llvm::Type*>(ts,nts));
}
JL_DLLEXPORT void MarkDeclarationsReferencedInExpr(C,clang::Expr *e)
{
clang::Sema &sema = Cxx->CI->getSema();
sema.MarkDeclarationsReferencedInExpr(e, true);
}
JL_DLLEXPORT void *getConstantFloat(llvm::Type *llvmt, double x)
{
return llvm::ConstantFP::get(llvmt,x);
}
JL_DLLEXPORT void *getConstantInt(llvm::Type *llvmt, uint64_t x)
{
return llvm::ConstantInt::get(llvmt,x);
}
JL_DLLEXPORT void *getConstantStruct(llvm::Type *llvmt, llvm::Constant **vals, size_t nvals)
{
return llvm::ConstantStruct::get(clang::cast<llvm::StructType>(llvmt),clang::ArrayRef<llvm::Constant*>(vals,nvals));
}
JL_DLLEXPORT const clang::Type *canonicalType(clang::Type *t)
{
return t->getCanonicalTypeInternal().getTypePtr();
}
JL_DLLEXPORT int builtinKind(clang::Type *t)
{
assert(clang::isa<clang::BuiltinType>(t));
return clang::cast<clang::BuiltinType>(t)->getKind();
}
JL_DLLEXPORT int isDeclInvalid(clang::Decl *D)
{
return D->isInvalidDecl();
}
// Test Support
JL_DLLEXPORT void *clang_get_cgt(C)
{
return (void*)&Cxx->CGM->getTypes();
}
JL_DLLEXPORT void *clang_shadow_module(C)
{
return (void*)Cxx->shadow;
}
JL_DLLEXPORT int RequireCompleteType(C,clang::Type *t)
{
clang::Sema &sema = Cxx->CI->getSema();
return sema.RequireCompleteType(getTrivialSourceLocation(Cxx),clang::QualType(t,0),0);
}
JL_DLLEXPORT void *CreateTemplatedFunction(C, char *Name, clang::TemplateParameterList** args, size_t nargs)
{
clang::DeclSpec DS(Cxx->Parser->getAttrFactory());
clang::Declarator D(DS, clang::Declarator::PrototypeContext);
clang::Preprocessor &PP = Cxx->Parser->getPreprocessor();
D.getName().setIdentifier(PP.getIdentifierInfo(Name),clang::SourceLocation());
clang::Sema &sema = Cxx->CI->getSema();
return sema.ActOnTemplateDeclarator(nullptr,clang::MultiTemplateParamsArg(args,nargs),D);
}
JL_DLLEXPORT void *ActOnTypeParameter(C, char *Name, unsigned Position)
{
clang::Sema &sema = Cxx->CI->getSema();
clang::ParsedType DefaultArg;
clang::Preprocessor &PP = Cxx->Parser->getPreprocessor();
clang::Scope S(nullptr,clang::Scope::TemplateParamScope,Cxx->CI->getDiagnostics());
void *ret = (void*)sema.ActOnTypeParameter(&S, false, clang::SourceLocation(),
clang::SourceLocation(), PP.getIdentifierInfo(Name), clang::SourceLocation(), 0, Position,
clang::SourceLocation(), DefaultArg);
//sema.ActOnPopScope(clang::SourceLocation(),&S);
return ret;
}
JL_DLLEXPORT void *CreateAnonymousClass(C, clang::Decl *Scope)
{
clang::CXXRecordDecl *RD = clang::CXXRecordDecl::Create(
Cxx->CI->getASTContext(), clang::TTK_Class,
clang::dyn_cast<clang::DeclContext>(Scope),
clang::SourceLocation(), clang::SourceLocation(),
nullptr);
RD->setImplicit(true);
RD->startDefinition();
return (void*)RD;
}
JL_DLLEXPORT void *AddCallOpToClass(clang::CXXRecordDecl *TheClass, clang::CXXMethodDecl *Method)
{
TheClass->addDecl(Method);
return Method;
}
JL_DLLEXPORT void FinalizeAnonClass(C, clang::CXXRecordDecl *TheClass)
{
llvm::SmallVector<clang::Decl *, 0> Fields;
Cxx->CI->getSema().ActOnFields(nullptr, clang::SourceLocation(), TheClass,
Fields, clang::SourceLocation(), clang::SourceLocation(), nullptr);
Cxx->CI->getSema().CheckCompletedCXXClass(TheClass);
}
JL_DLLEXPORT void EnterParserScope(C)
{
Cxx->Parser->EnterScope(clang::Scope::TemplateParamScope);
}
JL_DLLEXPORT void *ActOnTypeParameterParserScope(C, char *Name, unsigned Position)
{
clang::Sema &sema = Cxx->CI->getSema();
clang::ParsedType DefaultArg;
clang::Preprocessor &PP = Cxx->Parser->getPreprocessor();
void *ret = (void*)sema.ActOnTypeParameter(Cxx->Parser->getCurScope(), false, clang::SourceLocation(),
clang::SourceLocation(), PP.getIdentifierInfo(Name), clang::SourceLocation(), 0, Position,
clang::SourceLocation(), DefaultArg);
//sema.ActOnPopScope(clang::SourceLocation(),&S);
return ret;
}
JL_DLLEXPORT void ExitParserScope(C)
{
Cxx->Parser->ExitScope();
}
JL_DLLEXPORT void *CreateTemplateParameterList(C, clang::NamedDecl **D, size_t ND)
{
return (void*)clang::TemplateParameterList::Create(Cxx->CI->getASTContext(), clang::SourceLocation(),
clang::SourceLocation(), llvm::makeArrayRef(D, ND), clang::SourceLocation());
}
JL_DLLEXPORT void *CreateFunctionTemplateDecl(C, clang::DeclContext *DC, clang::TemplateParameterList *Params, clang::FunctionDecl *FD)
{
clang::FunctionTemplateDecl *FTD = clang::FunctionTemplateDecl::Create(
Cxx->CI->getASTContext(), DC, clang::SourceLocation(),
FD->getNameInfo().getName(), Params, FD);
FD->setDescribedFunctionTemplate(FTD);
FTD->setAccess(clang::AS_public);
return (void*)FTD;
}
JL_DLLEXPORT void *GetDescribedFunctionTemplate(clang::FunctionDecl *FD)
{
return (void*)FD->getDescribedFunctionTemplate();
}
JL_DLLEXPORT void *newFDVector() { return (void*)new std::vector<clang::FunctionDecl*>; }
JL_DLLEXPORT void deleteFDVector(void *v) { delete ((std::vector<clang::FunctionDecl*>*) v); }
JL_DLLEXPORT void copyFDVector(void *to, std::vector<clang::FunctionDecl*> *from)
{
memcpy(to, from->data(), sizeof(clang::FunctionDecl*)*from->size());
}
JL_DLLEXPORT size_t getFDVectorSize(std::vector<clang::FunctionDecl*> *v) {return v->size(); }
JL_DLLEXPORT void getSpecializations(clang::FunctionTemplateDecl *FTD, std::vector<clang::FunctionDecl*> *specs)
{
for (auto it : FTD->specializations())
specs->push_back(it);
}
JL_DLLEXPORT const char *getMangledFunctionName(C,clang::FunctionDecl *D)
{
return Cxx->CGM->getMangledName(clang::GlobalDecl(D)).data();
}
JL_DLLEXPORT const void *getTemplateSpecializationArgs(clang::FunctionDecl *FD)
{
return (const void*)FD->getTemplateSpecializationArgs();
}
JL_DLLEXPORT void *getLambdaCallOperator(clang::CXXRecordDecl *R)
{
return R->getLambdaCallOperator();
}
JL_DLLEXPORT void *getCallOperator(C, clang::CXXRecordDecl *R)
{
clang::DeclarationName Name =
Cxx->CI->getASTContext().DeclarationNames.getCXXOperatorName(clang::OO_Call);
clang::DeclContext::lookup_result Calls = R->lookup(Name);
assert(!Calls.empty() && "Missing lambda call operator!");
assert(Calls.size() == 1 && "More than one lambda call operator!");
clang::NamedDecl *CallOp = Calls.front();
if (clang::FunctionTemplateDecl *CallOpTmpl =
clang::dyn_cast<clang::FunctionTemplateDecl>(CallOp))
return clang::cast<clang::CXXMethodDecl>(CallOpTmpl->getTemplatedDecl());
return clang::cast<clang::CXXMethodDecl>(CallOp);
}
JL_DLLEXPORT bool isCxxDLambda(clang::CXXRecordDecl *R)
{
return R->isLambda();
}
JL_DLLEXPORT void *getFunctionTypeReturnType(void *T)
{
return ((clang::FunctionType*)T)->getReturnType().getAsOpaquePtr();
}
/// From SemaOverload.cpp
/// A convenience routine for creating a decayed reference to a function.
static clang::ExprResult
CreateFunctionRefExpr(clang::Sema &S, clang::FunctionDecl *Fn, clang::NamedDecl *FoundDecl,
bool HadMultipleCandidates,
clang::SourceLocation Loc = clang::SourceLocation(),
const clang::DeclarationNameLoc &LocInfo = clang::DeclarationNameLoc())
{
if (S.DiagnoseUseOfDecl(FoundDecl, Loc))
return clang::ExprError();
// If FoundDecl is different from Fn (such as if one is a template
// and the other a specialization), make sure DiagnoseUseOfDecl is
// called on both.
// FIXME: This would be more comprehensively addressed by modifying
// DiagnoseUseOfDecl to accept both the FoundDecl and the decl
// being used.
if (FoundDecl != Fn && S.DiagnoseUseOfDecl(Fn, Loc))
return clang::ExprError();
clang::DeclRefExpr *DRE = new (S.Context) clang::DeclRefExpr(Fn, false, Fn->getType(),
clang::VK_LValue, Loc, LocInfo);
if (HadMultipleCandidates)
DRE->setHadMultipleCandidates(true);
S.MarkDeclRefReferenced(DRE);
clang::ExprResult E = DRE;
E = S.DefaultFunctionArrayConversion(E.get());
if (E.isInvalid())
return clang::ExprError();
return E;
}
JL_DLLEXPORT void *CreateCStyleCast(C, clang::Expr *E, clang::Type *T)
{
clang::QualType QT(T,0);
return (void*)clang::CStyleCastExpr::Create (Cxx->CI->getASTContext(), QT, clang::VK_RValue, clang::CK_BitCast,
E, nullptr, Cxx->CI->getASTContext().getTrivialTypeSourceInfo(QT), clang::SourceLocation(), clang::SourceLocation());
}
JL_DLLEXPORT void *CreateReturnStmt(C, clang::Expr *E)
{
return (void*)new (Cxx->CI->getASTContext()) clang::ReturnStmt(clang::SourceLocation(),E,nullptr);
}
JL_DLLEXPORT void *CreateThisExpr(C, void *T)
{
return (void*)new (Cxx->CI->getASTContext()) clang::CXXThisExpr(
clang::SourceLocation(), clang::QualType::getFromOpaquePtr(T),
false);
}
JL_DLLEXPORT void *CreateFunctionRefExprFD(C, clang::FunctionDecl *FD)
{
return (void*)CreateFunctionRefExpr(Cxx->CI->getSema(),FD,FD,false).get();
}
JL_DLLEXPORT void *CreateFunctionRefExprFDTemplate(C, clang::FunctionTemplateDecl *FTD)
{
return (void*)CreateFunctionRefExpr(Cxx->CI->getSema(),FTD->getTemplatedDecl(),FTD,false).get();
}
JL_DLLEXPORT void SetFDBody(clang::FunctionDecl *FD, clang::Stmt *body)
{
FD->setBody(body);
}
JL_DLLEXPORT void ActOnFinishFunctionBody(C,clang::FunctionDecl *FD, clang::Stmt *Body)
{
Cxx->CI->getSema().ActOnFinishFunctionBody(FD,Body,true);
}
JL_DLLEXPORT void *CreateLinkageSpec(C, clang::DeclContext *DC, unsigned kind)
{
return (void *)(clang::DeclContext *)clang::LinkageSpecDecl::Create(Cxx->CI->getASTContext(), DC,
clang::SourceLocation(), clang::SourceLocation(), (clang::LinkageSpecDecl::LanguageIDs) kind,
true);
}
JL_DLLEXPORT const char *getLLVMValueName(llvm::Value *V)
{
return V->getName().data();
}
JL_DLLEXPORT const char *getNDName(clang::NamedDecl *ND)
{
return ND->getName().data();
}
JL_DLLEXPORT void *getParmVarDecl(clang::FunctionDecl *FD, unsigned i)
{
return (void *)FD->getParamDecl(i);
}
JL_DLLEXPORT void SetDeclUsed(C,clang::Decl *D)
{
D->markUsed(Cxx->CI->getASTContext());
}
JL_DLLEXPORT void *getPointerElementType(llvm::Type *T)
{
return (void*)T->getPointerElementType ();
}
JL_DLLEXPORT void emitDestroyCXXObject(C, llvm::Value *x, clang::Type *T)
{
clang::CXXRecordDecl *RD = T->getAsCXXRecordDecl();
clang::CXXDestructorDecl *Destructor = Cxx->CI->getSema().LookupDestructor(RD);
Cxx->CI->getSema().MarkFunctionReferenced(clang::SourceLocation(), Destructor);
Cxx->CI->getSema().DefineUsedVTables();
Cxx->CI->getSema().PerformPendingInstantiations(false);
Cxx->CGF->destroyCXXObject(*Cxx->CGF,
#ifdef LLVM38
clang::CodeGen::Address(x,clang::CharUnits::One()),
#else
x,
#endif
clang::QualType(T,0));
}
JL_DLLEXPORT bool hasTrivialDestructor(C, clang::CXXRecordDecl *RD)
{
clang::CXXScopeSpec spec;
spec.setBeginLoc(getTrivialSourceLocation(Cxx));
clang::Sema &cs = Cxx->CI->getSema();
cs.RequireCompleteDeclContext(spec,RD);
return RD->hasTrivialDestructor();
}
JL_DLLEXPORT void setPersonality(llvm::Function *F, llvm::Function *PersonalityF)
{
F->setPersonalityFn(PersonalityF);
}
JL_DLLEXPORT void *getFunction(C, const char *name, size_t length)
{
return Cxx->shadow->getFunction(llvm::StringRef(name,length));
}
JL_DLLEXPORT int hasFDBody(clang::FunctionDecl *FD)
{
return FD->hasBody();
}
JL_DLLEXPORT void *getUnderlyingTemplateDecl(clang::TemplateSpecializationType *TST)
{
return (void*)TST->getTemplateName().getAsTemplateDecl();
}
JL_DLLEXPORT void *getOrCreateTemplateSpecialization(C, clang::FunctionTemplateDecl *FTD, void **T, size_t nargs)
{
clang::TemplateArgumentListInfo TALI;
clang::sema::TemplateDeductionInfo Info(clang::SourceLocation{});
clang::FunctionDecl *FD;
for (size_t i = 0; i < nargs; ++i) {
clang::QualType QT = clang::QualType::getFromOpaquePtr(T[i]);
clang::TemplateArgumentLoc TAL(
clang::TemplateArgument{QT},
Cxx->CI->getASTContext().getTrivialTypeSourceInfo(QT));
TALI.addArgument(TAL);
}
Cxx->CI->getSema().DeduceTemplateArguments(FTD, &TALI, FD, Info, false);
return FD;
}
JL_DLLEXPORT void *CreateIntegerLiteral(C, uint64_t val, void *T)
{
clang::QualType QT = clang::QualType::getFromOpaquePtr(T);
return (void*)clang::IntegerLiteral::Create(Cxx->CI->getASTContext(),
llvm::APInt(8*sizeof(uint64_t),val), QT, clang::SourceLocation());
}
JL_DLLEXPORT void *desugarElaboratedType(clang::ElaboratedType *T)
{
return (void *)T->desugar().getAsOpaquePtr();
}
JL_DLLEXPORT unsigned getTTPTIndex(clang::TemplateTypeParmType *TTPT)
{
return TTPT->getIndex();
}
JL_DLLEXPORT void *getTemplatedDecl(clang::TemplateDecl *TD)
{
return TD->getTemplatedDecl();
}
JL_DLLEXPORT void *getEmptyStructType()
{
return (void*)llvm::StructType::get(jl_LLVMContext);
}
JL_DLLEXPORT void *getUnderlyingTypeOfEnum(clang::Type *T)
{
return (void*)clang::cast<clang::EnumType>(T)->getDecl()->getIntegerType().getAsOpaquePtr();
}
JL_DLLEXPORT void SetVarDeclInit(clang::VarDecl *VD, clang::Expr *Init)
{
return VD->setInit(Init);
}
JL_DLLEXPORT void SetConstexpr(clang::VarDecl *VD)
{
VD->setConstexpr(true);
}
JL_DLLEXPORT void InsertIntoShadowModule(C, llvm::Function *F)
{
// Copy the declaration characteristics of the Function (not the body)
llvm::Function *NewF = llvm::Function::Create(F->getFunctionType(),
llvm::Function::ExternalLinkage,
F->getName(), Cxx->shadow);
// FunctionType does not include any attributes. Copy them over manually
// as codegen may make decisions based on the presence of certain attributes
NewF->copyAttributesFrom(F);
#ifdef LLVM37
// Declarations are not allowed to have personality routines, but
// copyAttributesFrom sets them anyway, so clear them again manually
NewF->setPersonalityFn(nullptr);
#endif
#ifdef LLVM35
// DLLImport only needs to be set for the shadow module
// it just gets annoying in the JIT
NewF->setDLLStorageClass(GlobalValue::DefaultStorageClass);
#endif
}
//extern void *jl_pchar_to_string(const char *str, size_t len);
JL_DLLEXPORT void *getTypeName(C, void *Ty)
{
llvm::SmallString<256> OutName;
llvm::raw_svector_ostream Out(OutName);
Cxx->CGM->getCXXABI().
getMangleContext().mangleCXXRTTIName(clang::QualType::getFromOpaquePtr(Ty), Out);
StringRef Name = OutName.str();
StringRef ActualName = Name.substr(4);
return jl_pchar_to_string(ActualName.data(), ActualName.size());
}
// Exception handling
#include "unwind.h"
void __attribute__((noreturn)) (*process_cxx_exception)(uint64_t exceptionClass, _Unwind_Exception* unwind_exception);
_Unwind_Reason_Code __cxxjl_personality_v0
(int version, _Unwind_Action actions, uint64_t exceptionClass,
_Unwind_Exception* unwind_exception, _Unwind_Context* context)
{
// Catch all exceptions
if (actions & _UA_SEARCH_PHASE)
return _URC_HANDLER_FOUND;
(*process_cxx_exception)(exceptionClass,unwind_exception);
}
//} // extern "C"
/*
* Yes, yes, I know. Once Cxx settles down, I'll try to get this into clang.
* Until then, yay templates
*/
template <class Tag>
struct stowed
{
static typename Tag::type value;
};
template <class Tag>
typename Tag::type stowed<Tag>::value;
template <class Tag, typename Tag::type x>
struct stow_private
{
stow_private() { stowed<Tag>::value = x; }
static stow_private instance;
};
template <class Tag, typename Tag::type x>
stow_private<Tag,x> stow_private<Tag,x>::instance;
typedef llvm::DenseMap<const clang::Type*, llvm::StructType *> TMap;
typedef llvm::DenseMap<const clang::Type*, clang::CodeGen::CGRecordLayout *> CGRMap;
//extern "C" {
// A tag type for A::x. Each distinct private member you need to
// access should have its own tag. Each tag should contain a
// nested ::type that is the corresponding pointer-to-member type.
struct CodeGenTypes_RecordDeclTypes { typedef TMap (clang::CodeGen::CodeGenTypes::*type); };
struct CodeGenTypes_CGRecordLayouts { typedef CGRMap (clang::CodeGen::CodeGenTypes::*type); };
template struct stow_private<CodeGenTypes_RecordDeclTypes,&clang::CodeGen::CodeGenTypes::RecordDeclTypes>;
template struct stow_private<CodeGenTypes_CGRecordLayouts,&clang::CodeGen::CodeGenTypes::CGRecordLayouts>;
void RegisterType(C, clang::TagDecl *D, llvm::StructType *ST)
{
clang::RecordDecl *RD;
if(clang::isa<clang::TypedefNameDecl>(D))
{
RD = clang::dyn_cast<clang::RecordDecl>(
clang::dyn_cast<clang::TypedefNameDecl>(D)->getUnderlyingType()->getAsTagDecl());
} else {
RD = clang::cast<clang::RecordDecl>(D);
}
const clang::Type *Key = Cxx->CI->getASTContext().getTagDeclType(RD).getCanonicalType().getTypePtr();
(Cxx->CGM->getTypes().*stowed<CodeGenTypes_RecordDeclTypes>::value)[Key] = ST;
llvm::StructType *FakeST = llvm::StructType::create(jl_LLVMContext);
(Cxx->CGM->getTypes().*stowed<CodeGenTypes_CGRecordLayouts>::value)[Key] =
Cxx->CGM->getTypes().ComputeRecordLayout(RD,FakeST);
}
JL_DLLEXPORT bool isDCComplete(clang::DeclContext *DC)
{
return (!clang::isa<clang::TagDecl>(DC) || DC->isDependentContext() || clang::cast<clang::TagDecl>(DC)->isCompleteDefinition() || clang::cast<clang::TagDecl>(DC)->isBeingDefined());
}
#include <signal.h>
static void jl_unblock_signal(int sig)
{
// Put in a separate function to save some stack space since
// sigset_t can be pretty big.
sigset_t sset;
sigemptyset(&sset);
sigaddset(&sset, sig);
sigprocmask(SIG_UNBLOCK, &sset, nullptr);
}
//extern "C" {
void *theexception;
//extern void jl_throw(void *);
void abrt_handler(int sig, siginfo_t *info, void *)
{
jl_unblock_signal(sig);
jl_throw(theexception);
}
JL_DLLEXPORT void InstallSIGABRTHandler(void *exception)
{
theexception = exception;
struct sigaction act;
memset(&act, 0, sizeof(struct sigaction));
sigemptyset(&act.sa_mask);
act.sa_sigaction = abrt_handler;
act.sa_flags = SA_ONSTACK | SA_SIGINFO;
if (sigaction(SIGABRT, &act, nullptr) < 0) {
abort(); // hah
}
}
//}
//}
/*
JL_DLLEXPORT Type *julia_type_to_llvm(jl_value_t *jt, bool *isboxed)
{
// this function converts a Julia Type into the equivalent LLVM type
if (isboxed) *isboxed = false;
if (jt == (jl_value_t*)jl_bool_type) return T_int1;
if (jt == (jl_value_t*)jl_bottom_type) return T_void;
if (!jl_is_leaf_type(jt)) {
if (isboxed) *isboxed = true;
return T_pjlvalue;
}
if (jl_is_cpointer_type(jt)) {
Type *lt = julia_type_to_llvm(jl_tparam0(jt));
if (lt == NULL)
return NULL;
if (lt == T_void)
return T_pint8;
return PointerType::get(lt, 0);
}
if (jl_is_bitstype(jt)) {
int nb = jl_datatype_size(jt);
if (jl_is_floattype(jt)) {
#ifndef DISABLE_FLOAT16
if (nb == 2)
return T_float16;
else
#endif
if (nb == 4)
return T_float32;
else if (nb == 8)
return T_float64;
else if (nb == 16)
return T_float128;
}
return Type::getIntNTy(jl_LLVMContext, nb*8);
}
if (jl_isbits(jt)) {
if (((jl_datatype_t*)jt)->size == 0) {
return T_void;
}
return julia_struct_to_llvm(jt, isboxed);
}
if (isboxed) *isboxed = true;
return T_pjlvalue;
}
*/
llvm::Type *my_julia_type_to_llvm(void *jt, bool *isboxed)
{
return llvm::Type::getVoidTy(jl_LLVMContext);
}
int main()
{
std::string cpp_code = R"(
//#include <iostream>
int mycppfunction() {
int z = 0;
int y = 5;
int x = 10;
z = x*y + 2;
//std::cout << "The number is " << z << std::endl;
return z;
}
)";
CxxInstance cxx;
init_clang_instance(&cxx, nullptr, nullptr, true, nullptr, nullptr, my_julia_type_to_llvm);
int rc = cxxparse(&cxx, cpp_code.c_str(), cpp_code.size());
std::string func_name = "mycppfunction";
void *func = getFunction(&cxx, func_name.c_str(), func_name.size());
std::cout << "mycppfunction = " << rc << " : " << func << std::endl;
std::cout << "Hello world!" << std::endl;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment