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.
We could use build_ref_for_offset if that supported a similar ability to add the statements into the sequence. Instead we copy a modified version that does a similar thing into rewrite_to_defined_unconditional. Bootstrapped and tested on x86_64-linux-gnu. PR tree-optimization/121279 gcc/ChangeLog: * gimple-fold.cc (gimple_needing_rewrite_undefined): Return true for boolean loads. (rewrite_to_defined_unconditional): Handle boolean 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 | 113 +++++++++++++++++++++- gcc/testsuite/gcc.dg/torture/pr121279-1.c | 49 ++++++++++ 2 files changed, 161 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..40707d03946 100644 --- a/gcc/gimple-fold.cc +++ b/gcc/gimple-fold.cc @@ -69,6 +69,7 @@ along with GCC; see the file COPYING3. If not see #include "varasm.h" #include "internal-fn.h" #include "gimple-range.h" +#include "alias.h" enum strlen_range_kind { /* Compute the exact constant string length. */ @@ -10520,6 +10521,19 @@ 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) + && TREE_CODE (lhs_type) == BOOLEAN_TYPE + && !type_has_mode_precision_p (lhs_type) + /* Loads directly from a decl don't need the + rewrite as it should always contain a valid value. */ + && !DECL_P (rhs) + /* 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 +10572,104 @@ 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); + + /* Bool loads need to be rewritten to be a load from the same mode + and then a cast to the boolean 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) + && TREE_CODE (TREE_TYPE (lhs)) == BOOLEAN_TYPE) + { + tree rhs = gimple_assign_rhs1 (stmt); + /* Direct reads from decl don't need a rewrite. */ + gcc_assert (!DECL_P (rhs)); + /* 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))); + + location_t loc = gimple_location (stmt); + auto bits = GET_MODE_BITSIZE (SCALAR_TYPE_MODE (TREE_TYPE (rhs))); + tree new_type = build_nonstandard_integer_type (bits, true); + poly_int64 offset; + tree base = get_addr_base_and_unit_offset (rhs, &offset); + tree off; + /* Preserve address-space information. */ + addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (rhs)); + if (as != TYPE_ADDR_SPACE (new_type)) + new_type = build_qualified_type (new_type, + TYPE_QUALS (new_type) + | ENCODE_QUAL_ADDR_SPACE (as)); + + /* get_addr_base_and_unit_offset returns NULL for references with a variable + offset such as array[var_index]. */ + if (!base) + { + tree tmp, addr; + gassign *nstmt; + + /* Create instead `tmp = &array[index];` which then will be deferenced. */ + tmp = make_ssa_name (build_pointer_type (TREE_TYPE (rhs))); + addr = build_fold_addr_expr (unshare_expr (rhs)); + STRIP_USELESS_TYPE_CONVERSION (addr); + nstmt = gimple_build_assign (tmp, addr); + gimple_set_location (nstmt, loc); + if (in_place) + gsi_insert_before (gsi, nstmt, GSI_SAME_STMT); + else + gimple_seq_add_stmt (&stmts, nstmt); + off = build_zero_cst (reference_alias_ptr_type (rhs)); + base = tmp; + } + /* For [MEM a + 10]->b change it into MEM[a + 10 +offseof(b)] */ + else if (TREE_CODE (base) == MEM_REF) + { + off = build_int_cst (TREE_TYPE (TREE_OPERAND (base, 1)), + offset); + off = int_const_binop (PLUS_EXPR, TREE_OPERAND (base, 1), off); + base = unshare_expr (TREE_OPERAND (base, 0)); + } + /* For `a.b` change it into `MEM[&a + offsetof(b)]` */ + else + { + off = build_int_cst (reference_alias_ptr_type (rhs), + offset); + base = build_fold_addr_expr (unshare_expr (base)); + } + /* */ + if (TYPE_ALIGN (new_type) > TYPE_ALIGN (TREE_TYPE (rhs))) + new_type = build_aligned_type (new_type, TYPE_ALIGN (TREE_TYPE (rhs))); + tree mem_ref = fold_build2_loc (loc, MEM_REF, new_type, base, off); + if (TREE_THIS_VOLATILE (rhs)) + TREE_THIS_VOLATILE (mem_ref) = 1; + if (TREE_SIDE_EFFECTS (rhs)) + TREE_SIDE_EFFECTS (mem_ref) = 1; + + /* 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 +10691,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