Just like r16-465-gf2bb7ffe84840d8 but this time instead of a VCE there is a full on load from a boolean. This showed up when trying to remove the extra copy in the testcase from the revision mentioned above (pr120122-1.c). So when moving loads from a boolean type from being conditional to non-conditional, the load needs to become a full load and then casted into a bool so that the upper bits are correct.
Bitfields loads will always do the truncation so they don't need to be rewritten. What we do is wrap the original reference with a VCE which causes the full load and then do a casting to do the truncation. Changes since v1: * v2: Use VIEW_CONVERT_EXPR instead of doing a manual load. Accept all non mode precision loads rather than just boolean ones. Bootstrapped and tested on x86_64-linux-gnu. PR tree-optimization/121279 gcc/ChangeLog: * gimple-fold.cc (gimple_needing_rewrite_undefined): Return true for non mode precision loads. (rewrite_to_defined_unconditional): Handle non mode precision loads. gcc/testsuite/ChangeLog: * gcc.dg/torture/pr121279-1.c: New test. Signed-off-by: Andrew Pinski <andrew.pin...@oss.qualcomm.com> --- gcc/gimple-fold.cc | 55 ++++++++++++++++++++++- gcc/testsuite/gcc.dg/torture/pr121279-1.c | 49 ++++++++++++++++++++ 2 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.dg/torture/pr121279-1.c diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc index 85319b33492..3ec0be015e4 100644 --- a/gcc/gimple-fold.cc +++ b/gcc/gimple-fold.cc @@ -10520,6 +10520,17 @@ gimple_needing_rewrite_undefined (gimple *stmt) && !POINTER_TYPE_P (lhs_type)) return false; tree rhs = gimple_assign_rhs1 (stmt); + /* Boolean loads need special handling as they are treated as a full MODE load + and don't mask off the bits for the precision. */ + if (gimple_assign_load_p (stmt) + && INTEGRAL_TYPE_P (lhs_type) + && TYPE_MODE (lhs_type) != BLKmode + && !type_has_mode_precision_p (lhs_type) + /* Bit-fields loads don't need a rewrite as the masking + happens for them. */ + && (TREE_CODE (rhs) != COMPONENT_REF + || !DECL_BIT_FIELD (TREE_OPERAND (rhs, 1)))) + return true; /* VCE from integral types to a integral types but with a smaller precision need to be changed into casts to be well defined. */ @@ -10558,6 +10569,49 @@ rewrite_to_defined_unconditional (gimple_stmt_iterator *gsi, gimple *stmt, print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); } gimple_seq stmts = NULL; + tree lhs = gimple_assign_lhs (stmt); + + /* Non mode precision loads need to be rewritten to be a load from the same mode + and then a cast to the other type so the other bits are masked off + correctly since the load was done conditionally. It is similar to the VCE + case below. */ + if (gimple_assign_load_p (stmt) + && !type_has_mode_precision_p (TREE_TYPE (lhs))) + { + tree rhs = gimple_assign_rhs1 (stmt); + /* Bit-fields loads will do the masking so don't need the rewriting. */ + gcc_assert (TREE_CODE (rhs) != COMPONENT_REF + || !DECL_BIT_FIELD (TREE_OPERAND (rhs, 1))); + + auto bits = GET_MODE_BITSIZE (SCALAR_TYPE_MODE (TREE_TYPE (rhs))); + tree new_type = build_nonstandard_integer_type (bits, true); + location_t loc = gimple_location (stmt); + tree mem_ref = fold_build1_loc (loc, VIEW_CONVERT_EXPR, new_type, rhs); + /* Replace the original load with a new load and a new lhs. */ + tree new_lhs = make_ssa_name (new_type); + gimple_assign_set_rhs1 (stmt, mem_ref); + gimple_assign_set_lhs (stmt, new_lhs); + + if (in_place) + update_stmt (stmt); + else + { + gimple_set_modified (stmt, true); + gimple_seq_add_stmt (&stmts, stmt); + } + + /* Build the conversion statement. */ + gimple *cvt = gimple_build_assign (lhs, NOP_EXPR, new_lhs); + if (in_place) + { + gsi_insert_after (gsi, cvt, GSI_SAME_STMT); + update_stmt (stmt); + } + else + gimple_seq_add_stmt (&stmts, cvt); + return stmts; + } + /* VCE from integral types to another integral types but with smaller precisions need to be changed into casts to be well defined. */ @@ -10579,7 +10633,6 @@ rewrite_to_defined_unconditional (gimple_stmt_iterator *gsi, gimple *stmt, } return stmts; } - tree lhs = gimple_assign_lhs (stmt); tree type = unsigned_type_for (TREE_TYPE (lhs)); if (gimple_assign_rhs_code (stmt) == ABS_EXPR) gimple_assign_set_rhs_code (stmt, ABSU_EXPR); diff --git a/gcc/testsuite/gcc.dg/torture/pr121279-1.c b/gcc/testsuite/gcc.dg/torture/pr121279-1.c new file mode 100644 index 00000000000..516b887fe65 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr121279-1.c @@ -0,0 +1,49 @@ +/* { dg-do run } */ +/* PR tree-optimization/121279 */ + +#include <stdbool.h> + +struct Value { + int type; + union { + bool boolean; + long long t; + }; +}; + +static struct Value s_item_mem; + +/* truthy was being miscompiled for the value.type==2 case, + because the bool load from the union is pulled out of the + loop but that was conditional before and now it is not, + so turns it into `s_item_mem.type == 1 | bool` which is + not valid if `s_item_mem.type == 2` . */ +static bool truthy(void) __attribute__((noipa)); +static bool +truthy(void) +{ + bool tt = false; + for(int i = 0; i < 10; i++) + { + if (s_item_mem.type == 0) + tt = tt | 0; + else if (s_item_mem.type == 1) + tt = tt | s_item_mem.boolean; + else + tt = tt | 1; + } + return tt; +} + +int +main(void) +{ + s_item_mem.type = 2; + s_item_mem.t = -1; + bool b1 = !truthy(); + s_item_mem.type = 1; + s_item_mem.boolean = b1; + bool b = truthy(); + if (b1 != b) __builtin_abort(); + if (b) __builtin_abort(); +} -- 2.43.0