Mercurial > projects > ldc
changeset 1152:521dd1626d76
Added initial support for raw LLVM inline asm.
author | Tomas Lindquist Olsen <tomas.l.olsen gmail.com> |
---|---|
date | Sat, 28 Mar 2009 06:32:06 +0100 |
parents | 3cf0066e6faf |
children | 4454126b4345 |
files | dmd/attrib.c dmd/expression.h dmd/idgen.c gen/enums.h gen/functions.cpp gen/llvmhelpers.h gen/naked.cpp gen/toir.cpp runtime/import/ldc/llvmasm.di |
diffstat | 9 files changed, 163 insertions(+), 6 deletions(-) [+] |
line wrap: on
line diff
--- a/dmd/attrib.c Sat Mar 28 05:00:43 2009 +0100 +++ b/dmd/attrib.c Sat Mar 28 06:32:06 2009 +0100 @@ -987,6 +987,17 @@ } } + // 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 @@ } 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()); }
--- a/dmd/expression.h Sat Mar 28 05:00:43 2009 +0100 +++ b/dmd/expression.h Sat Mar 28 06:32:06 2009 +0100 @@ -1863,12 +1863,8 @@ 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
--- a/dmd/idgen.c Sat Mar 28 05:00:43 2009 +0100 +++ b/dmd/idgen.c Sat Mar 28 06:32:06 2009 +0100 @@ -225,6 +225,7 @@ { "vaarg", "va_arg" }, { "ldc" }, { "allow_inline" }, + { "llvm_inline_asm" }, // For special functions { "tohash", "toHash" },
--- a/gen/enums.h Sat Mar 28 05:00:43 2009 +0100 +++ b/gen/enums.h Sat Mar 28 06:32:06 2009 +0100 @@ -9,5 +9,6 @@ LLVMva_copy, LLVMva_end, LLVMva_arg, - LLVMldc + LLVMldc, + LLVMinline_asm };
--- a/gen/functions.cpp Sat Mar 28 05:00:43 2009 +0100 +++ b/gen/functions.cpp Sat Mar 28 06:32:06 2009 +0100 @@ -332,6 +332,22 @@ 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);
--- a/gen/llvmhelpers.h Sat Mar 28 05:00:43 2009 +0100 +++ b/gen/llvmhelpers.h Sat Mar 28 06:32:06 2009 +0100 @@ -136,6 +136,9 @@ /// 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 ////////////////////////////////////////////
--- a/gen/naked.cpp Sat Mar 28 05:00:43 2009 +0100 +++ b/gen/naked.cpp Sat Mar 28 06:32:06 2009 +0100 @@ -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 @@ // 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; +} + + + + + + + + + + +
--- a/gen/toir.cpp Sat Mar 28 05:00:43 2009 +0100 +++ b/gen/toir.cpp Sat Mar 28 06:32:06 2009 +0100 @@ -196,7 +196,11 @@ { 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 @@ 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);