changeset 220:ccc2e6898a78 trunk

[svn r236] added initial codegen of inline asm, pretty buggy and incomplete still. see the tangotests/asm1.d test for a sample of what does work!
author lindquist
date Fri, 06 Jun 2008 20:14:51 +0200
parents 761c8352f494
children 68687d8c3e9a
files dmd/mars.c dmd/mars.h gen/asmstmt.cpp gen/d-asm-i386.h llvmdc.kdevelop.filelist tangotests/asm1.d
diffstat 6 files changed, 129 insertions(+), 33 deletions(-) [+]
line wrap: on
line diff
--- a/dmd/mars.c	Thu Jun 05 19:22:37 2008 +0200
+++ b/dmd/mars.c	Fri Jun 06 20:14:51 2008 +0200
@@ -215,7 +215,10 @@
   -version=level compile in version code >= level\n\
   -version=ident compile in version code identified by ident\n\
   -w             enable warnings\n\
-  -fp80          enable 80bit reals on x86 32bit (EXPERIMENTAL)\n\
+\n\
+Experimental features:\n\
+  -inlineasm     allow use of inline asm\n\
+  -fp80          enable 80bit reals on x86 32bit\n\
 ",
 #if WIN32
 "  @cmdfile       read arguments from cmdfile\n"
@@ -320,8 +323,6 @@
 #endif /* linux */
 
     //VersionCondition::addPredefinedGlobalIdent("D_Bits");
-    VersionCondition::addPredefinedGlobalIdent("D_InlineAsm");
-    VersionCondition::addPredefinedGlobalIdent("D_InlineAsm_X86");
     VersionCondition::addPredefinedGlobalIdent("all");
 
 #if _WIN32
@@ -401,6 +402,8 @@
             global.params.llvmAnnotate = 1;
         else if (strcmp(p + 1, "fp80") == 0)
             global.params.useFP80 = 1;
+        else if (strcmp(p + 1, "inlineasm") == 0)
+            global.params.useInlineAsm = 1;
 	    else if (p[1] == 'o')
 	    {
 		switch (p[2])
@@ -752,13 +755,18 @@
         VersionCondition::addPredefinedGlobalIdent("LLVM64");
     }
 
+    if (!is_x86 && (global.params.useFP80 || global.params.useInlineAsm)) {
+        error("the -fp80 option is only valid for the x86 32bit architecture");
+        fatal();
+    }
+
     if (global.params.useFP80) {
-        if (!is_x86) {
-            error("the -fp80 option is only valid for the x86 32bit architecture");
-            fatal();
-        }
         VersionCondition::addPredefinedGlobalIdent("LLVM_X86_FP80");
     }
+    if (global.params.useInlineAsm) {
+        VersionCondition::addPredefinedGlobalIdent("D_InlineAsm");
+        VersionCondition::addPredefinedGlobalIdent("D_InlineAsm_X86");
+    }
 
     assert(tt_arch != 0);
     assert(tt_os != 0);
--- a/dmd/mars.h	Thu Jun 05 19:22:37 2008 +0200
+++ b/dmd/mars.h	Fri Jun 06 20:14:51 2008 +0200
@@ -134,6 +134,7 @@
     char llvmAnnotate;
     char *runtimePath;
     char useFP80;
+    char useInlineAsm;
     char fqnPaths; // use fully qualified object names
 };
 
--- a/gen/asmstmt.cpp	Thu Jun 05 19:22:37 2008 +0200
+++ b/gen/asmstmt.cpp	Fri Jun 06 20:14:51 2008 +0200
@@ -2,6 +2,9 @@
 //
 // Taken from an earlier version of DMD -- why is it missing from 0.79?
 
+#include "gen/llvm.h"
+#include "llvm/InlineAsm.h"
+
 //#include "d-gcc-includes.h"
 //#include "total.h"
 #include "dmd/statement.h"
@@ -9,8 +12,6 @@
 #include "dmd/declaration.h"
 #include "dmd/dsymbol.h"
 
-#include "llvm/InlineAsm.h"
-
 #include <cassert>
 #include <deque>
 #include <iostream>
@@ -19,6 +20,11 @@
 //#include "d-lang.h"
 //#include "d-codegen.h"
 
+#include "gen/irstate.h"
+#include "gen/dvalue.h"
+#include "gen/tollvm.h"
+#include "gen/logger.h"
+
 typedef enum {
     Arg_Integer,
     Arg_Pointer,
@@ -64,8 +70,33 @@
 llvm::InlineAsm*
 d_build_asm_stmt(std::string code, std::deque<DValue*> const& output_values, std::deque<DValue*> const& input_values, std::string constraints)
 {
-    //FIXME: Return InlineAsm::get(..) here.
-    return NULL;
+    std::vector<const LLType*> params;
+
+    // outputs
+    const LLType* ret = LLType::VoidTy;
+    if (!output_values.empty())
+    {
+        std::cout << "memory outputs" << std::endl;
+        assert(output_values.size() == 1);
+        const LLType* llty = DtoType(output_values[0]->getType());
+        params.push_back(llty);
+    }
+
+    // inputs
+    if (!input_values.empty())
+    {
+        std::cout << "inputs" << std::endl;
+        assert(input_values.size() == 1);
+        const LLType* llty = DtoType(input_values[0]->getType());
+        params.push_back(llty);
+    }
+
+    llvm::FunctionType* asmfnty = llvm::FunctionType::get(ret, params, false);
+
+std::cout << "function type: " << std::endl;
+std::cout << *asmfnty << std::endl;
+
+    return llvm::InlineAsm::get(asmfnty, code, constraints, true);
 }
 
 AsmStatement::AsmStatement(Loc loc, Token *tokens) :
@@ -214,6 +245,9 @@
 void
 AsmStatement::toIR(IRState * irs)
 {
+    Logger::println("AsmStatement::toIR(): %s", loc.toChars());
+    LOG_SCOPE;
+
 // FIXME
 //    gen.doLineNote( loc );
 
@@ -248,9 +282,11 @@
 	AsmArg * arg = (AsmArg *) code->args.data[i];
 	
 	bool is_input = true;
-	DValue* arg_val;
+	DValue* arg_val = 0;
 	std::string cns;
-	
+
+std::cout << std::endl;
+
 	switch (arg->type) {
 	case Arg_Integer:
 	    arg_val = arg->expr->toElem(irs);
@@ -259,23 +295,24 @@
 	    break;
 	case Arg_Pointer:
 // FIXME
-/*	    if (arg->expr->op == TOKvar)
-		arg_val = ((VarExp *) arg->expr)->var->toSymbol()->Stree;
-	    else if (arg->expr->op == TOKdsymbol) {
-		arg_val = irs->getLabelTree( (LabelDsymbol *) ((DsymbolExp *) arg->expr)->s );
-	    } else
-		assert(0);
-	    arg_val = irs->addressOf(arg_val);*/
+std::cout << "asm fixme Arg_Pointer" << std::endl;
+        if (arg->expr->op == TOKvar)
+        arg_val = arg->expr->toElem(irs);
+        else if (arg->expr->op == TOKdsymbol)
+        arg_val = arg->expr->toElem(irs);
+        else
+        assert(0);
+
 	    cns = p_cns;
 	    break;
 	case Arg_Memory:
 // FIXME
-/*	    if (arg->expr->op == TOKvar)
-		arg_val = ((VarExp *) arg->expr)->var->toSymbol()->Stree;
-	    else
-		arg_val = arg->expr->toElem(irs);
-	    if (DECL_P( arg_val ))
-		TREE_ADDRESSABLE( arg_val ) = 1;*/
+std::cout << "asm fixme Arg_Memory" << std::endl;
+        if (arg->expr->op == TOKvar)
+        arg_val = arg->expr->toElem(irs);
+        else
+        arg_val = arg->expr->toElem(irs);
+
 	    switch (arg->mode) {
 	    case Mode_Input:  cns = m_cns; break;
 	    case Mode_Output: cns = mw_cns;  is_input = false; break;
@@ -285,6 +322,7 @@
 	    break;
 	case Arg_FrameRelative:
 // FIXME
+std::cout << "asm fixme Arg_FrameRelative" << std::endl;
 /*	    if (arg->expr->op == TOKvar)
 		arg_val = ((VarExp *) arg->expr)->var->toSymbol()->Stree;
 	    else
@@ -301,6 +339,7 @@
 	    break;
 	case Arg_LocalSize:
 // FIXME
+std::cout << "asm fixme Arg_LocalSize" << std::endl;
 /*	    var_frame_offset = cfun->x_frame_offset;
 	    if (var_frame_offset < 0)
 		var_frame_offset = - var_frame_offset;
@@ -372,7 +411,7 @@
 	++p;
     }
 
-    //printf("final: %.*s\n", code->insnTemplateLen, code->insnTemplate);
+    printf("final: %.*s\n", code->insnTemplateLen, code->insnTemplate);
 
     std::string insnt(code->insnTemplate, code->insnTemplateLen);
 
@@ -407,12 +446,37 @@
 std::cout << "Inline Asm code: " << std::endl;
 std::cout << insnt << std::endl;
 std::cout << "LLVM constraints: " << llvmConstraints << std::endl;
-std::cout << std::endl;
 
     llvm::InlineAsm* t = d_build_asm_stmt(insnt, output_values, input_values, llvmConstraints);
+
+std::cout << "llvm::InlineAsm: " << std::endl;
+std::cout << *t << std::endl;
+
+    LLSmallVector<LLValue*, 2> callargs;
+
+    size_t cn = output_values.size();
+    for (size_t i=0; i<cn; ++i)
+    {
+        LLValue* val = output_values[i]->getLVal();
+        callargs.push_back(val);
+    }
+
+    cn = input_values.size();
+    for (size_t i=0; i<cn; ++i)
+    {
+        // FIXME: these should not be allowed to intermix with asm calls. they should somehow
+        // be outputted before any asm from a block, or the asm's should be moved after ...
+        LLValue* val = input_values[i]->getRVal();
+        callargs.push_back(val);
+    }
+
+    llvm::CallInst* call = irs->ir->CreateCall(t, callargs.begin(), callargs.end(), "");
+
+/*
 // FIXME
     //ASM_VOLATILE_P( t ) = 1;
     //irs->addExp( t );
     if (code->dollarLabel)
-	d_expand_priv_asm_label(irs, code->dollarLabel);
+    d_expand_priv_asm_label(irs, code->dollarLabel);
+*/
 }
--- a/gen/d-asm-i386.h	Thu Jun 05 19:22:37 2008 +0200
+++ b/gen/d-asm-i386.h	Fri Jun 06 20:14:51 2008 +0200
@@ -1730,7 +1730,7 @@
 	    stmt->regs |= (1 << Reg_EAX)|
 		(1 << Reg_ECX)|(1 << Reg_EDX);
 
-	insnTemplate->writebyte('\t');
+	insnTemplate->writebyte(' ');
 	for (int i__ = 0; i__ < nOperands; i__++) {
 	    int i;
 	    if (i__ != 0)
@@ -1857,7 +1857,7 @@
 
 			    e = new AddrExp(0, e);
 			    e->type = decl->type->pointerTo();
-
+#if !IN_LLVM
 			    /* DMD uses the same frame offsets for naked functions. */
 			    if (sc->func->naked)
 				operand->constDisplacement += 4;
@@ -1870,7 +1870,7 @@
 			    }
 			    e = new PtrExp(0, e);
 			    e->type = decl->type;
-			    
+#endif
 			    operand->constDisplacement = 0;
 			    operand->baseReg = Reg_Invalid;
 
@@ -2542,7 +2542,7 @@
 	machine_mode mode;
 
 	insnTemplate->writestring((char*) directives[op - Op_db]);
-	insnTemplate->writebyte('\t');
+	insnTemplate->writebyte(' ');
 
 	do {
 	    // DMD is pretty strict here, not even constant expressions are allowed..
--- a/llvmdc.kdevelop.filelist	Thu Jun 05 19:22:37 2008 +0200
+++ b/llvmdc.kdevelop.filelist	Fri Jun 06 20:14:51 2008 +0200
@@ -750,6 +750,8 @@
 tangotests/aa2.d
 tangotests/align1.d
 tangotests/arrays1.d
+tangotests/asm1.d
+tangotests/asm2.d
 tangotests/b.d
 tangotests/byval1.d
 tangotests/c.d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tangotests/asm1.d	Fri Jun 06 20:14:51 2008 +0200
@@ -0,0 +1,21 @@
+module tangotests.asm1;
+
+extern(C) int printf(char*, ...);
+
+int main()
+{
+    int i = 12;
+    int* ip = &i;
+    printf("%d\n", i);
+    asm
+    {
+        mov EBX, ip;
+        mov EAX, [EBX];
+        add EAX, 8;
+        mul EAX, EAX;
+        mov [EBX], EAX;
+    }
+    printf("%d\n", i);
+    assert(i == 400);
+    return 0;
+}