Add array copy/clone primops
authorDaniel Peebles <pumpkingod@gmail.com>
Tue, 12 Apr 2011 11:35:59 +0000 (13:35 +0200)
committerSimon Marlow <marlowsd@gmail.com>
Thu, 19 May 2011 13:04:26 +0000 (14:04 +0100)
compiler/prelude/primops.txt.pp
includes/Cmm.h
includes/stg/MiscClosures.h
rts/Linker.c
rts/PrimOps.cmm

index 49f7a97..bf9d477 100644 (file)
@@ -626,6 +626,55 @@ primop  UnsafeThawArrayOp  "unsafeThawArray#" GenPrimOp
    out_of_line = True
    has_side_effects = True
 
+primop  CopyArrayOp "copyArray#" GenPrimOp
+  Array# a -> Int# -> MutableArray# s a -> Int# -> Int# -> State# s -> State# s
+  {Copy a range of the Array# to the specified region in the MutableArray#.
+   Both arrays must fully contain the specified ranges, but this is not checked.
+   The two arrays must not be the same array in different states, but this is not checked either.}
+  with
+  out_of_line = True
+  has_side_effects = True
+
+primop  CopyMutableArrayOp "copyMutableArray#" GenPrimOp
+  MutableArray# s a -> Int# -> MutableArray# s a -> Int# -> Int# -> State# s -> State# s
+  {Copy a range of the first MutableArray# to the specified region in the second MutableArray#.
+   Both arrays must fully contain the specified ranges, but this is not checked.}
+  with
+  out_of_line = True
+  has_side_effects = True
+
+primop  CloneArrayOp "cloneArray#" GenPrimOp
+  Array# a -> Int# -> Int# -> Array# a
+  {Return a newly allocated Array# with the specified subrange of the provided Array#. 
+   The provided Array# should contain the full subrange specified by the two Int#s, but this is not checked.}
+  with
+  out_of_line = True
+  has_side_effects = True
+
+primop  CloneMutableArrayOp "cloneMutableArray#" GenPrimOp
+  MutableArray# s a -> Int# -> Int# -> State# s -> (# State# s, MutableArray# s a #)
+  {Return a newly allocated Array# with the specified subrange of the provided Array#.
+   The provided MutableArray# should contain the full subrange specified by the two Int#s, but this is not checked.}
+  with
+  out_of_line = True
+  has_side_effects = True
+
+primop  FreezeArrayOp "freezeArray#" GenPrimOp
+  MutableArray# s a -> Int# -> Int# -> State# s -> (# State# s, Array# a #)
+  {Return a newly allocated Array# with the specified subrange of the provided MutableArray#.
+   The provided MutableArray# should contain the full subrange specified by the two Int#s, but this is not checked.}
+  with
+  out_of_line = True
+  has_side_effects = True
+
+primop  ThawArrayOp "thawArray#" GenPrimOp
+  Array# a -> Int# -> Int# -> State# s -> (# State# s, MutableArray# s a #)
+  {Return a newly allocated Array# with the specified subrange of the provided MutableArray#.
+   The provided Array# should contain the full subrange specified by the two Int#s, but this is not checked.}
+  with
+  out_of_line = True
+  has_side_effects = True
+
 ------------------------------------------------------------------------
 section "Byte Arrays"
        {Operations on {\tt ByteArray\#}. A {\tt ByteArray\#} is a just a region of
index 0ba14fb..641faa2 100644 (file)
 #define StgFunInfoExtra_bitmap(i)     StgFunInfoExtraFwd_bitmap(i)
 #endif
 
-#define mutArrPtrsCardWords(n) \
-    ROUNDUP_BYTES_TO_WDS(((n) + (1 << MUT_ARR_PTRS_CARD_BITS) - 1) >> MUT_ARR_PTRS_CARD_BITS)
+#define mutArrCardMask ((1 << MUT_ARR_PTRS_CARD_BITS) - 1)
+#define mutArrPtrCardDown(i) ((i) >> MUT_ARR_PTRS_CARD_BITS)
+#define mutArrPtrCardUp(i)   (((i) + mutArrCardMask) >> MUT_ARR_PTRS_CARD_BITS)
+#define mutArrPtrsCardWords(n) ROUNDUP_BYTES_TO_WDS(mutArrPtrCardUp(n))
 
 #if defined(PROFILING) || (!defined(THREADED_RTS) && defined(DEBUG))
 #define OVERWRITING_CLOSURE(c) foreign "C" overwritingClosure(c "ptr")
index ed0bf65..3851f08 100644 (file)
@@ -380,6 +380,12 @@ RTS_FUN_DECL(stg_newByteArrayzh);
 RTS_FUN_DECL(stg_newPinnedByteArrayzh);
 RTS_FUN_DECL(stg_newAlignedPinnedByteArrayzh);
 RTS_FUN_DECL(stg_newArrayzh);
+RTS_FUN_DECL(stg_copyArrayzh);
+RTS_FUN_DECL(stg_copyMutableArrayzh);
+RTS_FUN_DECL(stg_cloneArrayzh);
+RTS_FUN_DECL(stg_cloneMutableArrayzh);
+RTS_FUN_DECL(stg_freezzeArrayzh);
+RTS_FUN_DECL(stg_thawArrayzh);
 
 RTS_FUN_DECL(stg_newMutVarzh);
 RTS_FUN_DECL(stg_atomicModifyMutVarzh);
index 28ba9a0..6b52be6 100644 (file)
@@ -826,6 +826,12 @@ typedef struct _RtsSymbolVal {
       SymI_HasProto(stg_myThreadIdzh)                   \
       SymI_HasProto(stg_labelThreadzh)                  \
       SymI_HasProto(stg_newArrayzh)                     \
+      SymI_HasProto(stg_copyArrayzh)                    \
+      SymI_HasProto(stg_copyMutableArrayzh)             \
+      SymI_HasProto(stg_cloneArrayzh)                   \
+      SymI_HasProto(stg_cloneMutableArrayzh)            \
+      SymI_HasProto(stg_freezzeArrayzh)                 \
+      SymI_HasProto(stg_thawArrayzh)                    \
       SymI_HasProto(stg_newBCOzh)                       \
       SymI_HasProto(stg_newByteArrayzh)                 \
       SymI_HasProto_redirect(newCAF, newDynCAF)         \
index 5c9cfb7..791ee96 100644 (file)
@@ -212,6 +212,112 @@ stg_unsafeThawArrayzh
   }
 }
 
+#define COPY_CARDS(src_start, src_cards_start, dst_start, dst_cards_start, n, copy) \
+  if (src_start & mutArrCardMask == dst_start & mutArrCardMask) { \
+    foreign "C" copy(dst_cards_start + mutArrPtrCardUp(dst_start), src_cards_start + mutArrPtrCardUp(src_start), mutArrPtrCardDown(n)); \
+    \
+    I8[dst_cards_start + mutArrPtrCardDown(dst_start)] = I8[dst_cards_start + mutArrPtrCardDown(dst_start)]     | I8[src_cards_start + mutArrPtrCardDown(src_start)]; \
+    I8[dst_cards_start + mutArrPtrCardUp(n)]           = I8[dst_cards_start + mutArrPtrCardUp(dst_start + n)] | I8[src_cards_start + mutArrPtrCardUp(src_start + n)]; \
+  } else { \
+    foreign "C" memset(dst_cards_start "ptr", 1, mutArrPtrCardDown(n)); \
+  }
+
+stg_copyArrayzh
+{
+  W_ bytes, n, src, dst, src_start, dst_start, src_start_ptr, dst_start_ptr;
+  W_ src_cards_start, dst_cards_start;
+
+  src = R1;
+  src_start = R2;
+  dst = R3;
+  dst_start = R4;
+  n = R5;
+  MAYBE_GC(R1_PTR & R3_PTR, stg_copyArrayzh);
+
+  bytes = WDS(n);
+
+  src_start_ptr = src + SIZEOF_StgMutArrPtrs + WDS(src_start);
+  dst_start_ptr = dst + SIZEOF_StgMutArrPtrs + WDS(dst_start);
+
+  // Copy data (we assume the arrays aren't overlapping since they're of different types)
+  foreign "C" memcpy(dst_start_ptr "ptr", src_start_ptr "ptr", bytes);
+
+  // The base address of both source and destination card tables
+  src_cards_start = src + SIZEOF_StgMutArrPtrs + WDS(StgMutArrPtrs_ptrs(src));
+  dst_cards_start = dst + SIZEOF_StgMutArrPtrs + WDS(StgMutArrPtrs_ptrs(dst));
+
+  COPY_CARDS(src_start, src_cards_start, dst_start, dst_cards_start, n, memcpy);
+
+  jump %ENTRY_CODE(Sp(0));
+}
+
+stg_copyMutableArrayzh
+{
+  W_ bytes, n, src, dst, src_start, dst_start, src_start_ptr, dst_start_ptr;
+  W_ src_cards_start, dst_cards_start;
+
+  src = R1;
+  src_start = R2;
+  dst = R3;
+  dst_start = R4;
+  n = R5;
+  MAYBE_GC(R1_PTR & R3_PTR, stg_copyMutableArrayzh);
+
+  bytes = WDS(n);
+
+  src_start_ptr = src + SIZEOF_StgMutArrPtrs + WDS(src_start);
+  dst_start_ptr = dst + SIZEOF_StgMutArrPtrs + WDS(dst_start);
+
+  src_cards_start = src + SIZEOF_StgMutArrPtrs + WDS(StgMutArrPtrs_ptrs(src));
+  dst_cards_start = dst + SIZEOF_StgMutArrPtrs + WDS(StgMutArrPtrs_ptrs(dst));
+
+  // The only time the memory might overlap is when the two arrays we were provided are the same array!
+  if (src == dst) {
+    foreign "C" memmove(dst_start_ptr "ptr", src_start_ptr "ptr", bytes);
+    COPY_CARDS(src_start, src_cards_start, dst_start, dst_cards_start, n, memmove);
+  } else {
+    foreign "C" memcpy(dst_start_ptr "ptr", src_start_ptr "ptr", bytes);
+    COPY_CARDS(src_start, src_cards_start, dst_start, dst_cards_start, n, memcpy);
+  }
+
+  jump %ENTRY_CODE(Sp(0));
+}
+
+#define ARRAY_CLONE(name, type) \
+  name \
+  { \
+    W_ src, src_off, words, n, init, arr, src_p, dst_p, size; \
+    \
+    src = R1; \
+    src_off = R2; \
+    n = R3; \
+    \
+    MAYBE_GC(R1_PTR, name); \
+    \
+    size = n + mutArrPtrsCardWords(n); \
+    words = BYTES_TO_WDS(SIZEOF_StgMutArrPtrs) + size; \
+    ("ptr" arr) = foreign "C" allocate(MyCapability() "ptr", words) [R2]; \
+    TICK_ALLOC_PRIM(SIZEOF_StgMutArrPtrs, WDS(n), 0); \
+    \
+    SET_HDR(arr, type, W_[CCCS]); \
+    StgMutArrPtrs_ptrs(arr) = n; \
+    StgMutArrPtrs_size(arr) = size; \
+    \
+    dst_p = arr + SIZEOF_StgMutArrPtrs; \
+    src_p = src + SIZEOF_StgMutArrPtrs + WDS(src_off); \
+    \
+    foreign "C" memcpy(dst_p "ptr", src_p "ptr", WDS(n)); \
+    \
+    foreign "C" memset(dst_p + WDS(n), 0, WDS(mutArrPtrsCardWords(n))); \
+    RET_P(arr); \
+  }
+
+ARRAY_CLONE(stg_cloneArrayzh, stg_MUT_ARR_PTRS_FROZEN0_info)
+ARRAY_CLONE(stg_cloneMutableArrayzh, stg_MUT_ARR_PTRS_DIRTY_info)
+ARRAY_CLONE(stg_freezzeArrayzh, stg_MUT_ARR_PTRS_FROZEN0_info)
+ARRAY_CLONE(stg_thawArrayzh, stg_MUT_ARR_PTRS_DIRTY_info)
+
+
 /* -----------------------------------------------------------------------------
    MutVar primitives
    -------------------------------------------------------------------------- */