+ case RS6000_BIF_VSUBUBM:
+ case RS6000_BIF_VSUBUHM:
+ case RS6000_BIF_VSUBUWM:
+ case RS6000_BIF_VSUBUDM:
+ case RS6000_BIF_VSUBFP:
+ case RS6000_BIF_XVSUBDP:
+ case RS6000_BIF_XVSUBSP:
+ bcode = MINUS_EXPR;
+ goto do_binary;
+ case RS6000_BIF_XVMULSP:
+ case RS6000_BIF_XVMULDP:
+ arg0 = gimple_call_arg (stmt, 0);
+ arg1 = gimple_call_arg (stmt, 1);
+ lhs = gimple_call_lhs (stmt);
+ g = gimple_build_assign (lhs, MULT_EXPR, arg0, arg1);
+ gimple_set_location (g, gimple_location (stmt));
+ gsi_replace (gsi, g, true);
+ return true;
+ /* Even element flavors of vec_mul (signed). */
+ case RS6000_BIF_VMULESB:
+ case RS6000_BIF_VMULESH:
+ case RS6000_BIF_VMULESW:
+ /* Even element flavors of vec_mul (unsigned). */
+ case RS6000_BIF_VMULEUB:
+ case RS6000_BIF_VMULEUH:
+ case RS6000_BIF_VMULEUW:
+ arg0 = gimple_call_arg (stmt, 0);
+ arg1 = gimple_call_arg (stmt, 1);
+ lhs = gimple_call_lhs (stmt);
+ g = gimple_build_assign (lhs, VEC_WIDEN_MULT_EVEN_EXPR, arg0, arg1);
+ gimple_set_location (g, gimple_location (stmt));
+ gsi_replace (gsi, g, true);
+ return true;
+ /* Odd element flavors of vec_mul (signed). */
+ case RS6000_BIF_VMULOSB:
+ case RS6000_BIF_VMULOSH:
+ case RS6000_BIF_VMULOSW:
+ /* Odd element flavors of vec_mul (unsigned). */
+ case RS6000_BIF_VMULOUB:
+ case RS6000_BIF_VMULOUH:
+ case RS6000_BIF_VMULOUW:
+ arg0 = gimple_call_arg (stmt, 0);
+ arg1 = gimple_call_arg (stmt, 1);
+ lhs = gimple_call_lhs (stmt);
+ g = gimple_build_assign (lhs, VEC_WIDEN_MULT_ODD_EXPR, arg0, arg1);
+ gimple_set_location (g, gimple_location (stmt));
+ gsi_replace (gsi, g, true);
+ return true;
+ /* Flavors of vec_div (Integer). */
+ case RS6000_BIF_DIV_V2DI:
+ case RS6000_BIF_UDIV_V2DI:
+ arg0 = gimple_call_arg (stmt, 0);
+ arg1 = gimple_call_arg (stmt, 1);
+ lhs = gimple_call_lhs (stmt);
+ g = gimple_build_assign (lhs, TRUNC_DIV_EXPR, arg0, arg1);
+ gimple_set_location (g, gimple_location (stmt));
+ gsi_replace (gsi, g, true);
+ return true;
+ /* Flavors of vec_div (Float). */
+ case RS6000_BIF_XVDIVSP:
+ case RS6000_BIF_XVDIVDP:
+ arg0 = gimple_call_arg (stmt, 0);
+ arg1 = gimple_call_arg (stmt, 1);
+ lhs = gimple_call_lhs (stmt);
+ g = gimple_build_assign (lhs, RDIV_EXPR, arg0, arg1);
+ gimple_set_location (g, gimple_location (stmt));
+ gsi_replace (gsi, g, true);
+ return true;
+ /* Flavors of vec_and. */
+ case RS6000_BIF_VAND_V16QI_UNS:
+ case RS6000_BIF_VAND_V16QI:
+ case RS6000_BIF_VAND_V8HI_UNS:
+ case RS6000_BIF_VAND_V8HI:
+ case RS6000_BIF_VAND_V4SI_UNS:
+ case RS6000_BIF_VAND_V4SI:
+ case RS6000_BIF_VAND_V2DI_UNS:
+ case RS6000_BIF_VAND_V2DI:
+ case RS6000_BIF_VAND_V4SF:
+ case RS6000_BIF_VAND_V2DF:
+ arg0 = gimple_call_arg (stmt, 0);
+ arg1 = gimple_call_arg (stmt, 1);
+ lhs = gimple_call_lhs (stmt);
+ g = gimple_build_assign (lhs, BIT_AND_EXPR, arg0, arg1);
+ gimple_set_location (g, gimple_location (stmt));
+ gsi_replace (gsi, g, true);
+ return true;
+ /* Flavors of vec_andc. */
+ case RS6000_BIF_VANDC_V16QI_UNS:
+ case RS6000_BIF_VANDC_V16QI:
+ case RS6000_BIF_VANDC_V8HI_UNS:
+ case RS6000_BIF_VANDC_V8HI:
+ case RS6000_BIF_VANDC_V4SI_UNS:
+ case RS6000_BIF_VANDC_V4SI:
+ case RS6000_BIF_VANDC_V2DI_UNS:
+ case RS6000_BIF_VANDC_V2DI:
+ case RS6000_BIF_VANDC_V4SF:
+ case RS6000_BIF_VANDC_V2DF:
+ arg0 = gimple_call_arg (stmt, 0);
+ arg1 = gimple_call_arg (stmt, 1);
+ lhs = gimple_call_lhs (stmt);
+ temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1));
+ g = gimple_build_assign (temp, BIT_NOT_EXPR, arg1);
+ gimple_set_location (g, gimple_location (stmt));
+ gsi_insert_before (gsi, g, GSI_SAME_STMT);
+ g = gimple_build_assign (lhs, BIT_AND_EXPR, arg0, temp);
+ gimple_set_location (g, gimple_location (stmt));
+ gsi_replace (gsi, g, true);
+ return true;
+ /* Flavors of vec_nand. */
+ case RS6000_BIF_NAND_V16QI_UNS:
+ case RS6000_BIF_NAND_V16QI:
+ case RS6000_BIF_NAND_V8HI_UNS:
+ case RS6000_BIF_NAND_V8HI:
+ case RS6000_BIF_NAND_V4SI_UNS:
+ case RS6000_BIF_NAND_V4SI:
+ case RS6000_BIF_NAND_V2DI_UNS:
+ case RS6000_BIF_NAND_V2DI:
+ case RS6000_BIF_NAND_V4SF:
+ case RS6000_BIF_NAND_V2DF:
+ arg0 = gimple_call_arg (stmt, 0);
+ arg1 = gimple_call_arg (stmt, 1);
+ lhs = gimple_call_lhs (stmt);
+ temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1));
+ g = gimple_build_assign (temp, BIT_AND_EXPR, arg0, arg1);
+ gimple_set_location (g, gimple_location (stmt));
+ gsi_insert_before (gsi, g, GSI_SAME_STMT);
+ g = gimple_build_assign (lhs, BIT_NOT_EXPR, temp);
+ gimple_set_location (g, gimple_location (stmt));
+ gsi_replace (gsi, g, true);
+ return true;
+ /* Flavors of vec_or. */
+ case RS6000_BIF_VOR_V16QI_UNS:
+ case RS6000_BIF_VOR_V16QI:
+ case RS6000_BIF_VOR_V8HI_UNS:
+ case RS6000_BIF_VOR_V8HI:
+ case RS6000_BIF_VOR_V4SI_UNS:
+ case RS6000_BIF_VOR_V4SI:
+ case RS6000_BIF_VOR_V2DI_UNS:
+ case RS6000_BIF_VOR_V2DI:
+ case RS6000_BIF_VOR_V4SF:
+ case RS6000_BIF_VOR_V2DF:
+ arg0 = gimple_call_arg (stmt, 0);
+ arg1 = gimple_call_arg (stmt, 1);
+ lhs = gimple_call_lhs (stmt);
+ g = gimple_build_assign (lhs, BIT_IOR_EXPR, arg0, arg1);
+ gimple_set_location (g, gimple_location (stmt));
+ gsi_replace (gsi, g, true);
+ return true;
+ /* flavors of vec_orc. */
+ case RS6000_BIF_ORC_V16QI_UNS:
+ case RS6000_BIF_ORC_V16QI:
+ case RS6000_BIF_ORC_V8HI_UNS:
+ case RS6000_BIF_ORC_V8HI:
+ case RS6000_BIF_ORC_V4SI_UNS:
+ case RS6000_BIF_ORC_V4SI:
+ case RS6000_BIF_ORC_V2DI_UNS:
+ case RS6000_BIF_ORC_V2DI:
+ case RS6000_BIF_ORC_V4SF:
+ case RS6000_BIF_ORC_V2DF:
+ arg0 = gimple_call_arg (stmt, 0);
+ arg1 = gimple_call_arg (stmt, 1);
+ lhs = gimple_call_lhs (stmt);
+ temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1));
+ g = gimple_build_assign (temp, BIT_NOT_EXPR, arg1);
+ gimple_set_location (g, gimple_location (stmt));
+ gsi_insert_before (gsi, g, GSI_SAME_STMT);
+ g = gimple_build_assign (lhs, BIT_IOR_EXPR, arg0, temp);
+ gimple_set_location (g, gimple_location (stmt));
+ gsi_replace (gsi, g, true);
+ return true;
+ /* Flavors of vec_xor. */
+ case RS6000_BIF_VXOR_V16QI_UNS:
+ case RS6000_BIF_VXOR_V16QI:
+ case RS6000_BIF_VXOR_V8HI_UNS:
+ case RS6000_BIF_VXOR_V8HI:
+ case RS6000_BIF_VXOR_V4SI_UNS:
+ case RS6000_BIF_VXOR_V4SI:
+ case RS6000_BIF_VXOR_V2DI_UNS:
+ case RS6000_BIF_VXOR_V2DI:
+ case RS6000_BIF_VXOR_V4SF:
+ case RS6000_BIF_VXOR_V2DF:
+ arg0 = gimple_call_arg (stmt, 0);
+ arg1 = gimple_call_arg (stmt, 1);
+ lhs = gimple_call_lhs (stmt);
+ g = gimple_build_assign (lhs, BIT_XOR_EXPR, arg0, arg1);
+ gimple_set_location (g, gimple_location (stmt));
+ gsi_replace (gsi, g, true);
+ return true;
+ /* Flavors of vec_nor. */
+ case RS6000_BIF_VNOR_V16QI_UNS:
+ case RS6000_BIF_VNOR_V16QI:
+ case RS6000_BIF_VNOR_V8HI_UNS:
+ case RS6000_BIF_VNOR_V8HI:
+ case RS6000_BIF_VNOR_V4SI_UNS:
+ case RS6000_BIF_VNOR_V4SI:
+ case RS6000_BIF_VNOR_V2DI_UNS:
+ case RS6000_BIF_VNOR_V2DI:
+ case RS6000_BIF_VNOR_V4SF:
+ case RS6000_BIF_VNOR_V2DF:
+ arg0 = gimple_call_arg (stmt, 0);
+ arg1 = gimple_call_arg (stmt, 1);
+ lhs = gimple_call_lhs (stmt);
+ temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1));
+ g = gimple_build_assign (temp, BIT_IOR_EXPR, arg0, arg1);
+ gimple_set_location (g, gimple_location (stmt));
+ gsi_insert_before (gsi, g, GSI_SAME_STMT);
+ g = gimple_build_assign (lhs, BIT_NOT_EXPR, temp);
+ gimple_set_location (g, gimple_location (stmt));
+ gsi_replace (gsi, g, true);
+ return true;
+ /* flavors of vec_abs. */
+ case RS6000_BIF_ABS_V16QI:
+ case RS6000_BIF_ABS_V8HI:
+ case RS6000_BIF_ABS_V4SI:
+ case RS6000_BIF_ABS_V4SF:
+ case RS6000_BIF_ABS_V2DI:
+ case RS6000_BIF_XVABSDP:
+ case RS6000_BIF_XVABSSP:
+ arg0 = gimple_call_arg (stmt, 0);
+ if (INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (arg0)))
+ && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (TREE_TYPE (arg0))))
+ return false;
+ lhs = gimple_call_lhs (stmt);
+ g = gimple_build_assign (lhs, ABS_EXPR, arg0);
+ gimple_set_location (g, gimple_location (stmt));
+ gsi_replace (gsi, g, true);
+ return true;
+ /* flavors of vec_min. */
+ case RS6000_BIF_XVMINDP:
+ case RS6000_BIF_XVMINSP:
+ case RS6000_BIF_VMINSD:
+ case RS6000_BIF_VMINUD:
+ case RS6000_BIF_VMINSB:
+ case RS6000_BIF_VMINSH:
+ case RS6000_BIF_VMINSW:
+ case RS6000_BIF_VMINUB:
+ case RS6000_BIF_VMINUH:
+ case RS6000_BIF_VMINUW:
+ case RS6000_BIF_VMINFP:
+ arg0 = gimple_call_arg (stmt, 0);
+ arg1 = gimple_call_arg (stmt, 1);
+ lhs = gimple_call_lhs (stmt);
+ g = gimple_build_assign (lhs, MIN_EXPR, arg0, arg1);
+ gimple_set_location (g, gimple_location (stmt));
+ gsi_replace (gsi, g, true);
+ return true;
+ /* flavors of vec_max. */
+ case RS6000_BIF_XVMAXDP:
+ case RS6000_BIF_XVMAXSP:
+ case RS6000_BIF_VMAXSD:
+ case RS6000_BIF_VMAXUD:
+ case RS6000_BIF_VMAXSB:
+ case RS6000_BIF_VMAXSH:
+ case RS6000_BIF_VMAXSW:
+ case RS6000_BIF_VMAXUB:
+ case RS6000_BIF_VMAXUH:
+ case RS6000_BIF_VMAXUW:
+ case RS6000_BIF_VMAXFP:
+ arg0 = gimple_call_arg (stmt, 0);
+ arg1 = gimple_call_arg (stmt, 1);
+ lhs = gimple_call_lhs (stmt);
+ g = gimple_build_assign (lhs, MAX_EXPR, arg0, arg1);
+ gimple_set_location (g, gimple_location (stmt));
+ gsi_replace (gsi, g, true);
+ return true;
+ /* Flavors of vec_eqv. */
+ case RS6000_BIF_EQV_V16QI:
+ case RS6000_BIF_EQV_V8HI:
+ case RS6000_BIF_EQV_V4SI:
+ case RS6000_BIF_EQV_V4SF:
+ case RS6000_BIF_EQV_V2DF:
+ case RS6000_BIF_EQV_V2DI:
+ arg0 = gimple_call_arg (stmt, 0);
+ arg1 = gimple_call_arg (stmt, 1);
+ lhs = gimple_call_lhs (stmt);
+ temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1));
+ g = gimple_build_assign (temp, BIT_XOR_EXPR, arg0, arg1);
+ gimple_set_location (g, gimple_location (stmt));
+ gsi_insert_before (gsi, g, GSI_SAME_STMT);
+ g = gimple_build_assign (lhs, BIT_NOT_EXPR, temp);
+ gimple_set_location (g, gimple_location (stmt));
+ gsi_replace (gsi, g, true);
+ return true;
+ /* Flavors of vec_rotate_left. */
+ case RS6000_BIF_VRLB:
+ case RS6000_BIF_VRLH:
+ case RS6000_BIF_VRLW:
+ case RS6000_BIF_VRLD:
+ arg0 = gimple_call_arg (stmt, 0);
+ arg1 = gimple_call_arg (stmt, 1);
+ lhs = gimple_call_lhs (stmt);
+ g = gimple_build_assign (lhs, LROTATE_EXPR, arg0, arg1);
+ gimple_set_location (g, gimple_location (stmt));
+ gsi_replace (gsi, g, true);
+ return true;
+ /* Flavors of vector shift right algebraic.
+ vec_sra{b,h,w} -> vsra{b,h,w}. */
+ case RS6000_BIF_VSRAB:
+ case RS6000_BIF_VSRAH:
+ case RS6000_BIF_VSRAW:
+ case RS6000_BIF_VSRAD:
+ {
+ arg0 = gimple_call_arg (stmt, 0);
+ arg1 = gimple_call_arg (stmt, 1);
+ lhs = gimple_call_lhs (stmt);
+ tree arg1_type = TREE_TYPE (arg1);
+ tree unsigned_arg1_type = unsigned_type_for (TREE_TYPE (arg1));
+ tree unsigned_element_type = unsigned_type_for (TREE_TYPE (arg1_type));
+ location_t loc = gimple_location (stmt);
+ /* Force arg1 into the range valid matching the arg0 type. */
+ /* Build a vector consisting of the max valid bit-size values. */
+ int n_elts = VECTOR_CST_NELTS (arg1);
+ tree element_size = build_int_cst (unsigned_element_type,
+ 128 / n_elts);
+ tree_vector_builder elts (unsigned_arg1_type, n_elts, 1);
+ for (int i = 0; i < n_elts; i++)
+ elts.safe_push (element_size);
+ tree modulo_tree = elts.build ();
+ /* Modulo the provided shift value against that vector. */
+ gimple_seq stmts = NULL;
+ tree unsigned_arg1 = gimple_build (&stmts, VIEW_CONVERT_EXPR,
+ unsigned_arg1_type, arg1);
+ tree new_arg1 = gimple_build (&stmts, loc, TRUNC_MOD_EXPR,
+ unsigned_arg1_type, unsigned_arg1,
+ modulo_tree);
+ gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
+ /* And finally, do the shift. */
+ g = gimple_build_assign (lhs, RSHIFT_EXPR, arg0, new_arg1);
+ gimple_set_location (g, loc);
+ gsi_replace (gsi, g, true);
+ return true;
+ }
+ /* Flavors of vector shift left.
+ builtin_altivec_vsl{b,h,w} -> vsl{b,h,w}. */
+ case RS6000_BIF_VSLB:
+ case RS6000_BIF_VSLH:
+ case RS6000_BIF_VSLW:
+ case RS6000_BIF_VSLD:
+ {
+ location_t loc;
+ gimple_seq stmts = NULL;
+ arg0 = gimple_call_arg (stmt, 0);
+ tree arg0_type = TREE_TYPE (arg0);
+ if (INTEGRAL_TYPE_P (TREE_TYPE (arg0_type))
+ && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg0_type)))
+ return false;
+ arg1 = gimple_call_arg (stmt, 1);
+ tree arg1_type = TREE_TYPE (arg1);
+ tree unsigned_arg1_type = unsigned_type_for (TREE_TYPE (arg1));
+ tree unsigned_element_type = unsigned_type_for (TREE_TYPE (arg1_type));
+ loc = gimple_location (stmt);
+ lhs = gimple_call_lhs (stmt);
+ /* Force arg1 into the range valid matching the arg0 type. */
+ /* Build a vector consisting of the max valid bit-size values. */
+ int n_elts = VECTOR_CST_NELTS (arg1);
+ int tree_size_in_bits = TREE_INT_CST_LOW (size_in_bytes (arg1_type))
+ * BITS_PER_UNIT;
+ tree element_size = build_int_cst (unsigned_element_type,
+ tree_size_in_bits / n_elts);
+ tree_vector_builder elts (unsigned_type_for (arg1_type), n_elts, 1);
+ for (int i = 0; i < n_elts; i++)
+ elts.safe_push (element_size);
+ tree modulo_tree = elts.build ();
+ /* Modulo the provided shift value against that vector. */
+ tree unsigned_arg1 = gimple_build (&stmts, VIEW_CONVERT_EXPR,
+ unsigned_arg1_type, arg1);
+ tree new_arg1 = gimple_build (&stmts, loc, TRUNC_MOD_EXPR,
+ unsigned_arg1_type, unsigned_arg1,
+ modulo_tree);
+ gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
+ /* And finally, do the shift. */
+ g = gimple_build_assign (lhs, LSHIFT_EXPR, arg0, new_arg1);
+ gimple_set_location (g, gimple_location (stmt));
+ gsi_replace (gsi, g, true);
+ return true;
+ }
+ /* Flavors of vector shift right. */
+ case RS6000_BIF_VSRB:
+ case RS6000_BIF_VSRH:
+ case RS6000_BIF_VSRW:
+ case RS6000_BIF_VSRD:
+ {
+ arg0 = gimple_call_arg (stmt, 0);
+ arg1 = gimple_call_arg (stmt, 1);
+ lhs = gimple_call_lhs (stmt);
+ tree arg1_type = TREE_TYPE (arg1);
+ tree unsigned_arg1_type = unsigned_type_for (TREE_TYPE (arg1));
+ tree unsigned_element_type = unsigned_type_for (TREE_TYPE (arg1_type));
+ location_t loc = gimple_location (stmt);
+ gimple_seq stmts = NULL;
+ /* Convert arg0 to unsigned. */
+ tree arg0_unsigned
+ = gimple_build (&stmts, VIEW_CONVERT_EXPR,
+ unsigned_type_for (TREE_TYPE (arg0)), arg0);
+ /* Force arg1 into the range valid matching the arg0 type. */
+ /* Build a vector consisting of the max valid bit-size values. */
+ int n_elts = VECTOR_CST_NELTS (arg1);
+ tree element_size = build_int_cst (unsigned_element_type,
+ 128 / n_elts);
+ tree_vector_builder elts (unsigned_arg1_type, n_elts, 1);
+ for (int i = 0; i < n_elts; i++)
+ elts.safe_push (element_size);
+ tree modulo_tree = elts.build ();
+ /* Modulo the provided shift value against that vector. */
+ tree unsigned_arg1 = gimple_build (&stmts, VIEW_CONVERT_EXPR,
+ unsigned_arg1_type, arg1);
+ tree new_arg1 = gimple_build (&stmts, loc, TRUNC_MOD_EXPR,
+ unsigned_arg1_type, unsigned_arg1,
+ modulo_tree);
+ /* Do the shift. */
+ tree res
+ = gimple_build (&stmts, RSHIFT_EXPR,
+ TREE_TYPE (arg0_unsigned), arg0_unsigned, new_arg1);
+ /* Convert result back to the lhs type. */
+ res = gimple_build (&stmts, VIEW_CONVERT_EXPR, TREE_TYPE (lhs), res);
+ gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
+ replace_call_with_value (gsi, res);
+ return true;
+ }
+ /* Vector loads. */
+ case RS6000_BIF_LVX_V16QI:
+ case RS6000_BIF_LVX_V8HI:
+ case RS6000_BIF_LVX_V4SI:
+ case RS6000_BIF_LVX_V4SF:
+ case RS6000_BIF_LVX_V2DI:
+ case RS6000_BIF_LVX_V2DF:
+ case RS6000_BIF_LVX_V1TI:
+ {
+ arg0 = gimple_call_arg (stmt, 0); // offset
+ arg1 = gimple_call_arg (stmt, 1); // address
+ lhs = gimple_call_lhs (stmt);
+ location_t loc = gimple_location (stmt);
+ /* Since arg1 may be cast to a different type, just use ptr_type_node
+ here instead of trying to enforce TBAA on pointer types. */
+ tree arg1_type = ptr_type_node;
+ tree lhs_type = TREE_TYPE (lhs);
+ /* POINTER_PLUS_EXPR wants the offset to be of type 'sizetype'. Create
+ the tree using the value from arg0. The resulting type will match
+ the type of arg1. */
+ gimple_seq stmts = NULL;
+ tree temp_offset = gimple_convert (&stmts, loc, sizetype, arg0);
+ tree temp_addr = gimple_build (&stmts, loc, POINTER_PLUS_EXPR,
+ arg1_type, arg1, temp_offset);
+ /* Mask off any lower bits from the address. */
+ tree aligned_addr = gimple_build (&stmts, loc, BIT_AND_EXPR,
+ arg1_type, temp_addr,
+ build_int_cst (arg1_type, -16));
+ gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
+ if (!is_gimple_mem_ref_addr (aligned_addr))
+ {
+ tree t = make_ssa_name (TREE_TYPE (aligned_addr));
+ gimple *g = gimple_build_assign (t, aligned_addr);
+ gsi_insert_before (gsi, g, GSI_SAME_STMT);
+ aligned_addr = t;
+ }
+ /* Use the build2 helper to set up the mem_ref. The MEM_REF could also
+ take an offset, but since we've already incorporated the offset
+ above, here we just pass in a zero. */
+ gimple *g
+ = gimple_build_assign (lhs, build2 (MEM_REF, lhs_type, aligned_addr,
+ build_int_cst (arg1_type, 0)));
+ gimple_set_location (g, loc);
+ gsi_replace (gsi, g, true);
+ return true;
+ }
+ /* Vector stores. */
+ case RS6000_BIF_STVX_V16QI:
+ case RS6000_BIF_STVX_V8HI:
+ case RS6000_BIF_STVX_V4SI:
+ case RS6000_BIF_STVX_V4SF:
+ case RS6000_BIF_STVX_V2DI:
+ case RS6000_BIF_STVX_V2DF:
+ {
+ arg0 = gimple_call_arg (stmt, 0); /* Value to be stored. */
+ arg1 = gimple_call_arg (stmt, 1); /* Offset. */
+ tree arg2 = gimple_call_arg (stmt, 2); /* Store-to address. */
+ location_t loc = gimple_location (stmt);
+ tree arg0_type = TREE_TYPE (arg0);
+ /* Use ptr_type_node (no TBAA) for the arg2_type.
+ FIXME: (Richard) "A proper fix would be to transition this type as
+ seen from the frontend to GIMPLE, for example in a similar way we
+ do for MEM_REFs by piggy-backing that on an extra argument, a
+ constant zero pointer of the alias pointer type to use (which would
+ also serve as a type indicator of the store itself). I'd use a
+ target specific internal function for this (not sure if we can have
+ those target specific, but I guess if it's folded away then that's
+ fine) and get away with the overload set." */
+ tree arg2_type = ptr_type_node;
+ /* POINTER_PLUS_EXPR wants the offset to be of type 'sizetype'. Create
+ the tree using the value from arg0. The resulting type will match
+ the type of arg2. */
+ gimple_seq stmts = NULL;
+ tree temp_offset = gimple_convert (&stmts, loc, sizetype, arg1);
+ tree temp_addr = gimple_build (&stmts, loc, POINTER_PLUS_EXPR,
+ arg2_type, arg2, temp_offset);
+ /* Mask off any lower bits from the address. */
+ tree aligned_addr = gimple_build (&stmts, loc, BIT_AND_EXPR,
+ arg2_type, temp_addr,
+ build_int_cst (arg2_type, -16));
+ gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
+ if (!is_gimple_mem_ref_addr (aligned_addr))
+ {
+ tree t = make_ssa_name (TREE_TYPE (aligned_addr));
+ gimple *g = gimple_build_assign (t, aligned_addr);
+ gsi_insert_before (gsi, g, GSI_SAME_STMT);
+ aligned_addr = t;
+ }
+ /* The desired gimple result should be similar to:
+ MEM[(__vector floatD.1407 *)_1] = vf1D.2697; */
+ gimple *g
+ = gimple_build_assign (build2 (MEM_REF, arg0_type, aligned_addr,
+ build_int_cst (arg2_type, 0)), arg0);
+ gimple_set_location (g, loc);
+ gsi_replace (gsi, g, true);
+ return true;
+ }
+
+ /* unaligned Vector loads. */
+ case RS6000_BIF_LXVW4X_V16QI:
+ case RS6000_BIF_LXVW4X_V8HI:
+ case RS6000_BIF_LXVW4X_V4SF:
+ case RS6000_BIF_LXVW4X_V4SI:
+ case RS6000_BIF_LXVD2X_V2DF:
+ case RS6000_BIF_LXVD2X_V2DI:
+ {
+ arg0 = gimple_call_arg (stmt, 0); // offset
+ arg1 = gimple_call_arg (stmt, 1); // address
+ lhs = gimple_call_lhs (stmt);
+ location_t loc = gimple_location (stmt);
+ /* Since arg1 may be cast to a different type, just use ptr_type_node
+ here instead of trying to enforce TBAA on pointer types. */
+ tree arg1_type = ptr_type_node;
+ tree lhs_type = TREE_TYPE (lhs);
+ /* In GIMPLE the type of the MEM_REF specifies the alignment. The
+ required alignment (power) is 4 bytes regardless of data type. */
+ tree align_ltype = build_aligned_type (lhs_type, 4);
+ /* POINTER_PLUS_EXPR wants the offset to be of type 'sizetype'. Create
+ the tree using the value from arg0. The resulting type will match
+ the type of arg1. */
+ gimple_seq stmts = NULL;
+ tree temp_offset = gimple_convert (&stmts, loc, sizetype, arg0);
+ tree temp_addr = gimple_build (&stmts, loc, POINTER_PLUS_EXPR,
+ arg1_type, arg1, temp_offset);
+ gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
+ if (!is_gimple_mem_ref_addr (temp_addr))
+ {
+ tree t = make_ssa_name (TREE_TYPE (temp_addr));
+ gimple *g = gimple_build_assign (t, temp_addr);
+ gsi_insert_before (gsi, g, GSI_SAME_STMT);
+ temp_addr = t;
+ }
+ /* Use the build2 helper to set up the mem_ref. The MEM_REF could also
+ take an offset, but since we've already incorporated the offset
+ above, here we just pass in a zero. */
+ gimple *g;
+ g = gimple_build_assign (lhs, build2 (MEM_REF, align_ltype, temp_addr,
+ build_int_cst (arg1_type, 0)));
+ gimple_set_location (g, loc);
+ gsi_replace (gsi, g, true);
+ return true;
+ }
+
+ /* unaligned Vector stores. */
+ case RS6000_BIF_STXVW4X_V16QI:
+ case RS6000_BIF_STXVW4X_V8HI:
+ case RS6000_BIF_STXVW4X_V4SF:
+ case RS6000_BIF_STXVW4X_V4SI:
+ case RS6000_BIF_STXVD2X_V2DF:
+ case RS6000_BIF_STXVD2X_V2DI:
+ {
+ arg0 = gimple_call_arg (stmt, 0); /* Value to be stored. */
+ arg1 = gimple_call_arg (stmt, 1); /* Offset. */
+ tree arg2 = gimple_call_arg (stmt, 2); /* Store-to address. */
+ location_t loc = gimple_location (stmt);
+ tree arg0_type = TREE_TYPE (arg0);
+ /* Use ptr_type_node (no TBAA) for the arg2_type. */
+ tree arg2_type = ptr_type_node;
+ /* In GIMPLE the type of the MEM_REF specifies the alignment. The
+ required alignment (power) is 4 bytes regardless of data type. */
+ tree align_stype = build_aligned_type (arg0_type, 4);
+ /* POINTER_PLUS_EXPR wants the offset to be of type 'sizetype'. Create
+ the tree using the value from arg1. */
+ gimple_seq stmts = NULL;
+ tree temp_offset = gimple_convert (&stmts, loc, sizetype, arg1);
+ tree temp_addr = gimple_build (&stmts, loc, POINTER_PLUS_EXPR,
+ arg2_type, arg2, temp_offset);
+ gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
+ if (!is_gimple_mem_ref_addr (temp_addr))
+ {
+ tree t = make_ssa_name (TREE_TYPE (temp_addr));
+ gimple *g = gimple_build_assign (t, temp_addr);
+ gsi_insert_before (gsi, g, GSI_SAME_STMT);
+ temp_addr = t;
+ }
+ gimple *g;
+ g = gimple_build_assign (build2 (MEM_REF, align_stype, temp_addr,
+ build_int_cst (arg2_type, 0)), arg0);
+ gimple_set_location (g, loc);
+ gsi_replace (gsi, g, true);
+ return true;
+ }
+
+ /* Vector Fused multiply-add (fma). */
+ case RS6000_BIF_VMADDFP:
+ case RS6000_BIF_XVMADDDP:
+ case RS6000_BIF_XVMADDSP: