changeset 232:092468448d25 trunk

[svn r248] Fixed: labels in inline asm block now work for the normal case. Fixed: inline asm blocks are now emitted as a single asm entity.
author lindquist
date Sun, 08 Jun 2008 06:15:51 +0200
parents 61aa721a6b7f
children 76ee1bbe487e
files dmd/parse.c dmd/statement.c dmd/statement.h gen/asmstmt.cpp gen/d-asm-i386.h gen/irstate.cpp gen/irstate.h gen/statements.cpp llvmdc.kdevelop.filelist
diffstat 9 files changed, 233 insertions(+), 83 deletions(-) [+]
line wrap: on
line diff
--- a/dmd/parse.c	Sun Jun 08 01:07:58 2008 +0200
+++ b/dmd/parse.c	Sun Jun 08 06:15:51 2008 +0200
@@ -3186,7 +3186,7 @@
 		}
 		break;
 	    }
-	    s = new CompoundStatement(loc, statements);
+        s = new AsmBlockStatement(loc, statements);
 	    nextToken();
 	    break;
 	}
--- a/dmd/statement.c	Sun Jun 08 01:07:58 2008 +0200
+++ b/dmd/statement.c	Sun Jun 08 06:15:51 2008 +0200
@@ -467,7 +467,7 @@
 	}
 	i++;
     }
-    if (statements->dim == 1)
+    if (statements->dim == 1 && !isAsmBlockStatement())
 	return s;
     return this;
 }
@@ -3593,9 +3593,7 @@
 	: Dsymbol(ident)
 {
     statement = NULL;
-#if IN_GCC
     asmLabelNum = 0;
-#endif
 }
 
 LabelDsymbol *LabelDsymbol::isLabel()		// is this a LabelDsymbol()?
--- a/dmd/statement.h	Sun Jun 08 01:07:58 2008 +0200
+++ b/dmd/statement.h	Sun Jun 08 06:15:51 2008 +0200
@@ -41,6 +41,7 @@
 struct Argument;
 struct StaticAssert;
 struct AsmStatement;
+struct AsmBlockStatement;
 struct GotoStatement;
 struct ScopeStatement;
 struct TryCatchStatement;
@@ -90,6 +91,7 @@
     virtual TryCatchStatement *isTryCatchStatement() { return NULL; }
     virtual GotoStatement *isGotoStatement() { return NULL; }
     virtual AsmStatement *isAsmStatement() { return NULL; }
+    virtual AsmBlockStatement *isAsmBlockStatement() { return NULL; }
 #ifdef _DH
     int incontract;
 #endif
@@ -754,7 +756,8 @@
     Statement *inlineScan(InlineScanState *iss);
 
     void toIR(IRState *irs);
-    
+
+    // LLVMDC
     llvm::BasicBlock* llvmBB;
 };
 
@@ -788,4 +791,13 @@
     void toIR(IRState *irs);
 };
 
+struct AsmBlockStatement : CompoundStatement
+{
+    AsmBlockStatement(Loc loc, Statements *s);
+    Statements *flatten(Scope *sc);
+    AsmBlockStatement *isAsmBlockStatement() { return this; }
+
+    void toIR(IRState *irs);
+};
+
 #endif /* DMD_STATEMENT_H */
--- a/gen/asmstmt.cpp	Sun Jun 08 01:07:58 2008 +0200
+++ b/gen/asmstmt.cpp	Sun Jun 08 06:15:51 2008 +0200
@@ -16,6 +16,7 @@
 #include <deque>
 #include <iostream>
 #include <sstream>
+#include <cstring>
 
 //#include "d-lang.h"
 //#include "d-codegen.h"
@@ -67,41 +68,6 @@
     }
 };
 
-llvm::InlineAsm*
-d_build_asm_stmt(std::string const& code,
-                 std::deque<LLValue*> const& output_values,
-                 std::deque<LLValue*> const& input_values,
-                 std::string const& constraints)
-{
-    std::vector<const LLType*> params;
-
-    // outputs
-    const LLType* ret = LLType::VoidTy;
-    if (!output_values.empty())
-    {
-        assert(output_values.size() == 1);
-        const LLType* llty = output_values[0]->getType();
-        std::cout << "out: " << *llty << '\n';
-        params.push_back(llty);
-    }
-
-    // inputs
-    if (!input_values.empty())
-    {
-        assert(input_values.size() == 1);
-        const LLType* llty = input_values[0]->getType();
-        std::cout << "in: " << *llty << '\n';
-        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) :
     Statement(loc)
 {
@@ -302,6 +268,7 @@
 std::cout << "asm fixme Arg_Pointer" << std::endl;
         if (arg->expr->op == TOKdsymbol)
         {
+            assert(0);
             DsymbolExp* dse = (DsymbolExp*)arg->expr;
             LabelDsymbol* lbl = dse->s->isLabel();
             assert(lbl);
@@ -439,7 +406,9 @@
     std::string insnt(code->insnTemplate, code->insnTemplateLen);
 
     // rewrite GCC-style constraints to LLVM-style constraints
-    std::string llvmConstraints;
+    std::string llvmOutConstraints;
+    std::string llvmInConstraints;
+    std::string llvmClobbers;
     int n = 0;
     typedef std::deque<std::string>::iterator it;
     for(it i = output_constraints.begin(), e = output_constraints.end(); i != e; ++i, ++n) {
@@ -454,41 +423,182 @@
             input_constraints.push_front(input_constraint);
             input_values.push_front(output_values[n]);
         }
-        llvmConstraints += *i;
-        llvmConstraints += ",";
+        llvmOutConstraints += *i;
+        llvmOutConstraints += ",";
     }
     for(it i = input_constraints.begin(), e = input_constraints.end(); i != e; ++i) {
-        llvmConstraints += *i;
-        llvmConstraints += ",";
+        llvmInConstraints += *i;
+        llvmInConstraints += ",";
     }
-    for(it i = clobbers.begin(), e = clobbers.end(); i != e; ++i) {
-        llvmConstraints += "~{" + *i + "},";
-    }
-    if(llvmConstraints.size() > 0)
-        llvmConstraints.resize(llvmConstraints.size()-1);
 
-std::cout << "Inline Asm code: " << std::endl;
-std::cout << insnt << std::endl;
-std::cout << "LLVM constraints: " << llvmConstraints << 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)
-    {
-        callargs.push_back(output_values[i]);
+    for(it i = clobbers.begin(), e = clobbers.end(); i != e; ++i) {
+        llvmClobbers += "~{" + *i + "},";
     }
 
-    cn = input_values.size();
-    for (size_t i=0; i<cn; ++i)
+    // excessive commas are removed later...
+
+    // push asm statement
+    IRAsmStmt* asmStmt = new IRAsmStmt;
+    asmStmt->code = insnt;
+    asmStmt->out_c = llvmOutConstraints;
+    asmStmt->in_c = llvmInConstraints;
+    asmStmt->clobbers = llvmClobbers;
+    asmStmt->out.insert(asmStmt->out.begin(), output_values.begin(), output_values.end());
+    asmStmt->in.insert(asmStmt->in.begin(), input_values.begin(), input_values.end());
+    irs->ASMs.push_back(asmStmt);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+AsmBlockStatement::AsmBlockStatement(Loc loc, Statements* s)
+:   CompoundStatement(loc, s)
+{
+}
+
+// rewrite argument indices to the block scope indices
+static void remap_outargs(std::string& insnt, size_t nargs, size_t& idx)
+{
+    static const std::string digits[10] =
     {
-        callargs.push_back(input_values[i]);
+        "0","1","2","3","4",
+        "5","6","7","8","9"
+    };
+    assert(nargs <= 10);
+
+    static const std::string prefix("<<<out");
+    static const std::string suffix(">>>");
+    std::string argnum;
+    std::string needle;
+    char buf[10];
+    for (unsigned i = 0; i < nargs; i++) {
+        needle = prefix + digits[i] + suffix;
+        sprintf(buf, "%u", idx++);
+        insnt.replace(insnt.find(needle), needle.size(), buf);
+    }
+}
+
+// rewrite argument indices to the block scope indices
+static void remap_inargs(std::string& insnt, size_t nargs, size_t& idx)
+{
+    static const std::string digits[10] =
+    {
+        "0","1","2","3","4",
+        "5","6","7","8","9"
+    };
+    assert(nargs <= 10);
+
+    static const std::string prefix("<<<in");
+    static const std::string suffix(">>>");
+    std::string argnum;
+    std::string needle;
+    char buf[10];
+    for (unsigned i = 0; i < nargs; i++) {
+        needle = prefix + digits[i] + suffix;
+        sprintf(buf, "%u", idx++);
+        insnt.replace(insnt.find(needle), needle.size(), buf);
+    }
+}
+
+void AsmBlockStatement::toIR(IRState* p)
+{
+    Logger::println("AsmBlockStatement::toIR(): %s", loc.toChars());
+    LOG_SCOPE;
+    Logger::println("BEGIN ASM");
+
+    assert(!p->inASM);
+    p->inASM = true;
+
+    // rest idx
+    size_t asmIdx = 0;
+    assert(p->ASMs.empty());
+
+    // do asm statements
+    for (int i=0; i<statements->dim; i++)
+    {
+        Statement* s = (Statement*)statements->data[i];
+        if (s) {
+            s->toIR(p);
+        }
     }
 
-    llvm::CallInst* call = irs->ir->CreateCall(t, callargs.begin(), callargs.end(), "");
+    // build asm block
+    std::vector<LLValue*> outargs;
+    std::vector<LLValue*> inargs;
+    std::vector<const LLType*> outtypes;
+    std::vector<const LLType*> intypes;
+    std::string out_c;
+    std::string in_c;
+    std::string clobbers;
+    std::string code;
+
+    size_t n = p->ASMs.size();
+    for (size_t i=0; i<n; ++i)
+    {
+        IRAsmStmt* a = p->ASMs[i];
+        assert(a);
+        size_t onn = a->out.size();
+        for (size_t j=0; j<onn; ++j)
+        {
+            outargs.push_back(a->out[j]);
+            outtypes.push_back(a->out[j]->getType());
+        }
+        if (!a->out_c.empty())
+        {
+            out_c += a->out_c;
+        }
+        if (!a->clobbers.empty())
+        {
+            clobbers += a->clobbers;
+        }
+        remap_outargs(a->code, onn, asmIdx);
+    }
+    for (size_t i=0; i<n; ++i)
+    {
+        IRAsmStmt* a = p->ASMs[i];
+        assert(a);
+        size_t inn = a->in.size();
+        for (size_t j=0; j<inn; ++j)
+        {
+            inargs.push_back(a->in[j]);
+            intypes.push_back(a->in[j]->getType());
+        }
+        if (!a->in_c.empty())
+        {
+            in_c += a->in_c;
+        }
+        remap_inargs(a->code, inn, asmIdx);
+        if (!code.empty())
+            code += " ; ";
+        code += a->code;
+    }
+    p->ASMs.clear();
+
+    out_c += in_c;
+    out_c += clobbers;
+    if (!out_c.empty())
+        out_c.resize(out_c.size()-1);
+
+    Logger::println("code = \"%s\"", code.c_str());
+    Logger::println("constraints = \"%s\"", out_c.c_str());
+
+    std::vector<const LLType*> types;
+    types.insert(types.end(), outtypes.begin(), outtypes.end());
+    types.insert(types.end(), intypes.begin(), intypes.end());
+    llvm::FunctionType* fty = llvm::FunctionType::get(llvm::Type::VoidTy, types, false);
+    Logger::cout() << "function type = " << *fty << '\n';
+    llvm::InlineAsm* ia = llvm::InlineAsm::get(fty, code, out_c, true);
+
+    std::vector<LLValue*> args;
+    args.insert(args.end(), outargs.begin(), outargs.end());
+    args.insert(args.end(), inargs.begin(), inargs.end());
+    llvm::CallInst* call = p->ir->CreateCall(ia, args.begin(), args.end(), "");
+
+    p->inASM = false;
+    Logger::println("END ASM");
 }
+
+// the whole idea of this statement is to avoid the flattening
+Statements* AsmBlockStatement::flatten(Scope* sc)
+{
+    return NULL;
+}
--- a/gen/d-asm-i386.h	Sun Jun 08 01:07:58 2008 +0200
+++ b/gen/d-asm-i386.h	Sun Jun 08 06:15:51 2008 +0200
@@ -1408,12 +1408,12 @@
 
     void addOperand(const char * fmt, AsmArgType type, Expression * e, AsmCode * asmcode, AsmArgMode mode = Mode_Input) {
 	insnTemplate->writestring((char*) fmt);
-	insnTemplate->printf("%d", asmcode->args.dim);
+	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("%d", asmcode->args.dim);
+    insnTemplate->printf("<<<%s%d>>>", (mode==Mode_Input)?"in":"out", asmcode->args.dim);
     insnTemplate->writestring((char*) fmtpost);
     asmcode->args.push( new AsmArg(type, e, mode) );
     }
@@ -1426,6 +1426,11 @@
     insnTemplate->writestring(buf);
     }
 
+    void addLabel(char* id) {
+    insnTemplate->writestring(".LDASM");
+    insnTemplate->writestring(id);
+    }
+
     /* Determines whether the operand is a register, memory reference
        or immediate.  Immediate addresses are currently classified as
        memory.  This function is called before the exact instructions
@@ -1887,7 +1892,7 @@
 			    addOperand(fmt, Arg_Memory, e, asmcode, mode);
 			    
 			} else {
-			    addOperand("$a", Arg_FrameRelative, e, asmcode);
+			    addOperand2("${",":a}", Arg_FrameRelative, e, asmcode);
 			}
 			if (opInfo->operands[i] & Opr_Dest)
 			    asmcode->clobbersMemory = 1;
@@ -1905,14 +1910,12 @@
 			    addLabel(lbl_num);
 			    asmcode->dollarLabel = lbl_num; // could make the dollar label part of the same asm..
 			} else if (e->op == TOKdsymbol) {
-// 			    LabelDsymbol * lbl = (LabelDsymbol *) ((DsymbolExp *) e)->s;
-// 			    if (! lbl->asmLabelNum)
-// 				lbl->asmLabelNum = ++d_priv_asm_label_serial;
-// 			    
-// 			    use_star = false;
-// 			    addLabel(lbl->asmLabelNum);
-                use_star = false;
-                addOperand("$", Arg_Pointer, e, asmcode);
+			    LabelDsymbol * lbl = (LabelDsymbol *) ((DsymbolExp *) e)->s;
+			    if (! lbl->asmLabelNum)
+				lbl->asmLabelNum = ++d_priv_asm_label_serial;
+
+			    use_star = false;
+			    addLabel(lbl->ident->toChars());
 			} else if ((decl && decl->isCodeseg())) { // if function or label
 			    use_star = false;
 			    addOperand2("${", ":c}", Arg_Pointer, e, asmcode);
@@ -1921,9 +1924,9 @@
 				insnTemplate->writebyte('*');
 				use_star = false;
 			    }
+                Type* tt = e->type->pointerTo();
 			    e = new AddrExp(0, e);
-			    assert(decl);
-			    e->type = decl->type->pointerTo();
+			    e->type = tt;
 
 			    addOperand(fmt, Arg_Memory, e, asmcode, mode);
 			}
@@ -1934,7 +1937,7 @@
 		if (operand->constDisplacement) {
 		    if (operand->symbolDisplacement.dim)
 			insnTemplate->writebyte('+');
-		    addOperand("$a", Arg_Integer, newIntExp(operand->constDisplacement), asmcode);
+		    addOperand2("${",":a}", Arg_Integer, newIntExp(operand->constDisplacement), asmcode);
 		    if (opInfo->operands[i] & Opr_Dest)
 			asmcode->clobbersMemory = 1;
 		}
--- a/gen/irstate.cpp	Sun Jun 08 01:07:58 2008 +0200
+++ b/gen/irstate.cpp	Sun Jun 08 06:15:51 2008 +0200
@@ -53,6 +53,7 @@
     emitMain = false;
     mainFunc = 0;
     ir.state = this;
+    inASM = false;
 }
 
 IrFunction* IRState::func()
--- a/gen/irstate.h	Sun Jun 08 01:07:58 2008 +0200
+++ b/gen/irstate.h	Sun Jun 08 06:15:51 2008 +0200
@@ -65,6 +65,16 @@
     IRExp(Expression* l, Expression* r, DValue* val);
 };
 
+struct IRAsmStmt
+{
+    std::string code;
+    std::string out_c;
+    std::string in_c;
+    std::string clobbers;
+    std::vector<LLValue*> out;
+    std::vector<LLValue*> in;
+};
+
 // represents the module
 struct IRState
 {
@@ -140,6 +150,10 @@
     FuncDeclVector ctors;
     FuncDeclVector dtors;
     FuncDeclVector unitTests;
+
+    // for inline asm
+    std::vector<IRAsmStmt*> ASMs;
+    bool inASM;
 };
 
 #endif // LLVMDC_GEN_IRSTATE_H
--- a/gen/statements.cpp	Sun Jun 08 01:07:58 2008 +0200
+++ b/gen/statements.cpp	Sun Jun 08 06:15:51 2008 +0200
@@ -992,6 +992,17 @@
     Logger::println("LabelStatement::toIR(): %s", loc.toChars());
     LOG_SCOPE;
 
+    // if it's an inline asm label, we don't create a basicblock, just emit it in the asm
+    if (p->inASM)
+    {
+        IRAsmStmt* a = new IRAsmStmt;
+        a->code = ".LDASM";
+        a->code += ident->toChars();
+        a->code += ":";
+        p->ASMs.push_back(a);
+        return;
+    }
+
     assert(tf == NULL);
 
     llvm::BasicBlock* oldend = gIR->scopeend();
--- a/llvmdc.kdevelop.filelist	Sun Jun 08 01:07:58 2008 +0200
+++ b/llvmdc.kdevelop.filelist	Sun Jun 08 06:15:51 2008 +0200
@@ -754,6 +754,7 @@
 tangotests/asm2.d
 tangotests/asm3.d
 tangotests/asm4.d
+tangotests/asm5.d
 tangotests/b.d
 tangotests/byval1.d
 tangotests/c.d