https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118480

--- Comment #7 from Jeevitha <jeevitha at gcc dot gnu.org> ---
Now, in the following case, we run into issues whenever we use a splat constant
with vec_slo or vec_sll:

vui128_t
test_slqi_char_15_V1 (vui128_t vra)
{
  vui8_t result;
  vui8_t tmp = vec_splats((unsigned char)15);
  result = vec_slo ((vui8_t)vra, tmp);
  return (vui128_t) vec_vsl (result, tmp);
}

Generated assembly:

test_slqi_char_15_V1:
    vspltisb 0,15
    vslo 2,2,0
    vsl 2,2,0
    blr

If you look at the final RTL, you’ll notice that the vspltisb has mode V4SI
instead of  V16QI for a char splat:

(insn:TI 6 9 7 (set (reg:V4SI 64 %v0 [122])
      (const_vector:V4SI [
          (const_int 252645135 [0xf0f0f0f]) repeated x4
      ])) "t4.c":14:12 1194 {vsx_movv4si_64bit}
   (expr_list:REG_EQUIV (const_vector:V4SI [
          (const_int 252645135 [0xf0f0f0f]) repeated x4
      ])
      (nil)))
vspltisb %v0,15   # 6  [c=20 l=20]  vsx_movv4si_64bit/15

This happens because vec_slo/vec_sll internally expect operands of type vsi
(vector signed int). So before calling __builtin_altivec_vslo, the tmp is
implicitly converted to an integer vector type.

Here's the Gimple data:


vui8_t tmp;
vui32_t result;
vector(4) int _1;
vector(4) int _2;
vector(4) int _3;
vector(4) int _4;
vector(4) int _5;
vector(4) int _6;
vui128_t _10;

<bb 2> :
tmp_7 = { 15, 15, ..., 15 };  // 16 elements
_1 = VIEW_CONVERT_EXPR<__vector signed int>(vra_8(D));
_2 = VIEW_CONVERT_EXPR<__vector signed int>(tmp_7);
_3 = __builtin_altivec_vslo(_1, _2);
result_9 = VIEW_CONVERT_EXPR<vui32_t>(_3);
_4 = VIEW_CONVERT_EXPR<__vector signed int>(result_9);
_5 = VIEW_CONVERT_EXPR<__vector signed int>(tmp_7);
_6 = __builtin_altivec_vsl(_4, _5);
_10 = VIEW_CONVERT_EXPR<vui128_t>(_6);
return _10;

This behavior occurs due to how we define the built-in function?. The
definition for __builtin_altivec_vslo in rs6000-builtins.def is:

const vsi __builtin_altivec_vslo (vsi, vsi);
  VSLO altivec_vslo {}

And the corresponding instruction definition in altivec.md:

(define_insn "altivec_vslo"
  [(set (match_operand:V4SI 0 "register_operand" "=v")
        (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "v")
                      (match_operand:V4SI 2 "register_operand" "v")]
                     UNSPEC_VSLO))]
  "TARGET_ALTIVEC"
  "vslo %0,%1,%2"
  [(set_attr "type" "vecperm")])

Although there are overloaded built-in forms that allow vec_slo to accept
vui8_t or other types:

vsc __builtin_vec_slo(vsc, vsc);   // VSLO_VSCS
vsc __builtin_vec_slo(vsc, vuc);   // VSLO_VSCU
...
vsi __builtin_vec_slo(vsi, vsc);   // VSLO_VSIS
vui __builtin_vec_slo(vui, vuc);   // VSLO_VUIU
...

Points to note:

Although we have many vector types, why are we defaulting to V4SI?

Even though it's being lowered to V4SI, how is vspltis* getting generated? I
found that in output_vec_const_move, we have special handling for this—but not
for xxsplti*.

Reply via email to