Added initial support for raw LLVM inline asm.

This commit is contained in:
Tomas Lindquist Olsen
2009-03-28 06:32:06 +01:00
parent 36f6ebc77f
commit 99b863e2b1
9 changed files with 163 additions and 6 deletions

View File

@@ -987,6 +987,17 @@ void PragmaDeclaration::semantic(Scope *sc)
}
}
// pragma(llvm_inline_asm) { templdecl(s) }
else if (ident == Id::llvm_inline_asm)
{
if (args && args->dim > 0)
{
error("takes no parameters");
fatal();
}
llvm_internal = LLVMinline_asm;
}
#endif // LDC
else if (ignoreUnsupportedPragmas)
@@ -1116,6 +1127,33 @@ void PragmaDeclaration::semantic(Scope *sc)
}
break;
case LLVMinline_asm:
if (TemplateDeclaration* td = s->isTemplateDeclaration())
{
if (td->parameters->dim != 0)
{
error("the '%s' pragma template must have exactly zero template parameters", ident->toChars());
fatal();
}
else if (!td->onemember)
{
error("the '%s' pragma template must have exactly one member", ident->toChars());
fatal();
}
else if (td->overnext || td->overroot)
{
error("the '%s' pragma template must not be overloaded", ident->toChars());
fatal();
}
td->llvmInternal = llvm_internal;
}
else
{
error("the '%s' pragma is only allowed on template declarations", ident->toChars());
fatal();
}
break;
default:
warning("the LDC specific pragma '%s' is not yet implemented, ignoring", ident->toChars());
}

View File

@@ -1863,12 +1863,8 @@ struct GEPExp : UnaExp
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
Expression *toLvalue(Scope *sc, Expression *e);
#if IN_DMD
elem *toElem(IRState *irs);
#elif IN_LLVM
DValue* toElem(IRState* irs);
llvm::Constant *toConstElem(IRState *irs);
#endif
};
#endif

View File

@@ -225,6 +225,7 @@ Msgtable msgtable[] =
{ "vaarg", "va_arg" },
{ "ldc" },
{ "allow_inline" },
{ "llvm_inline_asm" },
// For special functions
{ "tohash", "toHash" },

View File

@@ -9,5 +9,6 @@ enum
LLVMva_copy,
LLVMva_end,
LLVMva_arg,
LLVMldc
LLVMldc,
LLVMinline_asm
};

View File

@@ -332,6 +332,22 @@ void DtoResolveFunction(FuncDeclaration* fdecl)
fdecl->linkage = LINKintrinsic;
((TypeFunction*)fdecl->type)->linkage = LINKintrinsic;
}
else if (tempdecl->llvmInternal == LLVMinline_asm)
{
Logger::println("magic inline asm found");
TypeFunction* tf = (TypeFunction*)fdecl->type;
if (tf->varargs != 1 || (fdecl->parameters && fdecl->parameters->dim != 0))
{
error("invalid __asm declaration, must be a D style variadic with no explicit parameters");
fatal();
}
fdecl->llvmInternal = LLVMinline_asm;
fdecl->ir.resolved = true;
fdecl->ir.declared = true;
fdecl->ir.initialized = true;
fdecl->ir.defined = true;
return; // this gets mapped to a special inline asm call, no point in going on.
}
}
DtoFunctionType(fdecl);

View File

@@ -136,6 +136,9 @@ bool needsTemplateLinkage(Dsymbol* s);
/// Returns true if there is any unaligned type inside the aggregate.
bool hasUnalignedFields(Type* t);
///
DValue* DtoInlineAsmExpr(Loc loc, FuncDeclaration* fd, Expressions* arguments);
////////////////////////////////////////////
// gen/tocall.cpp stuff below
////////////////////////////////////////////

View File

@@ -1,8 +1,10 @@
#include "gen/llvm.h"
#include "llvm/InlineAsm.h"
#include "expression.h"
#include "statement.h"
#include "declaration.h"
#include "template.h"
#include <cassert>
@@ -10,6 +12,7 @@
#include "gen/irstate.h"
#include "gen/llvmhelpers.h"
#include "gen/tollvm.h"
#include "gen/dvalue.h"
//////////////////////////////////////////////////////////////////////////////////////////
@@ -320,3 +323,78 @@ void emitABIReturnAsmStmt(IRAsmBlock* asmblock, Loc loc, FuncDeclaration* fdecl)
// return values always go in the front
asmblock->s.push_front(as);
}
//////////////////////////////////////////////////////////////////////////////////////////
// sort of kinda related to naked ...
DValue * DtoInlineAsmExpr(Loc loc, FuncDeclaration * fd, Expressions * arguments)
{
Logger::println("DtoInlineAsmExpr @ %s", loc.toChars());
LOG_SCOPE;
TemplateInstance* ti = fd->toParent()->isTemplateInstance();
assert(ti && "invalid inline __asm expr");
assert(arguments->dim >= 2 && "invalid __asm call");
// get code param
Expression* e = (Expression*)arguments->data[0];
Logger::println("code exp: %s", e->toChars());
StringExp* se = (StringExp*)e;
if (e->op != TOKstring || se->sz != 1)
{
e->error("__asm code argument is not a char[] string literal");
fatal();
}
std::string code((char*)se->string, se->len);
// get constraints param
e = (Expression*)arguments->data[1];
Logger::println("constraint exp: %s", e->toChars());
se = (StringExp*)e;
if (e->op != TOKstring || se->sz != 1)
{
e->error("__asm constraints argument is not a char[] string literal");
fatal();
}
std::string constraints((char*)se->string, se->len);
// build runtime arguments
size_t n = arguments->dim;
LLSmallVector<llvm::Value*, 8> args;
args.reserve(n-2);
std::vector<const llvm::Type*> argtypes;
argtypes.reserve(n-2);
for (size_t i = 2; i < n; i++)
{
e = (Expression*)arguments->data[i];
args.push_back(e->toElem(gIR)->getRVal());
argtypes.push_back(args.back()->getType());
}
// build asm function type
llvm::FunctionType* FT = llvm::FunctionType::get(llvm::Type::VoidTy, argtypes, false);
// build asm call
bool sideeffect = true;
llvm::InlineAsm* ia = llvm::InlineAsm::get(FT, code, constraints, sideeffect);
llvm::Value* v = gIR->ir->CreateCall(ia, args.begin(), args.end(), "");
// return NULL for now
return NULL;
}

View File

@@ -196,7 +196,11 @@ DValue* VarExp::toElem(IRState* p)
{
Logger::println("FuncDeclaration");
LLValue* func = 0;
if (fdecl->llvmInternal != LLVMva_arg) {
if (fdecl->llvmInternal == LLVMinline_asm) {
error("special ldc inline asm is not a normal function");
fatal();
}
else if (fdecl->llvmInternal != LLVMva_arg) {
fdecl->codegen(Type::sir);
func = fdecl->ir.irFunc->func;
}
@@ -723,6 +727,19 @@ DValue* CallExp::toElem(IRState* p)
Logger::print("CallExp::toElem: %s @ %s\n", toChars(), type->toChars());
LOG_SCOPE;
// handle magic inline asm
if (e1->op == TOKvar)
{
VarExp* ve = (VarExp*)e1;
if (FuncDeclaration* fd = ve->var->isFuncDeclaration())
{
if (fd->llvmInternal == LLVMinline_asm)
{
return DtoInlineAsmExpr(loc, fd, arguments);
}
}
}
// get the callee value
DValue* fnval = e1->toElem(p);

View File

@@ -0,0 +1,7 @@
module ldc.llvmasm;
pragma(llvm_inline_asm)
template __asm()
{
void __asm(char[] asmcode, char[] constraints, ...);
}