aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorXi Ruoyao <xry111@xry111.site>2023-07-06 23:08:57 +0800
committerXi Ruoyao <xry111@xry111.site>2023-07-10 18:34:38 +0800
commit63ae6bc60c0f67fb2791991bf4b6e7e0a907d420 (patch)
treeed267a90eeae0875f4eb7cbd9a2ec61faca7cb91 /gcc
parent12b78b0b42d53019eb2c500d386094194e90ad16 (diff)
downloadgcc-63ae6bc60c0f67fb2791991bf4b6e7e0a907d420.zip
gcc-63ae6bc60c0f67fb2791991bf4b6e7e0a907d420.tar.gz
gcc-63ae6bc60c0f67fb2791991bf4b6e7e0a907d420.tar.bz2
vect: Fix vectorized BIT_FIELD_REF for signed bit-fields [PR110557]
If a bit-field is signed and it's wider than the output type, we must ensure the extracted result sign-extended. But this was not handled correctly. For example: int x : 8; long y : 55; bool z : 1; The vectorized extraction of y was: vect__ifc__49.29_110 = MEM <vector(2) long unsigned int> [(struct Item *)vectp_a.27_108]; vect_patt_38.30_112 = vect__ifc__49.29_110 & { 9223372036854775552, 9223372036854775552 }; vect_patt_39.31_113 = vect_patt_38.30_112 >> 8; vect_patt_40.32_114 = VIEW_CONVERT_EXPR<vector(2) long int>(vect_patt_39.31_113); This is obviously incorrect. This pach has implemented it as: vect__ifc__25.16_62 = MEM <vector(2) long unsigned int> [(struct Item *)vectp_a.14_60]; vect_patt_31.17_63 = VIEW_CONVERT_EXPR<vector(2) long int>(vect__ifc__25.16_62); vect_patt_32.18_64 = vect_patt_31.17_63 << 1; vect_patt_33.19_65 = vect_patt_32.18_64 >> 9; gcc/ChangeLog: PR tree-optimization/110557 * tree-vect-patterns.cc (vect_recog_bitfield_ref_pattern): Ensure the output sign-extended if necessary. gcc/testsuite/ChangeLog: PR tree-optimization/110557 * g++.dg/vect/pr110557.cc: New test.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/testsuite/g++.dg/vect/pr110557.cc37
-rw-r--r--gcc/tree-vect-patterns.cc62
2 files changed, 83 insertions, 16 deletions
diff --git a/gcc/testsuite/g++.dg/vect/pr110557.cc b/gcc/testsuite/g++.dg/vect/pr110557.cc
new file mode 100644
index 0000000..e1fbe1c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/vect/pr110557.cc
@@ -0,0 +1,37 @@
+// { dg-additional-options "-mavx" { target { avx_runtime } } }
+
+static inline long
+min (long a, long b)
+{
+ return a < b ? a : b;
+}
+
+struct Item
+{
+ int x : 8;
+ long y : 55;
+ bool z : 1;
+};
+
+__attribute__ ((noipa)) long
+test (Item *a, int cnt)
+{
+ long size = 0;
+ for (int i = 0; i < cnt; i++)
+ size = min ((long)a[i].y, size);
+ return size;
+}
+
+int
+main ()
+{
+ struct Item items[] = {
+ { 1, -1 },
+ { 2, -2 },
+ { 3, -3 },
+ { 4, -4 },
+ };
+
+ if (test (items, 4) != -4)
+ __builtin_trap ();
+}
diff --git a/gcc/tree-vect-patterns.cc b/gcc/tree-vect-patterns.cc
index 1bc36b0..c0832e8 100644
--- a/gcc/tree-vect-patterns.cc
+++ b/gcc/tree-vect-patterns.cc
@@ -2566,7 +2566,7 @@ vect_recog_widen_sum_pattern (vec_info *vinfo,
Widening with mask first, shift later:
container = (type_out) container;
masked = container & (((1 << bitsize) - 1) << bitpos);
- result = patt2 >> masked;
+ result = masked >> bitpos;
Widening with shift first, mask last:
container = (type_out) container;
@@ -2578,6 +2578,15 @@ vect_recog_widen_sum_pattern (vec_info *vinfo,
result = masked >> bitpos;
result = (type_out) result;
+ If the bitfield is signed and it's wider than type_out, we need to
+ keep the result sign-extended:
+ container = (type) container;
+ masked = container << (prec - bitsize - bitpos);
+ result = (type_out) (masked >> (prec - bitsize));
+
+ Here type is the signed variant of the wider of type_out and the type
+ of container.
+
The shifting is always optional depending on whether bitpos != 0.
*/
@@ -2636,14 +2645,22 @@ vect_recog_bitfield_ref_pattern (vec_info *vinfo, stmt_vec_info stmt_info,
if (BYTES_BIG_ENDIAN)
shift_n = prec - shift_n - mask_width;
+ bool ref_sext = (!TYPE_UNSIGNED (TREE_TYPE (bf_ref)) &&
+ TYPE_PRECISION (ret_type) > mask_width);
+ bool load_widen = (TYPE_PRECISION (TREE_TYPE (container)) <
+ TYPE_PRECISION (ret_type));
+
/* We move the conversion earlier if the loaded type is smaller than the
- return type to enable the use of widening loads. */
- if (TYPE_PRECISION (TREE_TYPE (container)) < TYPE_PRECISION (ret_type)
- && !useless_type_conversion_p (TREE_TYPE (container), ret_type))
- {
- pattern_stmt
- = gimple_build_assign (vect_recog_temp_ssa_var (ret_type),
- NOP_EXPR, container);
+ return type to enable the use of widening loads. And if we need a
+ sign extension, we need to convert the loaded value early to a signed
+ type as well. */
+ if (ref_sext || load_widen)
+ {
+ tree type = load_widen ? ret_type : container_type;
+ if (ref_sext)
+ type = gimple_signed_type (type);
+ pattern_stmt = gimple_build_assign (vect_recog_temp_ssa_var (type),
+ NOP_EXPR, container);
container = gimple_get_lhs (pattern_stmt);
container_type = TREE_TYPE (container);
prec = tree_to_uhwi (TYPE_SIZE (container_type));
@@ -2671,7 +2688,7 @@ vect_recog_bitfield_ref_pattern (vec_info *vinfo, stmt_vec_info stmt_info,
shift_first = true;
tree result;
- if (shift_first)
+ if (shift_first && !ref_sext)
{
tree shifted = container;
if (shift_n)
@@ -2694,14 +2711,27 @@ vect_recog_bitfield_ref_pattern (vec_info *vinfo, stmt_vec_info stmt_info,
}
else
{
- tree mask = wide_int_to_tree (container_type,
- wi::shifted_mask (shift_n, mask_width,
- false, prec));
- pattern_stmt
- = gimple_build_assign (vect_recog_temp_ssa_var (container_type),
- BIT_AND_EXPR, container, mask);
- tree masked = gimple_assign_lhs (pattern_stmt);
+ tree temp = vect_recog_temp_ssa_var (container_type);
+ if (!ref_sext)
+ {
+ tree mask = wide_int_to_tree (container_type,
+ wi::shifted_mask (shift_n,
+ mask_width,
+ false, prec));
+ pattern_stmt = gimple_build_assign (temp, BIT_AND_EXPR,
+ container, mask);
+ }
+ else
+ {
+ HOST_WIDE_INT shl = prec - shift_n - mask_width;
+ shift_n += shl;
+ pattern_stmt = gimple_build_assign (temp, LSHIFT_EXPR,
+ container,
+ build_int_cst (sizetype,
+ shl));
+ }
+ tree masked = gimple_assign_lhs (pattern_stmt);
append_pattern_def_seq (vinfo, stmt_info, pattern_stmt, vectype);
pattern_stmt
= gimple_build_assign (vect_recog_temp_ssa_var (container_type),