diff options
Diffstat (limited to 'gcc/dwarf2out.c')
-rw-r--r-- | gcc/dwarf2out.c | 92 |
1 files changed, 88 insertions, 4 deletions
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index fbda47e..523735e 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -16407,11 +16407,13 @@ mem_loc_descriptor (rtx rtl, machine_mode mode, if ((!dwarf_strict || dwarf_version >= 5) && is_a <scalar_int_mode> (mode, &int_mode)) { - if (GET_MODE_SIZE (int_mode) > DWARF2_ADDR_SIZE) + /* We can use a signed divide if the sign bit is not set. */ + if (GET_MODE_SIZE (int_mode) < DWARF2_ADDR_SIZE) { op = DW_OP_div; goto do_binop; } + mem_loc_result = typed_binop (DW_OP_div, rtl, base_type_for_mode (int_mode, 1), int_mode, mem_mode); @@ -18503,6 +18505,48 @@ function_to_dwarf_procedure (tree fndecl) return dwarf_proc_die; } +/* Helper function for loc_list_from_tree. Perform OP binary op, + but after converting arguments to type_die, afterwards convert + back to unsigned. */ + +static dw_loc_list_ref +typed_binop_from_tree (enum dwarf_location_atom op, tree loc, + dw_die_ref type_die, scalar_int_mode mode, + struct loc_descr_context *context) +{ + dw_loc_list_ref op0, op1; + dw_loc_descr_ref cvt, binop; + + if (type_die == NULL) + return NULL; + + op0 = loc_list_from_tree (TREE_OPERAND (loc, 0), 0, context); + op1 = loc_list_from_tree (TREE_OPERAND (loc, 1), 0, context); + if (op0 == NULL || op1 == NULL) + return NULL; + + cvt = new_loc_descr (dwarf_OP (DW_OP_convert), 0, 0); + cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref; + cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die; + cvt->dw_loc_oprnd1.v.val_die_ref.external = 0; + add_loc_descr_to_each (op0, cvt); + + cvt = new_loc_descr (dwarf_OP (DW_OP_convert), 0, 0); + cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref; + cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die; + cvt->dw_loc_oprnd1.v.val_die_ref.external = 0; + add_loc_descr_to_each (op1, cvt); + + add_loc_list (&op0, op1); + if (op0 == NULL) + return NULL; + + binop = new_loc_descr (op, 0, 0); + convert_descriptor_to_mode (mode, binop); + add_loc_descr_to_each (op0, binop); + + return op0; +} /* Generate Dwarf location list representing LOC. If WANT_ADDRESS is false, expression computing LOC will be computed @@ -19096,13 +19140,53 @@ loc_list_from_tree_1 (tree loc, int want_address, op = DW_OP_or; goto do_binop; + case EXACT_DIV_EXPR: case FLOOR_DIV_EXPR: + case TRUNC_DIV_EXPR: + /* Turn a divide by a power of 2 into a shift when possible. */ + if (TYPE_UNSIGNED (TREE_TYPE (loc)) + && tree_fits_uhwi_p (TREE_OPERAND (loc, 1))) + { + const int log2 = exact_log2 (tree_to_uhwi (TREE_OPERAND (loc, 1))); + if (log2 > 0) + { + list_ret + = loc_list_from_tree_1 (TREE_OPERAND (loc, 0), 0, context); + if (list_ret == 0) + return 0; + + add_loc_descr_to_each (list_ret, uint_loc_descriptor (log2)); + add_loc_descr_to_each (list_ret, + new_loc_descr (DW_OP_shr, 0, 0)); + break; + } + } + + /* fall through */ + case CEIL_DIV_EXPR: case ROUND_DIV_EXPR: - case TRUNC_DIV_EXPR: - case EXACT_DIV_EXPR: if (TYPE_UNSIGNED (TREE_TYPE (loc))) - return 0; + { + enum machine_mode mode = TYPE_MODE (TREE_TYPE (loc)); + scalar_int_mode int_mode; + + if ((dwarf_strict && dwarf_version < 5) + || !is_a <scalar_int_mode> (mode, &int_mode)) + return 0; + + /* We can use a signed divide if the sign bit is not set. */ + if (GET_MODE_SIZE (int_mode) < DWARF2_ADDR_SIZE) + { + op = DW_OP_div; + goto do_binop; + } + + list_ret = typed_binop_from_tree (DW_OP_div, loc, + base_type_for_mode (int_mode, 1), + int_mode, context); + break; + } op = DW_OP_div; goto do_binop; |