Pragma llvm_inline_ir

Adding pragma llvm_inline_ir.

Improved the error messages.

Append "ret void" when the return type is void

Improved the error message

in case when the string passed as llvm inline ir isn't valid llvm
assembly language.

LLVM 3.2 fix.

Add attribute AlwaysInline inside DtoInlineIRFunction.

Always generate a body for llvm_inline_ir

Also, always make llvm_inline_ir functions linkonce_odr. Because
the body is always generated when a module uses a llvm_inline_ir
function, the fact that the linker removes the function shouldn't
cause problems.
This commit is contained in:
Jernej Krempuš
2012-10-22 02:25:56 +02:00
parent 7708d2e27a
commit 7bbe782615
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,