{"id":678,"date":"2018-07-02T11:05:17","date_gmt":"2018-07-02T11:05:17","guid":{"rendered":"http:\/\/blogs.gentoo.org\/lu_zero\/?p=678"},"modified":"2018-07-03T11:08:59","modified_gmt":"2018-07-03T11:08:59","slug":"altivec-and-vsx-in-rust-part-1","status":"publish","type":"post","link":"https:\/\/blogs.gentoo.org\/lu_zero\/2018\/07\/02\/altivec-and-vsx-in-rust-part-1\/","title":{"rendered":"Altivec and VSX in Rust (part 1)"},"content":{"rendered":"<p>I&#8217;m involved in implementing the Altivec and VSX support on <a href=\"https:\/\/rust-lang.org\">rust<\/a> <a href=\"https:\/\/github.com\/rust-lang-nursery\/stdsimd\">stdsimd<\/a>.<\/p>\n<p>Supporting all the instructions in this language is a HUGE endeavor since for each instruction at least 2 tests have to be written and making functions type-generic gets you to the point of having few pages of implementation (that luckily desugars to the single right instruction and nothing else).<\/p>\n<p>Since I&#8217;m doing this <em>mainly<\/em> for my multimedia needs I have a short list of instructions I find handy to get some code written immediately and today I&#8217;ll talk a bit about some of them.<\/p>\n<p>This post is inspired by what <a href=\"https:\/\/medium.com\/@luc.trudeau\">Luc<\/a> did for <a href=\"https:\/\/medium.com\/@luc.trudeau\/arm-neon-intrinsics-add-functions-explained-with-c-90346d912796\">neon<\/a>, but I&#8217;m using rust instead.<\/p>\n<p>If other people find it useful, I&#8217;ll try to write down the remaining istructions.<\/p>\n<h2>Permutations<\/h2>\n<p>Most if not all the SIMD ISAs have at least one or multiple instructions to shuffle vector elements within a vector or among two.<\/p>\n<p>It is quite common to use those instructions to implement matrix transposes, but it isn&#8217;t its only use.<\/p>\n<p>In my toolbox I put <code>vec_perm<\/code> and <code>vec_xxpermdi<\/code> since even if the <em>portable<\/em> stdsimd provides some shuffle support it is quite unwieldy compared to the Altivec native offering.<\/p>\n<h3><code>vec_perm<\/code>: Vector Permute<\/h3>\n<p>Since it first iteration Altivec had a quite amazing instruction called <code>vec_perm<\/code> or <code>vperm<\/code>:<\/p>\n<div class=\"codehilite\">\n<pre><span><\/span><span class=\"w\">    <\/span><span class=\"k\">fn<\/span> <span class=\"nf\">vec_perm<\/span><span class=\"p\">(<\/span><span class=\"n\">a<\/span>: <span class=\"nc\">i8x16<\/span><span class=\"p\">,<\/span><span class=\"w\"> <\/span><span class=\"n\">b<\/span>: <span class=\"nc\">i8x16<\/span><span class=\"p\">,<\/span><span class=\"w\"> <\/span><span class=\"n\">c<\/span>: <span class=\"nc\">i8x16<\/span><span class=\"p\">)<\/span><span class=\"w\"> <\/span>-&gt; <span class=\"nc\">i8x16<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"><\/span>\n<span class=\"w\">        <\/span><span class=\"kd\">let<\/span><span class=\"w\"> <\/span><span class=\"k\">mut<\/span><span class=\"w\"> <\/span><span class=\"n\">d<\/span><span class=\"p\">;<\/span><span class=\"w\"><\/span>\n<span class=\"w\">        <\/span><span class=\"k\">for<\/span><span class=\"w\"> <\/span><span class=\"n\">i<\/span><span class=\"w\"> <\/span><span class=\"k\">in<\/span><span class=\"w\"> <\/span><span class=\"mi\">0<\/span><span class=\"p\">..<\/span><span class=\"mi\">16<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"><\/span>\n<span class=\"w\">            <\/span><span class=\"kd\">let<\/span><span class=\"w\"> <\/span><span class=\"n\">idx<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"n\">c<\/span><span class=\"p\">[<\/span><span class=\"n\">i<\/span><span class=\"p\">]<\/span><span class=\"w\"> <\/span><span class=\"o\">&amp;<\/span><span class=\"w\"> <\/span><span class=\"mh\">0xf<\/span><span class=\"p\">;<\/span><span class=\"w\"><\/span>\n<span class=\"w\">            <\/span><span class=\"n\">d<\/span><span class=\"p\">[<\/span><span class=\"n\">i<\/span><span class=\"p\">]<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"k\">if<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"n\">c<\/span><span class=\"p\">[<\/span><span class=\"n\">i<\/span><span class=\"p\">]<\/span><span class=\"w\"> <\/span><span class=\"o\">&amp;<\/span><span class=\"w\"> <\/span><span class=\"mh\">0x10<\/span><span class=\"p\">)<\/span><span class=\"w\"> <\/span><span class=\"o\">==<\/span><span class=\"w\"> <\/span><span class=\"mi\">0<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"><\/span>\n<span class=\"w\">                <\/span><span class=\"n\">a<\/span><span class=\"p\">[<\/span><span class=\"n\">idx<\/span><span class=\"p\">]<\/span><span class=\"w\"><\/span>\n<span class=\"w\">            <\/span><span class=\"p\">}<\/span><span class=\"w\"> <\/span><span class=\"k\">else<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"><\/span>\n<span class=\"w\">                <\/span><span class=\"n\">b<\/span><span class=\"p\">[<\/span><span class=\"n\">idx<\/span><span class=\"p\">]<\/span><span class=\"w\"><\/span>\n<span class=\"w\">            <\/span><span class=\"p\">};<\/span><span class=\"w\"><\/span>\n<span class=\"w\">        <\/span><span class=\"p\">}<\/span><span class=\"w\"><\/span>\n<span class=\"w\">        <\/span><span class=\"n\">d<\/span><span class=\"w\"><\/span>\n<span class=\"w\">    <\/span><span class=\"p\">}<\/span><span class=\"w\"><\/span>\n<\/pre>\n<\/div>\n<p>It is important to notice that the displacement map <code>c<\/code> is a vector and not a constant. That gives you quite a bit of flexibility in a number of situations.<\/p>\n<p>This instruction is the building block you can use to implement a large deal of common patterns, including some that are also covered by stand-alone instructions e.g.:<br \/>\n&#8211; packing\/unpacking across lanes as long you do not have to saturate: <code>vec_pack<\/code>, <code>vec_unpackh\/vec_unpackl<\/code><br \/>\n&#8211; interleave\/merge two vectors: <code>vec_mergel<\/code>, <code>vec_mergeh<\/code><br \/>\n&#8211; shift N bytes in a vector from another: <code>vec_sld<\/code><\/p>\n<p>It can be important to recall this since you could always take two permutations and make one, <code>vec_perm<\/code> itself is pretty fast and replacing two or more instructions with a single permute can get you a pretty neat speed boost.<\/p>\n<h3><code>vec_xxpermdi<\/code> Vector Permute Doubleword Immediate<\/h3>\n<p>Among a good deal of improvements VSX introduced a number of instructions that work on 64bit-elements vectors, among those we have a permute instruction and I found myself using it a lot.<\/p>\n<div class=\"codehilite\">\n<pre><span><\/span><span class=\"w\">    <\/span><span class=\"cp\">#[rustc_args_required_const(2)]<\/span><span class=\"w\"><\/span>\n<span class=\"w\">    <\/span><span class=\"k\">fn<\/span> <span class=\"nf\">vec_xxpermdi<\/span><span class=\"p\">(<\/span><span class=\"n\">a<\/span>: <span class=\"nc\">i64x2<\/span><span class=\"p\">,<\/span><span class=\"w\"> <\/span><span class=\"n\">b<\/span>: <span class=\"nc\">i64x2<\/span><span class=\"p\">,<\/span><span class=\"w\"> <\/span><span class=\"n\">c<\/span>: <span class=\"kt\">u8<\/span><span class=\"p\">)<\/span><span class=\"w\"> <\/span>-&gt; <span class=\"nc\">i64x2<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"><\/span>\n<span class=\"w\">        <\/span><span class=\"k\">match<\/span><span class=\"w\"> <\/span><span class=\"n\">c<\/span><span class=\"w\"> <\/span><span class=\"o\">&amp;<\/span><span class=\"w\"> <\/span><span class=\"mb\">0b11<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"><\/span>\n<span class=\"w\">            <\/span><span class=\"mb\">0b00<\/span><span class=\"w\"> <\/span><span class=\"o\">=&gt;<\/span><span class=\"w\"> <\/span><span class=\"n\">i64x2<\/span>::<span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"n\">a<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">],<\/span><span class=\"w\"> <\/span><span class=\"n\">b<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">]);<\/span><span class=\"w\"><\/span>\n<span class=\"w\">            <\/span><span class=\"mb\">0b01<\/span><span class=\"w\"> <\/span><span class=\"o\">=&gt;<\/span><span class=\"w\"> <\/span><span class=\"n\">i64x2<\/span>::<span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"n\">a<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">],<\/span><span class=\"w\"> <\/span><span class=\"n\">b<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">]);<\/span><span class=\"w\"><\/span>\n<span class=\"w\">            <\/span><span class=\"mb\">0b10<\/span><span class=\"w\"> <\/span><span class=\"o\">=&gt;<\/span><span class=\"w\"> <\/span><span class=\"n\">i64x2<\/span>::<span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"n\">a<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">],<\/span><span class=\"w\"> <\/span><span class=\"n\">b<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">]);<\/span><span class=\"w\"><\/span>\n<span class=\"w\">            <\/span><span class=\"mb\">0b11<\/span><span class=\"w\"> <\/span><span class=\"o\">=&gt;<\/span><span class=\"w\"> <\/span><span class=\"n\">i64x2<\/span>::<span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"n\">a<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">],<\/span><span class=\"w\"> <\/span><span class=\"n\">b<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">]);<\/span><span class=\"w\"><\/span>\n<span class=\"w\">        <\/span><span class=\"p\">}<\/span><span class=\"w\"><\/span>\n<span class=\"w\">    <\/span><span class=\"p\">}<\/span><span class=\"w\"><\/span>\n<\/pre>\n<\/div>\n<p>This instruction is surely less flexible than the previous permute but it does not require an additional load.<\/p>\n<p>When working on video codecs is quite common to deal with blocks of pixels that go from 4&#215;4 up to 64&#215;64, before <code>vec_xxpermdi<\/code> the common pattern was:<\/p>\n<div class=\"codehilite\">\n<pre><span><\/span><span class=\"w\">    <\/span><span class=\"cp\">#[inline(always)]<\/span><span class=\"w\"><\/span>\n<span class=\"w\">    <\/span><span class=\"k\">fn<\/span> <span class=\"nf\">store8<\/span><span class=\"p\">(<\/span><span class=\"n\">dst<\/span>: <span class=\"kp\">&amp;<\/span><span class=\"nc\">mut<\/span><span class=\"w\"> <\/span><span class=\"p\">[<\/span><span class=\"n\">u8x16<\/span><span class=\"p\">],<\/span><span class=\"w\"> <\/span><span class=\"n\">v<\/span>: <span class=\"kp\">&amp;<\/span><span class=\"p\">[<\/span><span class=\"n\">u8x16<\/span><span class=\"p\">])<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"><\/span>\n<span class=\"w\">        <\/span><span class=\"kd\">let<\/span><span class=\"w\"> <\/span><span class=\"n\">data<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"n\">dst<\/span><span class=\"p\">[<\/span><span class=\"n\">i<\/span><span class=\"p\">];<\/span><span class=\"w\"><\/span>\n<span class=\"w\">        <\/span><span class=\"n\">dst<\/span><span class=\"p\">[<\/span><span class=\"n\">i<\/span><span class=\"p\">]<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"n\">vec_perm<\/span><span class=\"p\">(<\/span><span class=\"n\">v<\/span><span class=\"p\">,<\/span><span class=\"w\"> <\/span><span class=\"n\">data<\/span><span class=\"p\">,<\/span><span class=\"w\"> <\/span><span class=\"n\">TAKE_THE_FIRST_8<\/span><span class=\"p\">);<\/span><span class=\"w\"><\/span>\n<span class=\"w\">    <\/span><span class=\"p\">}<\/span><span class=\"w\"><\/span>\n<\/pre>\n<\/div>\n<p>That implies to load the mask as often as needed as long as the destination.<\/p>\n<p>Using <code>vec_xxpermdi<\/code> avoids the mask load and that usually leads to a quite significative speedup when the actual function is tiny.<\/p>\n<h2>Mixed Arithmetics<\/h2>\n<p>With mixed arithmetics I consider all the instructions that do in a single step multiple vector arithmetics.<\/p>\n<p>The original altivec has the following operations available for the integer types:<br \/>\n&#8211; <code>vec_madds<\/code><br \/>\n&#8211; <code>vec_mladd<\/code><br \/>\n&#8211; <code>vec_mradds<\/code><br \/>\n&#8211; <code>vec_msum<\/code><br \/>\n&#8211; <code>vec_msums<\/code><br \/>\n&#8211; <code>vec_sum2s<\/code><br \/>\n&#8211; <code>vec_sum4s<\/code><br \/>\n&#8211; <code>vec_sums<\/code><\/p>\n<p>And the following two for the float type:<br \/>\n&#8211; <code>vec_madd<\/code><br \/>\n&#8211; <code>vec_nmsub<\/code><\/p>\n<p>All of them are quite useful and they will all find their way in <strong>stdsimd<\/strong> pretty soon.<\/p>\n<p>I&#8217;m describing today <code>vec_sums<\/code>, <code>vec_msums<\/code> and <code>vec_madds<\/code>.<\/p>\n<p>They are quite representative and the other instructions are similar in spirit:<br \/>\n&#8211; <code>vec_madds<\/code>, <code>vec_mladd<\/code> and <code>vec_mradds<\/code> all compute a lane-wise product, take either the high-order or the low-order part of it<br \/>\nand add a third vector returning a vector of the same element size.<br \/>\n&#8211; <code>vec_sums<\/code>, <code>vec_sum2s<\/code> and <code>vec_sum4s<\/code> all combine an in-vector sum operation with a sum with another vector.<br \/>\n&#8211; <code>vec_msum<\/code> and <code>vec_msums<\/code> both compute a sum of products, the intermediates are added together and then added to a wider-element<br \/>\nvector.<\/p>\n<blockquote><p>\nIf there is enough interest and time I can extend this post to cover all of them, for today we&#8217;ll go with this approximation.\n<\/p><\/blockquote>\n<h3><code>vec_sums<\/code>: Vector Sum Saturated<\/h3>\n<p>Usually SIMD instruction work with two (or 3) vectors and execute the same operation for each vector element.<br \/>\nSometimes you want to just do operations within the single vector and <code>vec_sums<\/code> is one of the few instructions that let you do that:<\/p>\n<div class=\"codehilite\">\n<pre><span><\/span><span class=\"w\">    <\/span><span class=\"k\">fn<\/span> <span class=\"nf\">vec_sums<\/span><span class=\"p\">(<\/span><span class=\"n\">a<\/span>: <span class=\"nc\">i32x4<\/span><span class=\"p\">,<\/span><span class=\"w\"> <\/span><span class=\"n\">b<\/span>: <span class=\"nc\">i32x4<\/span><span class=\"p\">)<\/span><span class=\"w\"> <\/span>-&gt; <span class=\"nc\">i32x4<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"><\/span>\n<span class=\"w\">        <\/span><span class=\"kd\">let<\/span><span class=\"w\"> <\/span><span class=\"n\">d<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"n\">i32x4<\/span>::<span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"mi\">0<\/span><span class=\"p\">,<\/span><span class=\"w\"> <\/span><span class=\"mi\">0<\/span><span class=\"p\">,<\/span><span class=\"w\"> <\/span><span class=\"mi\">0<\/span><span class=\"p\">,<\/span><span class=\"w\"> <\/span><span class=\"mi\">0<\/span><span class=\"p\">);<\/span><span class=\"w\"><\/span>\n\n<span class=\"w\">        <\/span><span class=\"n\">d<\/span><span class=\"p\">[<\/span><span class=\"mi\">3<\/span><span class=\"p\">]<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"n\">b<\/span><span class=\"p\">[<\/span><span class=\"mi\">3<\/span><span class=\"p\">].<\/span><span class=\"n\">saturating_add<\/span><span class=\"p\">(<\/span><span class=\"n\">a<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">]).<\/span><span class=\"n\">saturating_add<\/span><span class=\"p\">(<\/span><span class=\"n\">a<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">]).<\/span><span class=\"n\">saturating_add<\/span><span class=\"p\">(<\/span><span class=\"n\">a<\/span><span class=\"p\">[<\/span><span class=\"mi\">2<\/span><span class=\"p\">]).<\/span><span class=\"n\">saturating_add<\/span><span class=\"p\">(<\/span><span class=\"n\">a<\/span><span class=\"p\">[<\/span><span class=\"mi\">3<\/span><span class=\"p\">]);<\/span><span class=\"w\"><\/span>\n\n<span class=\"w\">        <\/span><span class=\"n\">d<\/span><span class=\"w\"><\/span>\n<span class=\"w\">    <\/span><span class=\"p\">}<\/span><span class=\"w\"><\/span>\n<\/pre>\n<\/div>\n<p>It returns in the last element of the vector the sum of the vector elements of <code>a<\/code> and the last element of <code>b<\/code>.<br \/>\nIt is pretty handy when you need to compute an average or similar operations.<\/p>\n<p>It works <em>only<\/em> with <code>32bit signed<\/code> element vectors.<\/p>\n<h3><code>vec_msums<\/code>: Vector Multiply Sum Saturated<\/h3>\n<p>This instruction sums the 32bit element of the third vector with the two products of the respective 16bit<br \/>\nelements of the first two vectors overlapping the element.<\/p>\n<p>It does quite a bit:<\/p>\n<div class=\"codehilite\">\n<pre><span><\/span><span class=\"w\">    <\/span><span class=\"k\">fn<\/span> <span class=\"nf\">vmsumshs<\/span><span class=\"p\">(<\/span><span class=\"n\">a<\/span>: <span class=\"nc\">i16x8<\/span><span class=\"p\">,<\/span><span class=\"w\"> <\/span><span class=\"n\">b<\/span>: <span class=\"nc\">i16x8<\/span><span class=\"p\">,<\/span><span class=\"w\"> <\/span><span class=\"n\">c<\/span>: <span class=\"nc\">i32x4<\/span><span class=\"p\">)<\/span><span class=\"w\"> <\/span>-&gt; <span class=\"nc\">i32x4<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"><\/span>\n<span class=\"w\">        <\/span><span class=\"kd\">let<\/span><span class=\"w\"> <\/span><span class=\"n\">d<\/span><span class=\"p\">;<\/span><span class=\"w\"><\/span>\n<span class=\"w\">        <\/span><span class=\"k\">for<\/span><span class=\"w\"> <\/span><span class=\"n\">i<\/span><span class=\"w\"> <\/span><span class=\"k\">in<\/span><span class=\"w\"> <\/span><span class=\"mi\">0<\/span><span class=\"p\">..<\/span><span class=\"mi\">4<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"><\/span>\n<span class=\"w\">            <\/span><span class=\"kd\">let<\/span><span class=\"w\"> <\/span><span class=\"n\">idx<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"mi\">2<\/span><span class=\"w\"> <\/span><span class=\"o\">*<\/span><span class=\"w\"> <\/span><span class=\"n\">i<\/span><span class=\"p\">;<\/span><span class=\"w\"><\/span>\n<span class=\"w\">            <\/span><span class=\"kd\">let<\/span><span class=\"w\"> <\/span><span class=\"n\">m0<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"n\">a<\/span><span class=\"p\">[<\/span><span class=\"n\">idx<\/span><span class=\"p\">]<\/span><span class=\"w\"> <\/span><span class=\"k\">as<\/span><span class=\"w\"> <\/span><span class=\"kt\">i32<\/span><span class=\"w\"> <\/span><span class=\"o\">*<\/span><span class=\"w\"> <\/span><span class=\"n\">b<\/span><span class=\"p\">[<\/span><span class=\"n\">idx<\/span><span class=\"p\">]<\/span><span class=\"w\"> <\/span><span class=\"k\">as<\/span><span class=\"w\"> <\/span><span class=\"kt\">i32<\/span><span class=\"p\">;<\/span><span class=\"w\"><\/span>\n<span class=\"w\">            <\/span><span class=\"kd\">let<\/span><span class=\"w\"> <\/span><span class=\"n\">m1<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"n\">a<\/span><span class=\"p\">[<\/span><span class=\"n\">idx<\/span><span class=\"w\"> <\/span><span class=\"o\">+<\/span><span class=\"w\"> <\/span><span class=\"mi\">1<\/span><span class=\"p\">]<\/span><span class=\"w\"> <\/span><span class=\"k\">as<\/span><span class=\"w\"> <\/span><span class=\"kt\">i32<\/span><span class=\"w\"> <\/span><span class=\"o\">*<\/span><span class=\"w\"> <\/span><span class=\"n\">b<\/span><span class=\"p\">[<\/span><span class=\"n\">idx<\/span><span class=\"w\"> <\/span><span class=\"o\">+<\/span><span class=\"w\"> <\/span><span class=\"mi\">1<\/span><span class=\"p\">]<\/span><span class=\"w\"> <\/span><span class=\"k\">as<\/span><span class=\"w\"> <\/span><span class=\"kt\">i32<\/span><span class=\"p\">;<\/span><span class=\"w\"><\/span>\n<span class=\"w\">            <\/span><span class=\"n\">d<\/span><span class=\"p\">[<\/span><span class=\"n\">i<\/span><span class=\"p\">]<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"n\">c<\/span><span class=\"p\">[<\/span><span class=\"n\">i<\/span><span class=\"p\">].<\/span><span class=\"n\">saturating_add<\/span><span class=\"p\">(<\/span><span class=\"n\">m0<\/span><span class=\"p\">).<\/span><span class=\"n\">saturating_add<\/span><span class=\"p\">(<\/span><span class=\"n\">m1<\/span><span class=\"p\">);<\/span><span class=\"w\"><\/span>\n<span class=\"w\">        <\/span><span class=\"p\">}<\/span><span class=\"w\"><\/span>\n<span class=\"w\">        <\/span><span class=\"n\">d<\/span><span class=\"w\"><\/span>\n<span class=\"w\">    <\/span><span class=\"p\">}<\/span><span class=\"w\"><\/span>\n\n<span class=\"w\">    <\/span><span class=\"k\">fn<\/span> <span class=\"nf\">vmsumuhs<\/span><span class=\"p\">(<\/span><span class=\"n\">a<\/span>: <span class=\"nc\">u16x8<\/span><span class=\"p\">,<\/span><span class=\"w\"> <\/span><span class=\"n\">b<\/span>: <span class=\"nc\">u16x8<\/span><span class=\"p\">,<\/span><span class=\"w\"> <\/span><span class=\"n\">c<\/span>: <span class=\"nc\">u32x4<\/span><span class=\"p\">)<\/span><span class=\"w\"> <\/span>-&gt; <span class=\"nc\">u32x4<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"><\/span>\n<span class=\"w\">        <\/span><span class=\"kd\">let<\/span><span class=\"w\"> <\/span><span class=\"n\">d<\/span><span class=\"p\">;<\/span><span class=\"w\"><\/span>\n<span class=\"w\">        <\/span><span class=\"k\">for<\/span><span class=\"w\"> <\/span><span class=\"n\">i<\/span><span class=\"w\"> <\/span><span class=\"k\">in<\/span><span class=\"w\"> <\/span><span class=\"mi\">0<\/span><span class=\"p\">..<\/span><span class=\"mi\">4<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"><\/span>\n<span class=\"w\">            <\/span><span class=\"kd\">let<\/span><span class=\"w\"> <\/span><span class=\"n\">idx<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"mi\">2<\/span><span class=\"w\"> <\/span><span class=\"o\">*<\/span><span class=\"w\"> <\/span><span class=\"n\">i<\/span><span class=\"p\">;<\/span><span class=\"w\"><\/span>\n<span class=\"w\">            <\/span><span class=\"kd\">let<\/span><span class=\"w\"> <\/span><span class=\"n\">m0<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"n\">a<\/span><span class=\"p\">[<\/span><span class=\"n\">idx<\/span><span class=\"p\">]<\/span><span class=\"w\"> <\/span><span class=\"k\">as<\/span><span class=\"w\"> <\/span><span class=\"kt\">u32<\/span><span class=\"w\"> <\/span><span class=\"o\">*<\/span><span class=\"w\"> <\/span><span class=\"n\">b<\/span><span class=\"p\">[<\/span><span class=\"n\">idx<\/span><span class=\"p\">]<\/span><span class=\"w\"> <\/span><span class=\"k\">as<\/span><span class=\"w\"> <\/span><span class=\"kt\">u32<\/span><span class=\"p\">;<\/span><span class=\"w\"><\/span>\n<span class=\"w\">            <\/span><span class=\"kd\">let<\/span><span class=\"w\"> <\/span><span class=\"n\">m1<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"n\">a<\/span><span class=\"p\">[<\/span><span class=\"n\">idx<\/span><span class=\"w\"> <\/span><span class=\"o\">+<\/span><span class=\"w\"> <\/span><span class=\"mi\">1<\/span><span class=\"p\">]<\/span><span class=\"w\"> <\/span><span class=\"k\">as<\/span><span class=\"w\"> <\/span><span class=\"kt\">u32<\/span><span class=\"w\"> <\/span><span class=\"o\">*<\/span><span class=\"w\"> <\/span><span class=\"n\">b<\/span><span class=\"p\">[<\/span><span class=\"n\">idx<\/span><span class=\"w\"> <\/span><span class=\"o\">+<\/span><span class=\"w\"> <\/span><span class=\"mi\">1<\/span><span class=\"p\">]<\/span><span class=\"w\"> <\/span><span class=\"k\">as<\/span><span class=\"w\"> <\/span><span class=\"kt\">u32<\/span><span class=\"p\">;<\/span><span class=\"w\"><\/span>\n<span class=\"w\">            <\/span><span class=\"n\">d<\/span><span class=\"p\">[<\/span><span class=\"n\">i<\/span><span class=\"p\">]<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"n\">c<\/span><span class=\"p\">[<\/span><span class=\"n\">i<\/span><span class=\"p\">].<\/span><span class=\"n\">saturating_add<\/span><span class=\"p\">(<\/span><span class=\"n\">m0<\/span><span class=\"p\">).<\/span><span class=\"n\">saturating_add<\/span><span class=\"p\">(<\/span><span class=\"n\">m1<\/span><span class=\"p\">);<\/span><span class=\"w\"><\/span>\n<span class=\"w\">        <\/span><span class=\"p\">}<\/span><span class=\"w\"><\/span>\n<span class=\"w\">        <\/span><span class=\"n\">d<\/span><span class=\"w\"><\/span>\n<span class=\"w\">    <\/span><span class=\"p\">}<\/span><span class=\"w\"><\/span>\n\n<span class=\"w\">    <\/span><span class=\"p\">...<\/span><span class=\"w\"><\/span>\n\n<span class=\"w\">    <\/span><span class=\"k\">fn<\/span> <span class=\"nf\">vec_msums<\/span><span class=\"o\">&lt;<\/span><span class=\"n\">T<\/span><span class=\"p\">,<\/span><span class=\"w\"> <\/span><span class=\"n\">U<\/span><span class=\"o\">&gt;<\/span><span class=\"p\">(<\/span><span class=\"n\">a<\/span>: <span class=\"nc\">T<\/span><span class=\"p\">,<\/span><span class=\"w\"> <\/span><span class=\"n\">b<\/span>: <span class=\"nc\">T<\/span><span class=\"p\">,<\/span><span class=\"w\"> <\/span><span class=\"n\">c<\/span>: <span class=\"nc\">U<\/span><span class=\"p\">)<\/span><span class=\"w\"> <\/span>-&gt; <span class=\"nc\">U<\/span><span class=\"w\"><\/span>\n<span class=\"w\">    <\/span><span class=\"k\">where<\/span><span class=\"w\"> <\/span><span class=\"n\">T<\/span>: <span class=\"nc\">sealed<\/span>::<span class=\"n\">VectorMultiplySumSaturate<\/span><span class=\"o\">&lt;<\/span><span class=\"n\">U<\/span><span class=\"o\">&gt;<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"><\/span>\n<span class=\"w\">        <\/span><span class=\"n\">a<\/span><span class=\"p\">.<\/span><span class=\"n\">msums<\/span><span class=\"p\">(<\/span><span class=\"n\">b<\/span><span class=\"p\">,<\/span><span class=\"w\"> <\/span><span class=\"n\">c<\/span><span class=\"p\">)<\/span><span class=\"w\"><\/span>\n<span class=\"w\">    <\/span><span class=\"p\">}<\/span><span class=\"w\"><\/span>\n<\/pre>\n<\/div>\n<p>It works only with 16bit elements, signed or unsigned. In order to support that on rust we have to use some creative trait.<br \/>\nIt is quite neat if you have to implement some filters.<\/p>\n<h3><code>vec_madds<\/code>: Vector Multiply Add Saturated<\/h3>\n<div class=\"codehilite\">\n<pre><span><\/span><span class=\"w\">    <\/span><span class=\"k\">fn<\/span> <span class=\"nf\">vec_madds<\/span><span class=\"p\">(<\/span><span class=\"n\">a<\/span>: <span class=\"nc\">i16x8<\/span><span class=\"p\">,<\/span><span class=\"w\"> <\/span><span class=\"n\">b<\/span>: <span class=\"nc\">i16x8<\/span><span class=\"p\">,<\/span><span class=\"w\"> <\/span><span class=\"n\">c<\/span>: <span class=\"nc\">i16x8<\/span><span class=\"p\">)<\/span><span class=\"w\"> <\/span>-&gt; <span class=\"nc\">i16x8<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"><\/span>\n<span class=\"w\">        <\/span><span class=\"kd\">let<\/span><span class=\"w\"> <\/span><span class=\"n\">d<\/span><span class=\"p\">;<\/span><span class=\"w\"><\/span>\n<span class=\"w\">        <\/span><span class=\"k\">for<\/span><span class=\"w\"> <\/span><span class=\"n\">i<\/span><span class=\"w\"> <\/span><span class=\"k\">in<\/span><span class=\"w\"> <\/span><span class=\"mi\">0<\/span><span class=\"p\">..<\/span><span class=\"mi\">8<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"><\/span>\n<span class=\"w\">            <\/span><span class=\"kd\">let<\/span><span class=\"w\"> <\/span><span class=\"n\">v<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"n\">a<\/span><span class=\"p\">[<\/span><span class=\"n\">i<\/span><span class=\"p\">]<\/span><span class=\"w\"> <\/span><span class=\"k\">as<\/span><span class=\"w\"> <\/span><span class=\"kt\">i32<\/span><span class=\"w\"> <\/span><span class=\"o\">*<\/span><span class=\"w\"> <\/span><span class=\"n\">b<\/span><span class=\"p\">[<\/span><span class=\"n\">i<\/span><span class=\"p\">]<\/span><span class=\"w\"> <\/span><span class=\"k\">as<\/span><span class=\"w\"> <\/span><span class=\"kt\">i32<\/span><span class=\"p\">)<\/span><span class=\"w\"> <\/span><span class=\"o\">&gt;&gt;<\/span><span class=\"w\"> <\/span><span class=\"mi\">15<\/span><span class=\"p\">;<\/span><span class=\"w\"><\/span>\n<span class=\"w\">            <\/span><span class=\"n\">d<\/span><span class=\"p\">[<\/span><span class=\"n\">i<\/span><span class=\"p\">]<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"n\">v<\/span><span class=\"w\"> <\/span><span class=\"k\">as<\/span><span class=\"w\"> <\/span><span class=\"kt\">i16<\/span><span class=\"p\">).<\/span><span class=\"n\">saturating_add<\/span><span class=\"p\">(<\/span><span class=\"n\">c<\/span><span class=\"p\">[<\/span><span class=\"n\">i<\/span><span class=\"p\">]);<\/span><span class=\"w\"><\/span>\n<span class=\"w\">        <\/span><span class=\"p\">}<\/span><span class=\"w\"><\/span>\n<span class=\"w\">        <\/span><span class=\"n\">d<\/span><span class=\"w\"><\/span>\n<span class=\"w\">    <\/span><span class=\"p\">}<\/span><span class=\"w\"><\/span>\n<\/pre>\n<\/div>\n<p>Takes the high-order 17bit of the lane-wise product of the first two vectors and adds it to a third one.<\/p>\n<h2>Coming next<\/h2>\n<p><a href=\"https:\/\/raptorengineering.com\/\">Raptor Enginering<\/a> kindly gave me access to a <strong>Power 9<\/strong> through their <a href=\"https:\/\/http:\/\/integricloud.com\/\">Integricloud<\/a> hosting.<\/p>\n<p>We could run some extensive benchmarks and we found some peculiar behaviour with the C compilers available on the machine and that got me, <a href=\"https:\/\/medium.com\/@luc.trudeau\">Luc<\/a> and <a href=\"http:\/\/sasshkas.blogspot.com\/\">Alexandra<\/a> a little puzzled.<\/p>\n<p>Next time I&#8217;ll try to collect in a little more organic way what I randomly put on my <a href=\"https:\/\/twitter.com\/lu_zero_\">twitter<\/a> as I noticed it.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;m involved in implementing the Altivec and VSX support on rust stdsimd. Supporting all the instructions in this language is a HUGE endeavor since for each instruction at least 2 tests have to be written and making functions type-generic gets you to the point of having few pages of implementation (that luckily desugars to the &hellip; <a href=\"https:\/\/blogs.gentoo.org\/lu_zero\/2018\/07\/02\/altivec-and-vsx-in-rust-part-1\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Altivec and VSX in Rust (part 1)<\/span><\/a><\/p>\n","protected":false},"author":10,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"spay_email":"","jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true},"categories":[24],"tags":[30,31,29],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p1aGWH-aW","_links":{"self":[{"href":"https:\/\/blogs.gentoo.org\/lu_zero\/wp-json\/wp\/v2\/posts\/678"}],"collection":[{"href":"https:\/\/blogs.gentoo.org\/lu_zero\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.gentoo.org\/lu_zero\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.gentoo.org\/lu_zero\/wp-json\/wp\/v2\/users\/10"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.gentoo.org\/lu_zero\/wp-json\/wp\/v2\/comments?post=678"}],"version-history":[{"count":2,"href":"https:\/\/blogs.gentoo.org\/lu_zero\/wp-json\/wp\/v2\/posts\/678\/revisions"}],"predecessor-version":[{"id":680,"href":"https:\/\/blogs.gentoo.org\/lu_zero\/wp-json\/wp\/v2\/posts\/678\/revisions\/680"}],"wp:attachment":[{"href":"https:\/\/blogs.gentoo.org\/lu_zero\/wp-json\/wp\/v2\/media?parent=678"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.gentoo.org\/lu_zero\/wp-json\/wp\/v2\/categories?post=678"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.gentoo.org\/lu_zero\/wp-json\/wp\/v2\/tags?post=678"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}