diff gen/asmstmt.cpp @ 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
line wrap: on
line diff
--- 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;
+}