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);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/runtime/import/ldc/llvmasm.di	Sat Mar 28 06:32:06 2009 +0100
@@ -0,0 +1,7 @@
+module ldc.llvmasm;
+
+pragma(llvm_inline_asm)
+template __asm()
+{
+    void __asm(char[] asmcode, char[] constraints, ...);
+}