changeset 1001:7a0238db1962

Implement support for intrinsics returning struct types (such as llvm.*.with.overflow)
author Frits van Bommel <fvbommel wxs.nl>
date Thu, 26 Feb 2009 22:47:06 +0100
parents d6895f24dc8f
children c749648ed2b8
files gen/functions.cpp gen/tocall.cpp runtime/import/ldc/intrinsics.di
diffstat 3 files changed, 77 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/gen/functions.cpp	Thu Feb 26 18:43:25 2009 +0100
+++ b/gen/functions.cpp	Thu Feb 26 22:47:06 2009 +0100
@@ -70,23 +70,33 @@
     else
     {
         assert(rt);
-        if (gABI->returnInArg(rt))
+        if (f->linkage == LINKintrinsic)
         {
-            rettype = getPtrToType(DtoType(rt));
-            actualRettype = LLType::VoidTy;
-            f->retInPtr = retinptr = true;
+            // Intrinsics don't care about ABI
+            Logger::cout() << "Intrinsic returning " << rt->toChars() << '\n';
+            actualRettype = rettype = DtoType(rt);
+            Logger::cout() << "  (LLVM type: " << *rettype << ")\n";
         }
         else
         {
-            rettype = DtoType(rt);
-            // do abi specific transformations
-            actualRettype = gABI->getRetType(f, rettype);
-        }
+            if (gABI->returnInArg(rt))
+            {
+                rettype = getPtrToType(DtoType(rt));
+                actualRettype = LLType::VoidTy;
+                f->retInPtr = retinptr = true;
+            }
+            else
+            {
+                rettype = DtoType(rt);
+                // do abi specific transformations
+                actualRettype = gABI->getRetType(f, rettype);
+            }
 
-        // FIXME: should probably be part of the abi
-        if (unsigned ea = DtoShouldExtend(rt))
-        {
-            f->retAttrs |= ea;
+            // FIXME: should probably be part of the abi
+            if (unsigned ea = DtoShouldExtend(rt))
+            {
+                f->retAttrs |= ea;
+            }
         }
     }
 
--- a/gen/tocall.cpp	Thu Feb 26 18:43:25 2009 +0100
+++ b/gen/tocall.cpp	Thu Feb 26 22:47:06 2009 +0100
@@ -464,8 +464,22 @@
     // get return value
     LLValue* retllval = (retinptr) ? args[0] : call->get();
 
-    // do abi specific return value fixups
-    retllval = gABI->getRet(tf, retllval);
+    if (tf->linkage == LINKintrinsic)
+    {
+        // Ignore ABI for intrinsics
+        Type* rettype = tf->next;
+        if (rettype->ty == Tstruct) {
+            // LDC assumes structs are in memory, so put it there.
+            LLValue* mem = DtoAlloca(retllval->getType());
+            DtoStore(retllval, mem);
+            retllval = mem;
+        }
+    }
+    else
+    {
+        // do abi specific return value fixups
+        retllval = gABI->getRet(tf, retllval);
+    }
 
     // repaint the type if necessary
     if (resulttype)
--- a/runtime/import/ldc/intrinsics.di	Thu Feb 26 18:43:25 2009 +0100
+++ b/runtime/import/ldc/intrinsics.di	Thu Feb 26 22:47:06 2009 +0100
@@ -332,6 +332,45 @@
 pragma(intrinsic, "llvm.atomic.load.umin.i#.p0i#")
     T llvm_atomic_load_umin(T)(T* ptr, T val);
 
+
+//
+// ARITHMETIC-WITH-OVERFLOW INTRINSICS
+//
+
+struct OverflowRet(T) {
+    static assert(is(T : int), T.stringof ~ " is not an integer type!");
+    T result;
+    bool overflow;
+}
+
+// Signed and unsigned addition
+pragma(intrinsic, "llvm.sadd.with.overflow.i#")
+    OverflowRet!(T) llvm_sadd_with_overflow(T)(T lhs, T rhs);
+
+pragma(intrinsic, "llvm.uadd.with.overflow.i#")
+    OverflowRet!(T) llvm_uadd_with_overflow(T)(T lhs, T rhs);
+
+// Signed and unsigned subtraction
+pragma(intrinsic, "llvm.ssub.with.overflow.i#")
+    OverflowRet!(T) llvm_ssub_with_overflow(T)(T lhs, T rhs);
+
+pragma(intrinsic, "llvm.usub.with.overflow.i#")
+    OverflowRet!(T) llvm_usub_with_overflow(T)(T lhs, T rhs);
+
+// Signed and unsigned multiplication
+pragma(intrinsic, "llvm.smul.with.overflow.i#")
+    OverflowRet!(T) llvm_smul_with_overflow(T)(T lhs, T rhs);
+
+/* Note: LLVM documentations says:
+ *  Warning: 'llvm.umul.with.overflow' is badly broken.
+ *  It is actively being fixed, but it should not currently be used!
+ *
+ * See: http://llvm.org/docs/LangRef.html#int_umul_overflow
+ */
+pragma(intrinsic, "llvm.umul.with.overflow.i#")
+    OverflowRet!(T) llvm_umul_with_overflow(T)(T lhs, T rhs);
+
+
 //
 // GENERAL INTRINSICS
 //