| | 1507 | -- Unroll memcpy calls if the source and destination pointers are at |
| | 1508 | -- least DWORD aligned and the number of bytes to copy isn't too |
| | 1509 | -- large. Otherwise, call C's memcpy. |
| | 1510 | genCCall (CmmPrim MO_Memcpy) _ args@[CmmHinted dst _, CmmHinted src _, |
| | 1511 | CmmHinted (CmmLit (CmmInt n _)) _, |
| | 1512 | CmmHinted (CmmLit (CmmInt align _)) _] |
| | 1513 | | n <= maxInlineSizeThreshold && align .&. 3 == 0 = do |
| | 1514 | code_dst <- getAnyReg dst |
| | 1515 | dst_r <- getNewRegNat size |
| | 1516 | code_src <- getAnyReg src |
| | 1517 | src_r <- getNewRegNat size |
| | 1518 | tmp_r <- getNewRegNat size |
| | 1519 | return $ code_dst dst_r `appOL` code_src src_r `appOL` |
| | 1520 | go dst_r src_r tmp_r n |
| | 1521 | where |
| | 1522 | size = if align .&. 4 /= 0 then II32 else archWordSize |
| | 1523 | |
| | 1524 | sizeBytes = fromIntegral (sizeInBytes size) |
| | 1525 | |
| | 1526 | go :: Reg -> Reg -> Reg -> Integer -> OrdList Instr |
| | 1527 | go dst src tmp i |
| | 1528 | | i >= sizeBytes = |
| | 1529 | unitOL (MOV size (OpAddr src_addr) (OpReg tmp)) `appOL` |
| | 1530 | unitOL (MOV size (OpReg tmp) (OpAddr dst_addr)) `appOL` |
| | 1531 | go dst src tmp (i - sizeBytes) |
| | 1532 | -- Deal with remaining bytes. |
| | 1533 | | i >= 4 = -- Will never happen on 32-bit |
| | 1534 | unitOL (MOV II32 (OpAddr src_addr) (OpReg tmp)) `appOL` |
| | 1535 | unitOL (MOV II32 (OpReg tmp) (OpAddr dst_addr)) `appOL` |
| | 1536 | go dst src tmp (i - 4) |
| | 1537 | | i >= 2 = |
| | 1538 | unitOL (MOVZxL II16 (OpAddr src_addr) (OpReg tmp)) `appOL` |
| | 1539 | unitOL (MOV II16 (OpReg tmp) (OpAddr dst_addr)) `appOL` |
| | 1540 | go dst src tmp (i - 2) |
| | 1541 | | i >= 1 = |
| | 1542 | unitOL (MOVZxL II8 (OpAddr src_addr) (OpReg tmp)) `appOL` |
| | 1543 | unitOL (MOV II8 (OpReg tmp) (OpAddr dst_addr)) `appOL` |
| | 1544 | go dst src tmp (i - 1) |
| | 1545 | | otherwise = nilOL |
| | 1546 | where |
| | 1547 | src_addr = AddrBaseIndex (EABaseReg src) EAIndexNone |
| | 1548 | (ImmInteger (n - i)) |
| | 1549 | dst_addr = AddrBaseIndex (EABaseReg dst) EAIndexNone |
| | 1550 | (ImmInteger (n - i)) |
| | 1551 | |
| | 1552 | genCCall (CmmPrim MO_Memset) _ args@[CmmHinted dst _, |
| | 1553 | CmmHinted (CmmLit (CmmInt c _)) _, |
| | 1554 | CmmHinted (CmmLit (CmmInt n _)) _, |
| | 1555 | CmmHinted (CmmLit (CmmInt align _)) _] |
| | 1556 | | n <= maxInlineSizeThreshold && align .&. 3 == 0 = do |
| | 1557 | code_dst <- getAnyReg dst |
| | 1558 | dst_r <- getNewRegNat size |
| | 1559 | return $ code_dst dst_r `appOL` go dst_r n |
| | 1560 | where |
| | 1561 | (size, val) = case align .&. 3 of |
| | 1562 | 2 -> (II16, c2) |
| | 1563 | 0 -> (II32, c4) |
| | 1564 | _ -> (II8, c) |
| | 1565 | c2 = c `shiftL` 8 .|. c |
| | 1566 | c4 = c2 `shiftL` 16 .|. c2 |
| | 1567 | |
| | 1568 | sizeBytes = fromIntegral (sizeInBytes size) |
| | 1569 | |
| | 1570 | go :: Reg -> Integer -> OrdList Instr |
| | 1571 | go dst i |
| | 1572 | -- TODO: Add movabs instruction and support 64-bit sets. |
| | 1573 | | i >= sizeBytes = -- This might be smaller than the below sizes |
| | 1574 | unitOL (MOV size (OpImm (ImmInteger val)) (OpAddr dst_addr)) `appOL` |
| | 1575 | go dst (i - sizeBytes) |
| | 1576 | | i >= 4 = -- Will never happen on 32-bit |
| | 1577 | unitOL (MOV II32 (OpImm (ImmInteger c4)) (OpAddr dst_addr)) `appOL` |
| | 1578 | go dst (i - 4) |
| | 1579 | | i >= 2 = |
| | 1580 | unitOL (MOV II16 (OpImm (ImmInteger c2)) (OpAddr dst_addr)) `appOL` |
| | 1581 | go dst (i - 2) |
| | 1582 | | i >= 1 = |
| | 1583 | unitOL (MOV II8 (OpImm (ImmInteger c)) (OpAddr dst_addr)) `appOL` |
| | 1584 | go dst (i - 1) |
| | 1585 | | otherwise = nilOL |
| | 1586 | where |
| | 1587 | dst_addr = AddrBaseIndex (EABaseReg dst) EAIndexNone |
| | 1588 | (ImmInteger (n - i)) |
| | 1589 | |