emitCloneSmallArray :: CLabel -> CmmFormal -> CmmExpr -> CmmExpr -> WordOff
                    -> FCode ()
emitCloneSmallArray info_p res_r src src_off n = do
    dflags <- getDynFlags

    let info_ptr = mkLblExpr info_p
        rep = smallArrPtrsRep n

    tickyAllocPrim (mkIntExpr dflags (smallArrPtrsHdrSize dflags))
        (mkIntExpr dflags (nonHdrSize dflags rep))
        (zeroExpr dflags)

    let hdr_size = fixedHdrSize dflags

    base <- allocHeapClosure rep info_ptr curCCS
                     [ (mkIntExpr dflags n,
                        hdr_size + oFFSET_StgSmallMutArrPtrs_ptrs dflags)
                     ]

    arr <- CmmLocal `fmap` newTemp (bWord dflags)
    emit $ mkAssign arr base

    dst_p <- assignTempE $ cmmOffsetB dflags (CmmReg arr)
             (smallArrPtrsHdrSize dflags)
    src_p <- assignTempE $ cmmOffsetExprW dflags src
             (cmmAddWord dflags
              (mkIntExpr dflags (smallArrPtrsHdrSizeW dflags)) src_off)

    emitMemcpyCall dst_p src_p (mkIntExpr dflags (wordsToBytes dflags n))
        (wORD_SIZE dflags)

    emit $ mkAssign (CmmLocal res_r) (CmmReg arr)

-- | Takes and offset in the destination array, the base address of
-- the card table, and the number of elements affected (*not* the
-- number of cards). The number of elements may not be zero.
-- Marks the relevant cards as dirty.
emitCloneSmallArray :: CLabel -> CmmFormal -> CmmExpr -> CmmExpr -> WordOff
                    -> FCode ()
emitCloneSmallArray info_p res_r src src_off n = do
    dflags <- getDynFlags

    let info_ptr = mkLblExpr info_p
        rep = smallArrPtrsRep n

    tickyAllocPrim (mkIntExpr dflags (smallArrPtrsHdrSize dflags))
        (mkIntExpr dflags (nonHdrSize dflags rep))
        (zeroExpr dflags)

    let hdr_size = fixedHdrSize dflags

    base <- allocHeapClosure rep info_ptr curCCS
                     [ (mkIntExpr dflags n,
                        hdr_size + oFFSET_StgSmallMutArrPtrs_ptrs dflags)
                     ]

    arr <- CmmLocal `fmap` newTemp (bWord dflags)
    emit $ mkAssign arr base

    dst_p <- assignTempE $ cmmOffsetB dflags (CmmReg arr)
             (smallArrPtrsHdrSize dflags)
    src_p <- assignTempE $ cmmOffsetExprW dflags src
             (cmmAddWord dflags
              (mkIntExpr dflags (smallArrPtrsHdrSizeW dflags)) src_off)

    emitMemcpyCall dst_p src_p (mkIntExpr dflags (wordsToBytes dflags n))
        (wORD_SIZE dflags)

    emit $ mkAssign (CmmLocal res_r) (CmmReg arr)

-- | Takes and offset in the destination array, the base address of
-- the card table, and the number of elements affected (*not* the
-- number of cards). The number of elements may not be zero.
-- Marks the relevant cards as dirty.
emitCloneSmallArray info_p res_r src src_off n = do
    dflags <- getDynFlags

    let info_ptr = mkLblExpr info_p
        rep = smallArrPtrsRep n

    tickyAllocPrim (mkIntExpr dflags (smallArrPtrsHdrSize dflags))
        (mkIntExpr dflags (nonHdrSize dflags rep))
        (zeroExpr dflags)

    let hdr_size = fixedHdrSize dflags

    base <- allocHeapClosure rep info_ptr curCCS
                     [ (mkIntExpr dflags n,
                        hdr_size + oFFSET_StgSmallMutArrPtrs_ptrs dflags)
                     ]

    arr <- CmmLocal `fmap` newTemp (bWord dflags)
    emit $ mkAssign arr base

    dst_p <- assignTempE $ cmmOffsetB dflags (CmmReg arr)
             (smallArrPtrsHdrSize dflags)
    src_p <- assignTempE $ cmmOffsetExprW dflags src
             (cmmAddWord dflags
              (mkIntExpr dflags (smallArrPtrsHdrSizeW dflags)) src_off)

    emitMemcpyCall dst_p src_p (mkIntExpr dflags (wordsToBytes dflags n))
        (wORD_SIZE dflags)

    emit $ mkAssign (CmmLocal res_r) (CmmReg arr)

-- | Takes and offset in the destination array, the base address of
-- the card table, and the number of elements affected (*not* the
-- number of cards). The number of elements may not be zero.
-- Marks the relevant cards as dirty.