Merge pull request #226 from jerro/pragma-llvm-inline-ir

Pragma llvm_inline_ir
This commit is contained in:
David Nadlinger
2012-11-15 12:05:17 -08:00
6 changed files with 154 additions and 3 deletions

View File

@@ -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})
#

View File

@@ -239,6 +239,7 @@ Msgtable msgtable[] =
{ "ldc" },
{ "allow_inline" },
{ "llvm_inline_asm" },
{ "llvm_inline_ir" },
{ "fence" },
{ "atomic_load" },
{ "atomic_store" },

View File

@@ -283,6 +283,7 @@ Msgtable msgtable[] =
{ "ldc" },
{ "allow_inline" },
{ "llvm_inline_asm" },
{ "llvm_inline_ir" },
{ "fence" },
{ "atomic_load" },
{ "atomic_store" },

View File

@@ -257,6 +257,83 @@ llvm::FunctionType* DtoFunctionType(Type* type, Type* thistype, Type* nesttype,
//////////////////////////////////////////////////////////////////////////////////////////
#include <llvm/Support/raw_ostream.h>
#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<char*>(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<TypeFunction*>(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<TypeFunction*>(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());
}

View File

@@ -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());
}

View File

@@ -22,6 +22,7 @@ enum Pragma
LLVMva_end,
LLVMva_arg,
LLVMinline_asm,
LLVMinline_ir,
LLVMfence,
LLVMatomic_store,
LLVMatomic_load,