# Changeset View

# Standalone View

# compiler/codeGen/StgCmmPrim.hs

Show First 20 Lines • Show All 657 Lines • ▼ Show 20 Line(s) | |||||

658 | emitPrimOp _ [res] Word2FloatOp [w] = emitPrimCall [res] | 658 | emitPrimOp _ [res] Word2FloatOp [w] = emitPrimCall [res] | ||

659 | (MO_UF_Conv W32) [w] | 659 | (MO_UF_Conv W32) [w] | ||

660 | emitPrimOp _ [res] Word2DoubleOp [w] = emitPrimCall [res] | 660 | emitPrimOp _ [res] Word2DoubleOp [w] = emitPrimCall [res] | ||

661 | (MO_UF_Conv W64) [w] | 661 | (MO_UF_Conv W64) [w] | ||

662 | 662 | | |||

663 | -- SIMD primops | 663 | -- SIMD primops | ||

664 | emitPrimOp dflags [res] (VecBroadcastOp vcat n w) [e] = do | 664 | emitPrimOp dflags [res] (VecBroadcastOp vcat n w) [e] = do | ||

665 | checkVecCompatibility dflags vcat n w | 665 | checkVecCompatibility dflags vcat n w | ||

666 | doVecPackOp (vecElemInjectCast dflags vcat w) ty zeros (replicate n e) res | 666 | doVecBroadcastOp (vecElemInjectCast dflags vcat w) ty zeros e res | ||

667 | where | 667 | where | ||

668 | zeros :: CmmExpr | 668 | zeros :: CmmExpr | ||

669 | zeros = CmmLit $ CmmVec (replicate n zero) | 669 | zeros = CmmLit $ CmmVec (replicate n zero) | ||

670 | 670 | | |||

671 | zero :: CmmLit | 671 | zero :: CmmLit | ||

672 | zero = case vcat of | 672 | zero = case vcat of | ||

673 | IntVec -> CmmInt 0 w | 673 | IntVec -> CmmInt 0 w | ||

674 | WordVec -> CmmInt 0 w | 674 | WordVec -> CmmInt 0 w | ||

▲ Show 20 Lines • Show All 204 Lines • ▼ Show 20 Line(s) | 878 | IntQuotRemOp | ncg && (x86ish || ppc) -> | |||

879 | Left (MO_S_QuotRem (wordWidth dflags)) | 879 | Left (MO_S_QuotRem (wordWidth dflags)) | ||

880 | | otherwise -> | 880 | | otherwise -> | ||

881 | Right (genericIntQuotRemOp (wordWidth dflags)) | 881 | Right (genericIntQuotRemOp (wordWidth dflags)) | ||

882 | 882 | | |||

883 | Int8QuotRemOp | (ncg && x86ish) | 883 | Int8QuotRemOp | (ncg && x86ish) | ||

884 | || llvm -> Left (MO_S_QuotRem W8) | 884 | || llvm -> Left (MO_S_QuotRem W8) | ||

885 | | otherwise -> Right (genericIntQuotRemOp W8) | 885 | | otherwise -> Right (genericIntQuotRemOp W8) | ||

886 | 886 | | |||

887 | Int16QuotRemOp | (ncg && x86ish) | ||||

888 | || llvm -> Left (MO_S_QuotRem W16) | ||||

889 | | otherwise -> Right (genericIntQuotRemOp W16) | ||||

890 | | ||||

891 | | ||||

887 | WordQuotRemOp | ncg && (x86ish || ppc) -> | 892 | WordQuotRemOp | ncg && (x86ish || ppc) -> | ||

888 | Left (MO_U_QuotRem (wordWidth dflags)) | 893 | Left (MO_U_QuotRem (wordWidth dflags)) | ||

889 | | otherwise -> | 894 | | otherwise -> | ||

890 | Right (genericWordQuotRemOp (wordWidth dflags)) | 895 | Right (genericWordQuotRemOp (wordWidth dflags)) | ||

891 | 896 | | |||

892 | WordQuotRem2Op | (ncg && (x86ish | 897 | WordQuotRem2Op | (ncg && (x86ish | ||

893 | || ppc)) | 898 | || ppc)) | ||

894 | || llvm -> Left (MO_U_QuotRem2 (wordWidth dflags)) | 899 | || llvm -> Left (MO_U_QuotRem2 (wordWidth dflags)) | ||

895 | | otherwise -> Right (genericWordQuotRem2Op dflags) | 900 | | otherwise -> Right (genericWordQuotRem2Op dflags) | ||

896 | 901 | | |||

897 | Word8QuotRemOp | (ncg && x86ish) | 902 | Word8QuotRemOp | (ncg && x86ish) | ||

898 | || llvm -> Left (MO_U_QuotRem W8) | 903 | || llvm -> Left (MO_U_QuotRem W8) | ||

899 | | otherwise -> Right (genericWordQuotRemOp W8) | 904 | | otherwise -> Right (genericWordQuotRemOp W8) | ||

900 | 905 | | |||

906 | Word16QuotRemOp| (ncg && x86ish) | ||||

907 | || llvm -> Left (MO_U_QuotRem W16) | ||||

908 | | otherwise -> Right (genericWordQuotRemOp W16) | ||||

909 | | ||||

901 | WordAdd2Op | (ncg && (x86ish | 910 | WordAdd2Op | (ncg && (x86ish | ||

902 | || ppc)) | 911 | || ppc)) | ||

903 | || llvm -> Left (MO_Add2 (wordWidth dflags)) | 912 | || llvm -> Left (MO_Add2 (wordWidth dflags)) | ||

904 | | otherwise -> Right genericWordAdd2Op | 913 | | otherwise -> Right genericWordAdd2Op | ||

905 | 914 | | |||

906 | WordAddCOp | (ncg && (x86ish | 915 | WordAddCOp | (ncg && (x86ish | ||

907 | || ppc)) | 916 | || ppc)) | ||

908 | || llvm -> Left (MO_AddWordC (wordWidth dflags)) | 917 | || llvm -> Left (MO_AddWordC (wordWidth dflags)) | ||

▲ Show 20 Lines • Show All 442 Lines • ▼ Show 20 Line(s) | |||||

1351 | 1360 | | |||

1352 | translateOp _ Word8EqOp = Just (MO_Eq W8) | 1361 | translateOp _ Word8EqOp = Just (MO_Eq W8) | ||

1353 | translateOp _ Word8GeOp = Just (MO_U_Ge W8) | 1362 | translateOp _ Word8GeOp = Just (MO_U_Ge W8) | ||

1354 | translateOp _ Word8GtOp = Just (MO_U_Gt W8) | 1363 | translateOp _ Word8GtOp = Just (MO_U_Gt W8) | ||

1355 | translateOp _ Word8LeOp = Just (MO_U_Le W8) | 1364 | translateOp _ Word8LeOp = Just (MO_U_Le W8) | ||

1356 | translateOp _ Word8LtOp = Just (MO_U_Lt W8) | 1365 | translateOp _ Word8LtOp = Just (MO_U_Lt W8) | ||

1357 | translateOp _ Word8NeOp = Just (MO_Ne W8) | 1366 | translateOp _ Word8NeOp = Just (MO_Ne W8) | ||

1358 | 1367 | | |||

1368 | -- Int16# signed ops | ||||

1369 | | ||||

1370 | translateOp dflags Int16Extend = Just (MO_SS_Conv W16 (wordWidth dflags)) | ||||

1371 | translateOp dflags Int16Narrow = Just (MO_SS_Conv (wordWidth dflags) W16) | ||||

1372 | translateOp _ Int16NegOp = Just (MO_S_Neg W16) | ||||

1373 | translateOp _ Int16AddOp = Just (MO_Add W16) | ||||

1374 | translateOp _ Int16SubOp = Just (MO_Sub W16) | ||||

1375 | translateOp _ Int16MulOp = Just (MO_Mul W16) | ||||

1376 | translateOp _ Int16QuotOp = Just (MO_S_Quot W16) | ||||

1377 | translateOp _ Int16RemOp = Just (MO_S_Rem W16) | ||||

1378 | | ||||

1379 | translateOp _ Int16EqOp = Just (MO_Eq W16) | ||||

1380 | translateOp _ Int16GeOp = Just (MO_S_Ge W16) | ||||

1381 | translateOp _ Int16GtOp = Just (MO_S_Gt W16) | ||||

1382 | translateOp _ Int16LeOp = Just (MO_S_Le W16) | ||||

1383 | translateOp _ Int16LtOp = Just (MO_S_Lt W16) | ||||

1384 | translateOp _ Int16NeOp = Just (MO_Ne W16) | ||||

1385 | | ||||

1386 | -- Word16# unsigned ops | ||||

1387 | | ||||

1388 | translateOp dflags Word16Extend = Just (MO_UU_Conv W16 (wordWidth dflags)) | ||||

1389 | translateOp dflags Word16Narrow = Just (MO_UU_Conv (wordWidth dflags) W16) | ||||

1390 | translateOp _ Word16NotOp = Just (MO_Not W16) | ||||

1391 | translateOp _ Word16AddOp = Just (MO_Add W16) | ||||

1392 | translateOp _ Word16SubOp = Just (MO_Sub W16) | ||||

1393 | translateOp _ Word16MulOp = Just (MO_Mul W16) | ||||

1394 | translateOp _ Word16QuotOp = Just (MO_U_Quot W16) | ||||

1395 | translateOp _ Word16RemOp = Just (MO_U_Rem W16) | ||||

1396 | | ||||

1397 | translateOp _ Word16EqOp = Just (MO_Eq W16) | ||||

1398 | translateOp _ Word16GeOp = Just (MO_U_Ge W16) | ||||

1399 | translateOp _ Word16GtOp = Just (MO_U_Gt W16) | ||||

1400 | translateOp _ Word16LeOp = Just (MO_U_Le W16) | ||||

1401 | translateOp _ Word16LtOp = Just (MO_U_Lt W16) | ||||

1402 | translateOp _ Word16NeOp = Just (MO_Ne W16) | ||||

1403 | | ||||

1359 | -- Char# ops | 1404 | -- Char# ops | ||

1360 | 1405 | | |||

1361 | translateOp dflags CharEqOp = Just (MO_Eq (wordWidth dflags)) | 1406 | translateOp dflags CharEqOp = Just (MO_Eq (wordWidth dflags)) | ||

1362 | translateOp dflags CharNeOp = Just (MO_Ne (wordWidth dflags)) | 1407 | translateOp dflags CharNeOp = Just (MO_Ne (wordWidth dflags)) | ||

1363 | translateOp dflags CharGeOp = Just (MO_U_Ge (wordWidth dflags)) | 1408 | translateOp dflags CharGeOp = Just (MO_U_Ge (wordWidth dflags)) | ||

1364 | translateOp dflags CharLeOp = Just (MO_U_Le (wordWidth dflags)) | 1409 | translateOp dflags CharLeOp = Just (MO_U_Le (wordWidth dflags)) | ||

1365 | translateOp dflags CharGtOp = Just (MO_U_Gt (wordWidth dflags)) | 1410 | translateOp dflags CharGtOp = Just (MO_U_Gt (wordWidth dflags)) | ||

1366 | translateOp dflags CharLtOp = Just (MO_U_Lt (wordWidth dflags)) | 1411 | translateOp dflags CharLtOp = Just (MO_U_Lt (wordWidth dflags)) | ||

▲ Show 20 Lines • Show All 317 Lines • ▼ Show 20 Line(s) | |||||

1684 | vecElemProjectCast dflags WordVec W32 = Just (mo_u_32ToWord dflags) | 1729 | vecElemProjectCast dflags WordVec W32 = Just (mo_u_32ToWord dflags) | ||

1685 | vecElemProjectCast _ WordVec W64 = Nothing | 1730 | vecElemProjectCast _ WordVec W64 = Nothing | ||

1686 | vecElemProjectCast _ _ _ = Nothing | 1731 | vecElemProjectCast _ _ _ = Nothing | ||

1687 | 1732 | | |||

1688 | -- Check to make sure that we can generate code for the specified vector type | 1733 | -- Check to make sure that we can generate code for the specified vector type | ||

1689 | -- given the current set of dynamic flags. | 1734 | -- given the current set of dynamic flags. | ||

1690 | checkVecCompatibility :: DynFlags -> PrimOpVecCat -> Length -> Width -> FCode () | 1735 | checkVecCompatibility :: DynFlags -> PrimOpVecCat -> Length -> Width -> FCode () | ||

1691 | checkVecCompatibility dflags vcat l w = do | 1736 | checkVecCompatibility dflags vcat l w = do | ||

1692 | when (hscTarget dflags /= HscLlvm) $ do | 1737 | when (hscTarget dflags /= HscLlvm && hscTarget dflags /= HscAsm) $ do | ||

1693 | sorry $ unlines ["SIMD vector instructions require the LLVM back-end." | 1738 | sorry "SIMD vector instructions not supported for the C backend or GHCi" | ||

carter: a TODO we can address some other time, because there are C intrinsics per platform | |||||

1694 | ,"Please use -fllvm."] | | |||

1695 | check vecWidth vcat l w | 1739 | check vecWidth vcat l w | ||

1696 | where | 1740 | where | ||

1697 | check :: Width -> PrimOpVecCat -> Length -> Width -> FCode () | 1741 | check :: Width -> PrimOpVecCat -> Length -> Width -> FCode () | ||

1698 | check W128 FloatVec 4 W32 | not (isSseEnabled dflags) = | 1742 | check W128 FloatVec 4 W32 | not (isSseEnabled dflags) = | ||

1699 | sorry $ "128-bit wide single-precision floating point " ++ | 1743 | sorry $ "128-bit wide single-precision floating point " ++ | ||

1700 | "SIMD vector instructions require at least -msse." | 1744 | "SIMD vector instructions require at least -msse." | ||

1701 | check W128 _ _ _ | not (isSse2Enabled dflags) = | 1745 | check W128 _ _ _ | not (isSse2Enabled dflags) = | ||

1702 | sorry $ "128-bit wide integer and double precision " ++ | 1746 | sorry $ "128-bit wide integer and double precision " ++ | ||

1703 | "SIMD vector instructions require at least -msse2." | 1747 | "SIMD vector instructions require at least -msse2." | ||

1704 | check W256 FloatVec _ _ | not (isAvxEnabled dflags) = | 1748 | check W256 FloatVec _ _ | not (isAvxEnabled dflags) = | ||

1705 | sorry $ "256-bit wide floating point " ++ | 1749 | sorry $ "256-bit wide floating point " ++ | ||

1706 | "SIMD vector instructions require at least -mavx." | 1750 | "SIMD vector instructions require at least -mavx." | ||

1707 | check W256 _ _ _ | not (isAvx2Enabled dflags) = | 1751 | check W256 _ _ _ | not (isAvx2Enabled dflags) = | ||

1708 | sorry $ "256-bit wide integer " ++ | 1752 | sorry $ "256-bit wide integer " ++ | ||

1709 | "SIMD vector instructions require at least -mavx2." | 1753 | "SIMD vector instructions require at least -mavx2." | ||

1710 | check W512 _ _ _ | not (isAvx512fEnabled dflags) = | 1754 | check W512 _ _ _ | not (isAvx512fEnabled dflags) = | ||

1711 | sorry $ "512-bit wide " ++ | 1755 | sorry $ "512-bit wide " ++ | ||

1712 | "SIMD vector instructions require -mavx512f." | 1756 | "SIMD vector instructions require -mavx512f." | ||

1713 | check _ _ _ _ = return () | 1757 | check _ _ _ _ = return () | ||

1714 | 1758 | | |||

1715 | vecWidth = typeWidth (vecVmmType vcat l w) | 1759 | vecWidth = typeWidth (vecVmmType vcat l w) | ||

1716 | 1760 | | |||

1717 | ------------------------------------------------------------------------------ | 1761 | ------------------------------------------------------------------------------ | ||

1718 | -- Helpers for translating vector packing and unpacking. | 1762 | -- Helpers for translating vector packing and unpacking. | ||

1763 | doVecBroadcastOp :: Maybe MachOp -- Cast from element to vector component | ||||

1764 | -> CmmType -- Type of vector | ||||

1765 | -> CmmExpr -- Initial vector | ||||

1766 | -> CmmExpr -- Elements | ||||

1767 | -> CmmFormal -- Destination for result | ||||

1768 | -> FCode () | ||||

1769 | doVecBroadcastOp maybe_pre_write_cast ty z es res = do | ||||

1770 | dst <- newTemp ty | ||||

1771 | emitAssign (CmmLocal dst) z | ||||

1772 | vecBroadcast dst es 0 | ||||

1773 | where | ||||

1774 | vecBroadcast :: CmmFormal -> CmmExpr -> Int -> FCode () | ||||

1775 | vecBroadcast src e _ = do | ||||

1776 | dst <- newTemp ty | ||||

1777 | if isFloatType (vecElemType ty) | ||||

1778 | then emitAssign (CmmLocal dst) (CmmMachOp (MO_VF_Broadcast len wid) | ||||

1779 | [CmmReg (CmmLocal src), cast e]) | ||||

Lint: Line Too Long: This line is 84 characters long, but the convention is 80 characters. | |||||

1780 | --TODO : Add the MachOp MO_V_Broadcast | ||||

1781 | else emitAssign (CmmLocal dst) (CmmMachOp (MO_V_Insert len wid) | ||||

1782 | [CmmReg (CmmLocal src), cast e]) | ||||

Lint: Line Too Long: This line is 84 characters long, but the convention is 80 characters. | |||||

1783 | emitAssign (CmmLocal res) (CmmReg (CmmLocal dst)) | ||||

1784 | | ||||

1785 | cast :: CmmExpr -> CmmExpr | ||||

1786 | cast val = case maybe_pre_write_cast of | ||||

1787 | Nothing -> val | ||||

1788 | Just cast -> CmmMachOp cast [val] | ||||

1789 | | ||||

1790 | len :: Length | ||||

1791 | len = vecLength ty | ||||

1792 | | ||||

1793 | wid :: Width | ||||

1794 | wid = typeWidth (vecElemType ty) | ||||

1719 | 1795 | | |||

1720 | doVecPackOp :: Maybe MachOp -- Cast from element to vector component | 1796 | doVecPackOp :: Maybe MachOp -- Cast from element to vector component | ||

1721 | -> CmmType -- Type of vector | 1797 | -> CmmType -- Type of vector | ||

1722 | -> CmmExpr -- Initial vector | 1798 | -> CmmExpr -- Initial vector | ||

1723 | -> [CmmExpr] -- Elements | 1799 | -> [CmmExpr] -- Elements | ||

1724 | -> CmmFormal -- Destination for result | 1800 | -> CmmFormal -- Destination for result | ||

1725 | -> FCode () | 1801 | -> FCode () | ||

1726 | doVecPackOp maybe_pre_write_cast ty z es res = do | 1802 | doVecPackOp maybe_pre_write_cast ty z es res = do | ||

1727 | dst <- newTemp ty | 1803 | dst <- newTemp ty | ||

1728 | emitAssign (CmmLocal dst) z | 1804 | emitAssign (CmmLocal dst) z | ||

carter: why'd you remove this? | |||||

@carter I mentioned about this in the previous diff: https://phabricator.haskell.org/D4779#131943 I think I should have added a link to the previous discussion in the summary. Its here : https://phabricator.haskell.org/D4779 Abhiroop: @carter I mentioned about this in the previous diff: https://phabricator.haskell. | |||||

i didn't understand the explanation then, you didn't quite say it clearly: could you try to explain it again please? carter: i didn't understand the explanation then, you didn't quite say it clearly:
could you try to… | |||||

I will provide an example. Previously for the code: broadcastFloatX4# 1.5# the following Cmm( details elided) would be emitted: c1JZ: // global _c1JS::Fx4V128 = <0.0 :: W32, 0.0 :: W32, 0.0 :: W32, 0.0 :: W32>; // CmmAssign _c1JT::Fx4V128 = %MO_VF_Insert_4_W32(_c1JS::Fx4V128, 1.5 :: W32, 0 :: W32); // CmmAssign _c1JU::Fx4V128 = %MO_VF_Insert_4_W32(_c1JT::Fx4V128, 1.5 :: W32, 1 :: W32); // CmmAssign _c1JV::Fx4V128 = %MO_VF_Insert_4_W32(_c1JU::Fx4V128, 1.5 :: W32, 2 :: W32); // CmmAssign _c1JW::Fx4V128 = %MO_VF_Insert_4_W32(_c1JV::Fx4V128, 1.5 :: W32, 3 :: W32); // CmmAssign _c1JR::Fx4V128 = _c1JW::Fx4V128; // CmmAssign XMM1 = _c1JR::Fx4V128; // CmmAssign call (P64[Sp])(XMM1) args: 8, res: 0, upd: 8; // CmmCall Consider the first line: _c1JS::Fx4V128 = <0.0 :: W32, 0.0 :: W32, 0.0 :: W32, 0.0 :: W32>; // CmmAssign this Cmm corresponds to the code that I commented out. This register is passed in the next function and four other calls are made. In the new implementation of the broadcast operation the Cmm for the same function broadcastFloatX4# looks like this: c1JW: // global _c1JT::Fx4V128 = %MO_VF_Insert_4_W32(1.5 :: W32, 0 :: W32); // CmmAssign _c1JR::Fx4V128 = _c1JT::Fx4V128; // CmmAssign XMM1 = _c1JR::Fx4V128; // CmmAssign call (P64[Sp])(XMM1) args: 8, res: 0, upd: 8; // CmmCall This operation is straight away translated to a VBROADCASTSS instruction. There is no need of the initialization which was done in the previous code. My guess is, initially for the broadcast, the offset of the xmm register would be calculated (0,32,64,96) and each float would be inserted at that offset. Due to which four operations were involved. The new implementation does this in one operation. Abhiroop: I will provide an example.
Previously for the code:
```
broadcastFloatX4# 1.5#
```
the… | |||||

1729 | vecPack dst es 0 | 1805 | vecPack dst es 0 | ||

1730 | where | 1806 | where | ||

1731 | vecPack :: CmmFormal -> [CmmExpr] -> Int -> FCode () | 1807 | vecPack :: CmmFormal -> [CmmExpr] -> Int -> FCode () | ||

1732 | vecPack src [] _ = | 1808 | vecPack src [] _ = | ||

1733 | emitAssign (CmmLocal res) (CmmReg (CmmLocal src)) | 1809 | emitAssign (CmmLocal res) (CmmReg (CmmLocal src)) | ||

1734 | 1810 | | |||

1735 | vecPack src (e : es) i = do | 1811 | vecPack src (e : es) i = do | ||

1736 | dst <- newTemp ty | 1812 | dst <- newTemp ty | ||

The above two changes are to fix the "-dcmm-lint" errors. Cmm lint runs a liveness pass where it doesn't allow unused registers to survive. These two registers were not being used and they were initially written to facilitate the implementation of broadcast using multiple pack operations. The current implementation doesn't require this register. Abhiroop: The above two changes are to fix the "-dcmm-lint" errors. Cmm lint runs a liveness pass where… | |||||

1737 | if isFloatType (vecElemType ty) | 1813 | if isFloatType (vecElemType ty) | ||

1738 | then emitAssign (CmmLocal dst) (CmmMachOp (MO_VF_Insert len wid) | 1814 | then emitAssign (CmmLocal dst) (CmmMachOp (MO_VF_Insert len wid) | ||

1739 | [CmmReg (CmmLocal src), cast e, iLit]) | 1815 | [CmmReg (CmmLocal src), cast e, iLit]) | ||

1740 | else emitAssign (CmmLocal dst) (CmmMachOp (MO_V_Insert len wid) | 1816 | else emitAssign (CmmLocal dst) (CmmMachOp (MO_V_Insert len wid) | ||

1741 | [CmmReg (CmmLocal src), cast e, iLit]) | 1817 | [CmmReg (CmmLocal src), cast e, iLit]) | ||

1742 | vecPack dst es (i + 1) | 1818 | vecPack dst es (i + 1) | ||

1743 | where | 1819 | where | ||

1744 | -- vector indices are always 32-bits | 1820 | -- vector indices are always 32-bits | ||

1745 | iLit = CmmLit (CmmInt (toInteger i) W32) | 1821 | iLit = CmmLit (CmmInt ((toInteger i) * 16) W32) | ||

The logic for this part for reference: https://www.felixcloutier.com/x86/INSERTPS.html#insertps--128-bit-legacy-sse-version- Abhiroop: The logic for this part for reference: https://www.felixcloutier.com/x86/INSERTPS.html#insertps… | |||||

1746 | 1822 | | |||

1747 | cast :: CmmExpr -> CmmExpr | 1823 | cast :: CmmExpr -> CmmExpr | ||

1748 | cast val = case maybe_pre_write_cast of | 1824 | cast val = case maybe_pre_write_cast of | ||

1749 | Nothing -> val | 1825 | Nothing -> val | ||

1750 | Just cast -> CmmMachOp cast [val] | 1826 | Just cast -> CmmMachOp cast [val] | ||

1751 | 1827 | | |||

1752 | len :: Length | 1828 | len :: Length | ||

1753 | len = vecLength ty | 1829 | len = vecLength ty | ||

▲ Show 20 Lines • Show All 756 Lines • Show Last 20 Lines |

a TODO we can address some other time, because there are C intrinsics per platform