diff gen/abi.cpp @ 989:420ef073448d

Forgot new files that were supposed to be in last commit.
author Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
date Thu, 26 Feb 2009 14:13:27 +0100
parents
children 223a679053dd
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen/abi.cpp	Thu Feb 26 14:13:27 2009 +0100
@@ -0,0 +1,225 @@
+#include "gen/llvm.h"
+
+#include "mars.h"
+
+#include "gen/irstate.h"
+#include "gen/llvmhelpers.h"
+#include "gen/tollvm.h"
+#include "gen/abi.h"
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+/////////////////////        baseclass            ////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+// FIXME: Would be nice to come up a better and faster way to do this, right
+// now I'm more worried about actually making this abstraction work at all ...
+// It's definitely way overkill with the amount of return value rewrites we
+// have right now, but I expect this to change with proper x86-64 abi support
+
+TargetABI::TargetABI()
+{
+}
+
+llvm::Value* TargetABI::getRet(TypeFunction* tf, llvm::Value* io)
+{
+    if (ABIRetRewrite* r = findRetRewrite(tf))
+    {
+        return r->get(io);
+    }
+    return io;
+}
+
+llvm::Value* TargetABI::putRet(TypeFunction* tf, llvm::Value* io)
+{
+    if (ABIRetRewrite* r = findRetRewrite(tf))
+    {
+        return r->put(io);
+    }
+    return io;
+}
+
+const llvm::Type* TargetABI::getRetType(TypeFunction* tf, const llvm::Type* t)
+{
+    if (ABIRetRewrite* r = findRetRewrite(tf))
+    {
+        return r->type(t);
+    }
+    return t;
+}
+
+ABIRetRewrite * TargetABI::findRetRewrite(TypeFunction * tf)
+{
+    size_t n = retOps.size();
+    if (n)
+    for (size_t i = 0; i < n; i++)
+    {
+        if (retOps[i]->test(tf))
+            return retOps[i];
+    }
+    return NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+/////////////////////              X86            ////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+// simply swap of real/imag parts for proper x87 complex abi
+struct X87_complex_swap : ABIRetRewrite
+{
+    LLValue* get(LLValue* v)
+    {
+        return DtoAggrPairSwap(v);
+    }
+    LLValue* put(LLValue* v)
+    {
+        return DtoAggrPairSwap(v);
+    }
+    const LLType* type(const LLType* t)
+    {
+        return t;
+    }
+    bool test(TypeFunction* tf)
+    {
+        return (tf->next->toBasetype()->iscomplex());
+    }
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+struct X86TargetABI : TargetABI
+{
+    X86TargetABI()
+    {
+        retOps.push_back(new X87_complex_swap);
+    }
+
+    bool returnInArg(Type* t)
+    {
+        Type* rt = t->toBasetype();
+        return (rt->ty == Tstruct);
+    }
+
+    bool passByRef(Type* t)
+    {
+        t = t->toBasetype();
+        return (t->ty == Tstruct || t->ty == Tsarray);
+    }
+};
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+///////////////////            X86-64               //////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+struct X86_64_cfloat_rewrite : ABIRetRewrite
+{
+    // {double} -> {float,float}
+    LLValue* get(LLValue* in)
+    {
+        // extract double
+        LLValue* v = gIR->ir->CreateExtractValue(in, 0);
+        // cast to i64
+        v = gIR->ir->CreateBitCast(v, LLType::Int64Ty);
+
+        // extract real part
+        LLValue* rpart = gIR->ir->CreateTrunc(v, LLType::Int32Ty);
+        rpart = gIR->ir->CreateBitCast(rpart, LLType::FloatTy, ".re");
+
+        // extract imag part
+        LLValue* ipart = gIR->ir->CreateLShr(v, LLConstantInt::get(LLType::Int64Ty, 32, false));
+        ipart = gIR->ir->CreateTrunc(ipart, LLType::Int32Ty);
+        ipart = gIR->ir->CreateBitCast(ipart, LLType::FloatTy, ".im");
+
+        // return {float,float} aggr pair with same bits
+        return DtoAggrPair(rpart, ipart, ".final_cfloat");
+    }
+
+    // {float,float} -> {double}
+    LLValue* put(LLValue* v)
+    {
+        // extract real
+        LLValue* r = gIR->ir->CreateExtractValue(v, 0);
+        // cast to i32
+        r = gIR->ir->CreateBitCast(r, LLType::Int32Ty);
+        // zext to i64
+        r = gIR->ir->CreateZExt(r, LLType::Int64Ty);
+
+        // extract imag
+        LLValue* i = gIR->ir->CreateExtractValue(v, 1);
+        // cast to i32
+        i = gIR->ir->CreateBitCast(i, LLType::Int32Ty);
+        // zext to i64
+        i = gIR->ir->CreateZExt(i, LLType::Int64Ty);
+        // shift up
+        i = gIR->ir->CreateShl(i, LLConstantInt::get(LLType::Int64Ty, 32, false));
+
+        // combine
+        v = gIR->ir->CreateOr(r, i);
+
+        // cast to double
+        v = gIR->ir->CreateBitCast(v, LLType::DoubleTy);
+
+        // return {double}
+        const LLType* t = LLStructType::get(LLType::DoubleTy, 0);
+        LLValue* undef = llvm::UndefValue::get(t);
+        return gIR->ir->CreateInsertValue(undef, v, 0);
+    }
+
+    // {float,float} -> {double}
+    const LLType* type(const LLType* t)
+    {
+        return LLStructType::get(LLType::DoubleTy, 0);
+    }
+
+    // test if rewrite applies to function
+    bool test(TypeFunction* tf)
+    {
+        return (tf->next->toBasetype() == Type::tcomplex32);
+    }
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+struct X86_64TargetABI : TargetABI
+{
+    X86_64TargetABI()
+    {
+        retOps.push_back(new X86_64_cfloat_rewrite);
+    }
+
+    bool returnInArg(Type* t)
+    {
+        Type* rt = t->toBasetype();
+        return (rt->ty == Tstruct);
+    }
+
+    bool passByRef(Type* t)
+    {
+        t = t->toBasetype();
+        return (t->ty == Tstruct || t->ty == Tsarray);
+    }
+};
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+TargetABI * TargetABI::getTarget()
+{
+    switch(global.params.cpu)
+    {
+    case ARCHx86:
+        return new X86TargetABI;
+    case ARCHx86_64:
+        return new X86_64TargetABI;
+    default:
+        return NULL;
+    }
+}