diff gen/asm-x86-64.h @ 920:545f54041d91

Implemented proper support for naked asm using llvm module level asm. Still not 100% complete, but already 1000 times better that what we had before. Don's BignumX86 implementation from Tango (when turned into a standalone unittest) seems to fully work with no changes, and great performance :) Fixed align N; in asm blocks. Fixed inreg parameter passing on x86 for ref/out params. Removed support for lazy initialization of function local static variables, I have no idea why I ever implemented this, it's not in the D spec, and DMD doesn't support it :P Some of the global variable related changes might cause minor regressions, but they should be easily fixable.
author Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
date Tue, 03 Feb 2009 08:54:57 +0100
parents e70a0e7e2260
children 0ea8bdfe4405
line wrap: on
line diff
--- a/gen/asm-x86-64.h	Mon Feb 02 02:35:44 2009 +0100
+++ b/gen/asm-x86-64.h	Tue Feb 03 08:54:57 2009 +0100
@@ -1529,21 +1529,66 @@
     }
 
     void addOperand(const char * fmt, AsmArgType type, Expression * e, AsmCode * asmcode, AsmArgMode mode = Mode_Input) {
-	insnTemplate->writestring((char*) fmt);
-	insnTemplate->printf("<<%s%d>>", (mode==Mode_Input)?"in":"out", asmcode->args.dim);
-	asmcode->args.push( new AsmArg(type, e, mode) );
+        if (sc->func->naked)
+        {
+            switch(type)
+            {
+            case Arg_Integer:
+                if (e->type->isunsigned())
+                    insnTemplate->printf("$%llu", e->toUInteger());
+                else
+                    insnTemplate->printf("$%lld", e->toInteger());
+                break;
+
+            case Arg_Pointer:
+                stmt->error("unsupported pointer reference to '%s' in naked asm", e->toChars());
+                break;
+
+            case Arg_Memory:
+                if (e->op == TOKvar)
+                {
+                    VarExp* v = (VarExp*)e;
+                    if (VarDeclaration* vd = v->var->isVarDeclaration())
+                    {
+                        if (!vd->isDataseg())
+                        {
+                            stmt->error("only global variables can be referenced by identifier in naked asm");
+                            break;
+                        }
+
+                        // print out the mangle
+                        insnTemplate->writestring(vd->mangle());
+                        vd->nakedUse = true;
+                        break;
+                    }
+                }
+                stmt->error("unsupported memory reference to '%s' in naked asm", e->toChars());
+                break;
+
+            default:
+                assert(0 && "asm unsupported arg");
+                break;
+            }
+        }
+        else
+        {
+            insnTemplate->writestring((char*) fmt);
+            insnTemplate->printf("<<%s%d>>", (mode==Mode_Input)?"in":"out", asmcode->args.dim);
+            asmcode->args.push( new AsmArg(type, e, mode) );
+        }
     }
     void addOperand2(const char * fmtpre, const char * fmtpost, AsmArgType type, Expression * e, AsmCode * asmcode, AsmArgMode mode = Mode_Input) {
-    insnTemplate->writestring((char*) fmtpre);
-    insnTemplate->printf("<<%s%d>>", (mode==Mode_Input)?"in":"out", asmcode->args.dim);
-    insnTemplate->writestring((char*) fmtpost);
-    asmcode->args.push( new AsmArg(type, e, mode) );
+        assert(!sc->func->naked);
+        insnTemplate->writestring((char*) fmtpre);
+        insnTemplate->printf("<<%s%d>>", (mode==Mode_Input)?"in":"out", asmcode->args.dim);
+        insnTemplate->writestring((char*) fmtpost);
+        asmcode->args.push( new AsmArg(type, e, mode) );
     }
 
     void addLabel(char* id) {
-    insnTemplate->writestring(sc->func->mangle());
-    insnTemplate->writestring("_");
-    insnTemplate->writestring(id);
+        insnTemplate->writestring(sc->func->mangle());
+        insnTemplate->writestring("_");
+        insnTemplate->writestring(id);
     }
 
     /* Determines whether the operand is a register, memory reference
@@ -2037,9 +2082,12 @@
 				insnTemplate->writebyte('*');
 				use_star = false;
 			    }
+
+                if (!sc->func->naked) { // no addrexp in naked asm please :)
                 Type* tt = e->type->pointerTo();
 			    e = new AddrExp(0, e);
 			    e->type = tt;
+                }
 
 			    addOperand(fmt, Arg_Memory, e, asmcode, mode);
 			}
@@ -2636,9 +2684,9 @@
 	// parse primary: DMD allows 'MyAlign' (const int) but not '2+2'
 	// GAS is padding with NOPs last time I checked.
 	Expression * e = parseAsmExp()->optimize(WANTvalue | WANTinterpret);
-	integer_t align = e->toInteger();
+	uinteger_t align = e->toUInteger();
 
-	if (align & align - 1 == 0) {
+	if ((align & (align - 1)) == 0) {
 	    //FIXME: This printf is not portable. The use of `align` varies from system to system; 
 	    // on i386 using a.out, .align `n` will align on a 2^`n` boundary instead of an `n` boundary
 #ifdef HAVE_GAS_BALIGN_AND_P2ALIGN 
@@ -2647,7 +2695,7 @@
 	    insnTemplate->printf(".align\t%u", (unsigned) align);
 #endif
 	} else {
-	    stmt->error("alignment must be a power of 2");
+	    stmt->error("alignment must be a power of 2, not %u", (unsigned) align);
 	}
 
 	setAsmCode();