mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-02-12 18:03:13 +01:00
Added initial support for raw LLVM inline asm.
This commit is contained in:
38
dmd/attrib.c
38
dmd/attrib.c
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -225,6 +225,7 @@ Msgtable msgtable[] =
|
||||
{ "vaarg", "va_arg" },
|
||||
{ "ldc" },
|
||||
{ "allow_inline" },
|
||||
{ "llvm_inline_asm" },
|
||||
|
||||
// For special functions
|
||||
{ "tohash", "toHash" },
|
||||
|
||||
@@ -9,5 +9,6 @@ enum
|
||||
LLVMva_copy,
|
||||
LLVMva_end,
|
||||
LLVMva_arg,
|
||||
LLVMldc
|
||||
LLVMldc,
|
||||
LLVMinline_asm
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
////////////////////////////////////////////
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
19
gen/toir.cpp
19
gen/toir.cpp
@@ -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);
|
||||
|
||||
|
||||
7
runtime/import/ldc/llvmasm.di
Normal file
7
runtime/import/ldc/llvmasm.di
Normal file
@@ -0,0 +1,7 @@
|
||||
module ldc.llvmasm;
|
||||
|
||||
pragma(llvm_inline_asm)
|
||||
template __asm()
|
||||
{
|
||||
void __asm(char[] asmcode, char[] constraints, ...);
|
||||
}
|
||||
Reference in New Issue
Block a user