changeset 527:cecfee2d01a8

Added support for overloaded intrinsics. Added atomic intrinsics in the intrinsics.di header.
author Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
date Wed, 20 Aug 2008 01:02:22 +0200
parents 642f6fa854e5
children 3197ffdc2811
files dmd/attrib.c dmd/template.c dmd/template.h gen/functions.cpp gen/llvmhelpers.cpp gen/llvmhelpers.h llvmdc-tango runtime/import/llvmdc/intrinsics.di tests/mini/atomic1.d
diffstat 9 files changed, 127 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/dmd/attrib.c	Tue Aug 19 20:18:01 2008 +0200
+++ b/dmd/attrib.c	Wed Aug 20 01:02:22 2008 +0200
@@ -838,7 +838,7 @@
         expr = expr->semantic(sc);
         if (!args || args->dim != 1 || !parseStringExp(expr, arg1str))
         {
-             error("pragma intrinsic requires exactly 1 string literal parameter");
+             error("requires exactly 1 string literal parameter");
              fatal();
         }
         llvm_internal = LLVMintrinsic;
@@ -849,7 +849,7 @@
     {
         if (args && args->dim > 0)
         {
-             error("pragma no_typeinfo takes no parameters");
+             error("takes no parameters");
              fatal();
         }
         llvm_internal = LLVMno_typeinfo;
@@ -860,7 +860,7 @@
     {
         if (args && args->dim > 0)
         {
-             error("pragma no_moduleinfo takes no parameters");
+             error("takes no parameters");
              fatal();
         }
         llvm_internal = LLVMno_moduleinfo;
@@ -871,7 +871,7 @@
     {
         if (args && args->dim > 0)
         {
-             error("pragma alloca takes no parameters");
+             error("takes no parameters");
              fatal();
         }
         llvm_internal = LLVMalloca;
@@ -882,7 +882,7 @@
     {
         if (args && args->dim > 0)
         {
-             error("pragma va_start takes no parameters");
+             error("takes no parameters");
              fatal();
         }
         llvm_internal = LLVMva_start;
@@ -893,7 +893,7 @@
     {
         if (args && args->dim > 0)
         {
-             error("pragma va_copy takes no parameters");
+             error("takes no parameters");
              fatal();
         }
         llvm_internal = LLVMva_copy;
@@ -904,7 +904,7 @@
     {
         if (args && args->dim > 0)
         {
-             error("pragma va_end takes no parameters");
+             error("takes no parameters");
              fatal();
         }
         llvm_internal = LLVMva_end;
@@ -915,7 +915,7 @@
     {
         if (args && args->dim > 0)
         {
-             error("pragma va_arg takes no parameters");
+             error("takes no parameters");
              fatal();
         }
         llvm_internal = LLVMva_arg;
@@ -928,7 +928,7 @@
         expr = expr->semantic(sc);
         if (!args || args->dim != 1 || !parseStringExp(expr, arg1str))
         {
-             error("pragma llvmdc requires exactly 1 string literal parameter");
+             error("requires exactly 1 string literal parameter");
              fatal();
         }
         else if (arg1str == "verbose")
@@ -937,7 +937,7 @@
         }
         else
         {
-            error("pragma llvmdc command '%s' invalid");
+            error("command '%s' invalid");
             fatal();
         }
     }
@@ -1000,9 +1000,14 @@
                 fd->llvmInternal = llvm_internal;
                 fd->intrinsicName = arg1str;
             }
+            else if (TemplateDeclaration* td = s->isTemplateDeclaration())
+            {
+                td->llvmInternal = llvm_internal;
+                td->intrinsicName = arg1str;
+            }
             else
             {
-                error("the intrinsic pragma is only allowed on function declarations");
+                error("only allowed on function declarations");
                 fatal();
             }
             break;
--- a/dmd/template.c	Tue Aug 19 20:18:01 2008 +0200
+++ b/dmd/template.c	Wed Aug 20 01:02:22 2008 +0200
@@ -303,6 +303,10 @@
     }
     d = Dsymbol::arraySyntaxCopy(members);
     td = new TemplateDeclaration(loc, ident, p, d);
+    
+    // LLVMDC
+    td->intrinsicName = intrinsicName;
+    
     return td;
 }
 
--- a/dmd/template.h	Tue Aug 19 20:18:01 2008 +0200
+++ b/dmd/template.h	Wed Aug 20 01:02:22 2008 +0200
@@ -15,6 +15,8 @@
 #pragma once
 #endif /* __DMC__ */
 
+#include <string>
+
 #include "root.h"
 #include "arraytypes.h"
 #include "dsymbol.h"
@@ -83,6 +85,9 @@
 
     TemplateTupleParameter *isVariadic();
     int isOverloadable();
+    
+    // LLVMDC
+    std::string intrinsicName;
 };
 
 struct TemplateParameter
--- a/gen/functions.cpp	Tue Aug 19 20:18:01 2008 +0200
+++ b/gen/functions.cpp	Wed Aug 20 01:02:22 2008 +0200
@@ -300,6 +300,12 @@
             Logger::println("magic va_start found");
             fdecl->llvmInternal = LLVMva_start;
         }
+        else if (tempdecl->llvmInternal == LLVMintrinsic)
+        {
+            Logger::println("overloaded intrinsic found");
+            fdecl->llvmInternal = LLVMintrinsic;
+            DtoOverloadedIntrinsicName(tinst, tempdecl, fdecl->intrinsicName);
+        }
     }
 
     DtoFunctionType(fdecl);
--- a/gen/llvmhelpers.cpp	Tue Aug 19 20:18:01 2008 +0200
+++ b/gen/llvmhelpers.cpp	Wed Aug 20 01:02:22 2008 +0200
@@ -1553,3 +1553,32 @@
     assert(0);
     return 0;
 }
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+void DtoOverloadedIntrinsicName(TemplateInstance* ti, TemplateDeclaration* td, std::string& name)
+{
+    Logger::println("DtoOverloadedIntrinsicName");
+    LOG_SCOPE;
+
+    Logger::println("template instance: %s", ti->toChars());
+    Logger::println("template declaration: %s", td->toChars());
+    Logger::println("intrinsic name: %s", td->intrinsicName.c_str());
+    
+    // for now use the size in bits of the first template param in the instance
+    assert(ti->tdtypes.dim == 1);
+    Type* T = (Type*)ti->tdtypes.data[0];
+
+    char tmp[10];
+    sprintf(tmp, "%d", T->size()*8);
+    
+    // replace # in name with bitsize
+    name = td->intrinsicName;
+
+    std::string needle("#");
+    size_t pos;
+    while(std::string::npos != (pos = name.find(needle)))
+        name.replace(pos, 1, tmp);
+    
+    Logger::println("final intrinsic name: %s", name.c_str());
+}
--- a/gen/llvmhelpers.h	Tue Aug 19 20:18:01 2008 +0200
+++ b/gen/llvmhelpers.h	Wed Aug 20 01:02:22 2008 +0200
@@ -110,6 +110,9 @@
 /// get the default initializer of the type
 LLConstant* DtoDefaultInit(Type* t);
 
+// fixup an overloaded intrinsic name string
+void DtoOverloadedIntrinsicName(TemplateInstance* ti, TemplateDeclaration* td, std::string& name);
+
 ////////////////////////////////////////////
 // gen/tocall.cpp stuff below
 ////////////////////////////////////////////
--- a/llvmdc-tango	Tue Aug 19 20:18:01 2008 +0200
+++ b/llvmdc-tango	Wed Aug 20 01:02:22 2008 +0200
@@ -42,7 +42,7 @@
 
 
 [link]
-#oneatatime=yes
+oneatatime=yes
 cmd=llvmdc $i -of$o
 
 libdir=-L-L=$i
@@ -52,7 +52,7 @@
 
 [liblink]
 safe=yes
-#oneatatime=yes
+oneatatime=yes
 cmd=llvm-ar rsc $o $i
 
 libdir=-L=$i
--- a/runtime/import/llvmdc/intrinsics.di	Tue Aug 19 20:18:01 2008 +0200
+++ b/runtime/import/llvmdc/intrinsics.di	Wed Aug 20 01:02:22 2008 +0200
@@ -245,16 +245,65 @@
     ulong llvm_part_select_i(ulong val, uint loBit, uint hiBit);
 
 
+// The 'llvm.part.set' family of intrinsic functions replaces a range of bits in an integer value with another integer value. It returns the integer with the replaced bits.
+
+// TODO
+// declare i17 @llvm.part.set.i17.i9 (i17 %val, i9 %repl, i32 %lo, i32 %hi)
+// declare i29 @llvm.part.set.i29.i9 (i29 %val, i9 %repl, i32 %lo, i32 %hi)
+
+
 
 
 //
 // ATOMIC OPERATIONS AND SYNCHRONIZATION INTRINSICS
 //
 
-// TODO
+// The llvm.memory.barrier intrinsic guarantees ordering between specific pairs of memory access types.
 
+pragma(intrinsic, "llvm.memory.barrier")
+    void llvm_memory_barrier(bool ll, bool ls, bool sl, bool ss, bool device);
 
+// This loads a value in memory and compares it to a given value. If they are equal, it stores a new value into the memory.
 
+pragma(intrinsic, "llvm.atomic.cmp.swap.i#.p0i#")
+    T llvm_atomic_cmp_swap(T)(T* ptr, T cmp, T val);
+
+// This intrinsic loads the value stored in memory at ptr and yields the value from memory. It then stores the value in val in the memory at ptr.
+
+pragma(intrinsic, "llvm.atomic.swap.i#.p0i#")
+    T llvm_atomic_swap(T)(T* ptr, T val);
+
+// This intrinsic adds delta to the value stored in memory at ptr. It yields the original value at ptr.
+
+pragma(intrinsic, "llvm.atomic.load.add.i#.p0i#")
+    T llvm_atomic_load_add(T)(T* ptr, T val);
+
+// This intrinsic subtracts delta to the value stored in memory at ptr. It yields the original value at ptr.
+
+pragma(intrinsic, "llvm.atomic.load.sub.i#.p0i#")
+    T llvm_atomic_load_sub(T)(T* ptr, T val);
+
+// These intrinsics bitwise the operation (and, nand, or, xor) delta to the value stored in memory at ptr. It yields the original value at ptr.
+
+pragma(intrinsic, "llvm.atomic.load.and.i#.p0i#")
+    T llvm_atomic_load_and(T)(T* ptr, T val);
+pragma(intrinsic, "llvm.atomic.load.nand.i#.p0i#")
+    T llvm_atomic_load_nand(T)(T* ptr, T val);
+pragma(intrinsic, "llvm.atomic.load.or.i#.p0i#")
+    T llvm_atomic_load_or(T)(T* ptr, T val);
+pragma(intrinsic, "llvm.atomic.load.xor.i#.p0i#")
+    T llvm_atomic_load_xor(T)(T* ptr, T val);
+
+// These intrinsics takes the signed or unsigned minimum or maximum of delta and the value stored in memory at ptr. It yields the original value at ptr. 
+
+pragma(intrinsic, "llvm.atomic.load.max.i#.p0i#")
+    T llvm_atomic_load_max(T)(T* ptr, T val);
+pragma(intrinsic, "llvm.atomic.load.min.i#.p0i#")
+    T llvm_atomic_load_min(T)(T* ptr, T val);
+pragma(intrinsic, "llvm.atomic.load.umax.i#.p0i#")
+    T llvm_atomic_load_umax(T)(T* ptr, T val);
+pragma(intrinsic, "llvm.atomic.load.umin.i#.p0i#")
+    T llvm_atomic_load_umin(T)(T* ptr, T val);
 
 //
 // GENERAL INTRINSICS
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/mini/atomic1.d	Wed Aug 20 01:02:22 2008 +0200
@@ -0,0 +1,12 @@
+module mini.atomic1;
+
+pragma(intrinsic, "llvm.atomic.swap.i#.p0i#")
+    T atomic_swap(T)(T* ptr, T val);
+
+void main()
+{
+    int i = 42;
+    int j = atomic_swap(&i, 43);
+    assert(j == 42);
+    assert(i == 43);
+}