mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-02-02 04:53:19 +01:00
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:
@@ -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})
|
||||
|
||||
#
|
||||
|
||||
@@ -239,6 +239,7 @@ Msgtable msgtable[] =
|
||||
{ "ldc" },
|
||||
{ "allow_inline" },
|
||||
{ "llvm_inline_asm" },
|
||||
{ "llvm_inline_ir" },
|
||||
{ "fence" },
|
||||
{ "atomic_load" },
|
||||
{ "atomic_store" },
|
||||
|
||||
@@ -283,6 +283,7 @@ Msgtable msgtable[] =
|
||||
{ "ldc" },
|
||||
{ "allow_inline" },
|
||||
{ "llvm_inline_asm" },
|
||||
{ "llvm_inline_ir" },
|
||||
{ "fence" },
|
||||
{ "atomic_load" },
|
||||
{ "atomic_store" },
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ enum Pragma
|
||||
LLVMva_end,
|
||||
LLVMva_arg,
|
||||
LLVMinline_asm,
|
||||
LLVMinline_ir,
|
||||
LLVMfence,
|
||||
LLVMatomic_store,
|
||||
LLVMatomic_load,
|
||||
|
||||
Reference in New Issue
Block a user