diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e7aad73..e69ca14e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,7 +14,7 @@ endif(MSVC) # We need to find exactly the right LLVM version, our code usually does not # work across LLVM »minor« releases. find_package(LLVM 3.0 REQUIRED - all-targets bitwriter linker ipo instrumentation backend support tablegen ${EXTRA_LLVM_MODULES}) + all-targets bitwriter linker ipo instrumentation backend support tablegen asmparser ${EXTRA_LLVM_MODULES}) math(EXPR LDC_LLVM_VER ${LLVM_VERSION_MAJOR}*100+${LLVM_VERSION_MINOR}) # diff --git a/dmd/idgen.c b/dmd/idgen.c index 12d11463..49166c26 100644 --- a/dmd/idgen.c +++ b/dmd/idgen.c @@ -239,6 +239,7 @@ Msgtable msgtable[] = { "ldc" }, { "allow_inline" }, { "llvm_inline_asm" }, + { "llvm_inline_ir" }, { "fence" }, { "atomic_load" }, { "atomic_store" }, diff --git a/dmd2/idgen.c b/dmd2/idgen.c index 5334221f..dbb2ef93 100644 --- a/dmd2/idgen.c +++ b/dmd2/idgen.c @@ -283,6 +283,7 @@ Msgtable msgtable[] = { "ldc" }, { "allow_inline" }, { "llvm_inline_asm" }, + { "llvm_inline_ir" }, { "fence" }, { "atomic_load" }, { "atomic_store" }, diff --git a/gen/functions.cpp b/gen/functions.cpp index 269fd87f..6b3e42e5 100644 --- a/gen/functions.cpp +++ b/gen/functions.cpp @@ -257,6 +257,83 @@ llvm::FunctionType* DtoFunctionType(Type* type, Type* thistype, Type* nesttype, ////////////////////////////////////////////////////////////////////////////////////////// +#include +#include "llvm/Support/SourceMgr.h" +#include "llvm/Assembly/Parser.h" + +LLFunction* DtoInlineIRFunction(FuncDeclaration* fdecl) +{ + const char* mangled_name = fdecl->mangle(); + TemplateInstance* tinst = fdecl->parent->isTemplateInstance(); + assert(tinst); + + Objects& objs = tinst->tdtypes; + assert(objs.dim == 3); + + Expression* a0 = isExpression(objs[0]); + assert(a0); + StringExp* strexp = a0->toString(); + assert(strexp); + assert(strexp->sz == 1); + std::string code(static_cast(strexp->string), strexp->len); + + Type* ret = isType(objs[1]); + assert(ret); + + Tuple* a2 = isTuple(objs[2]); + assert(a2); + Objects& arg_types = a2->objects; + + std::string str; + llvm::raw_string_ostream stream(str); + stream << "define " << *DtoType(ret) << " @" << mangled_name << "("; + + for(size_t i = 0; ;) + { + Type* ty = isType(arg_types[i]); + //assert(ty); + if(!ty) + { + error(tinst->loc, + "All parameters of a template defined with pragma llvm_inline_ir, except for the first one, should be types"); + fatal(); + } + stream << *DtoType(ty); + + i++; + if(i >= arg_types.dim) + break; + + stream << ", "; + } + + if(ret->ty == Tvoid) + code.append("\nret void"); + + stream << ")\n{\n" << code << "\n}"; + + llvm::SMDiagnostic err; + llvm::ParseAssemblyString(stream.str().c_str(), gIR->module, err, gIR->context()); + std::string errstr = err.getMessage(); + if(errstr != "") + error(tinst->loc, + "can't parse inline LLVM IR:\n%s\n%s\n%s\nThe input string was: \n%s", + err.getLineContents().c_str(), + (std::string(err.getColumnNo(), ' ') + '^').c_str(), + errstr.c_str(), stream.str().c_str()); + + LLFunction* fun = gIR->module->getFunction(mangled_name); + fun->setLinkage(llvm::GlobalValue::LinkOnceODRLinkage); +#if LDC_LLVM_VER >= 302 + fun->addFnAttr(llvm::Attributes::AlwaysInline); +#else + fun->addFnAttr(AlwaysInline); +#endif + return fun; +} + +////////////////////////////////////////////////////////////////////////////////////////// + static llvm::FunctionType* DtoVaFunctionType(FuncDeclaration* fdecl) { TypeFunction* f = static_cast(fdecl->type); @@ -407,6 +484,15 @@ void DtoResolveFunction(FuncDeclaration* fdecl) fdecl->ir.defined = true; return; // this gets mapped to a special inline asm call, no point in going on. } + else if (tempdecl->llvmInternal == LLVMinline_ir) + { + fdecl->llvmInternal = LLVMinline_ir; + fdecl->linkage = LINKc; + fdecl->ir.defined = true; + Type* type = fdecl->type; + assert(type->ty == Tfunction); + static_cast(type)->linkage = LINKc; + } } DtoType(fdecl->type); @@ -488,8 +574,13 @@ static void set_param_attrs(TypeFunction* f, llvm::Function* func, FuncDeclarati bool found = false; for (size_t j = 0; j < newSize; ++j) { if (attrs[j].Index == curr.Index) { - // TODO: LLVM 3.2. +#if LDC_LLVM_VER >= 302 + attrs[j].Attrs = llvm::Attributes::get( + gIR->context(), + llvm::AttrBuilder(attrs[j].Attrs).addAttributes(curr.Attrs)); +#else attrs[j].Attrs |= curr.Attrs; +#endif found = true; break; } @@ -556,7 +647,10 @@ void DtoDeclareFunction(FuncDeclaration* fdecl) LLFunctionType* functype = DtoFunctionType(fdecl); LLFunction* func = vafunc ? vafunc : gIR->module->getFunction(mangled_name); if (!func) { - func = LLFunction::Create(functype, DtoLinkage(fdecl), mangled_name, gIR->module); + if(fdecl->llvmInternal == LLVMinline_ir) + func = DtoInlineIRFunction(fdecl); + else + func = LLFunction::Create(functype, DtoLinkage(fdecl), mangled_name, gIR->module); } else if (func->getFunctionType() != functype) { error(fdecl->loc, "Function type does not match previously declared function with the same mangled name: %s", fdecl->mangle()); } diff --git a/gen/pragma.cpp b/gen/pragma.cpp index 4118d4d9..3969f38a 100644 --- a/gen/pragma.cpp +++ b/gen/pragma.cpp @@ -257,6 +257,17 @@ Pragma DtoGetPragma(Scope *sc, PragmaDeclaration *decl, std::string &arg1str) return LLVMinline_asm; } + // pragma(llvm_inline_ir) { templdecl(s) } + else if (ident == Id::llvm_inline_ir) + { + if (args && args->dim > 0) + { + error("takes no parameters"); + fatal(); + } + return LLVMinline_ir; + } + return LLVMnone; } @@ -421,6 +432,49 @@ void DtoCheckPragma(PragmaDeclaration *decl, Dsymbol *s, } break; + case LLVMinline_ir: + if (TemplateDeclaration* td = s->isTemplateDeclaration()) + { + Dsymbol* member = td->onemember; + if (!member) + { + error("the '%s' pragma template must have exactly one member", ident->toChars()); + fatal(); + } + FuncDeclaration* fun = member->isFuncDeclaration(); + if (!fun) + { + error("the '%s' pragma template's member must be a function declaration", ident->toChars()); + fatal(); + } + + TemplateParameters& params = *td->parameters; + bool valid_params = + params.dim == 3 && params[1]->isTemplateTypeParameter() && + params[2]->isTemplateTupleParameter(); + + if(valid_params) + { + TemplateValueParameter* p0 = params[0]->isTemplateValueParameter(); + valid_params = valid_params && p0 && p0->valType == Type::tstring; + } + + if(!valid_params) + { + error("the '%s' pragma template must have exactly three parameters: a string, a type and a type tuple", + ident->toChars()); + fatal(); + } + + td->llvmInternal = llvm_internal; + } + else + { + error("the '%s' pragma is only allowed on template declarations", ident->toChars()); + fatal(); + } + break; + default: warning(Loc(), "the LDC specific pragma '%s' is not yet implemented, ignoring", ident->toChars()); } diff --git a/gen/pragma.h b/gen/pragma.h index 9895bc2d..fb28b9d9 100644 --- a/gen/pragma.h +++ b/gen/pragma.h @@ -22,6 +22,7 @@ enum Pragma LLVMva_end, LLVMva_arg, LLVMinline_asm, + LLVMinline_ir, LLVMfence, LLVMatomic_store, LLVMatomic_load,