@@ -257,7 +257,7 @@ promote_debug_loc (struct elt_loc_list *
{
n_debug_values--;
l->setting_insn = cselib_current_insn;
- gcc_assert (!l->next);
+ gcc_assert (!l->next || cselib_preserve_constants);
}
}
@@ -1719,6 +1719,12 @@ cselib_subst_to_values (rtx x, enum mach
}
return e->val_rtx;
+ case ENTRY_VALUE:
+ e = cselib_lookup (x, GET_MODE (x), 0, memmode);
+ if (! e)
+ break;
+ return e->val_rtx;
+
case CONST_DOUBLE:
case CONST_VECTOR:
case CONST_INT:
@@ -1843,6 +1849,43 @@ cselib_lookup_1 (rtx x, enum machine_mod
used_regs[n_used_regs++] = i;
REG_VALUES (i) = new_elt_list (REG_VALUES (i), NULL);
}
+ else if (cselib_preserve_constants
+ && GET_MODE_CLASS (mode) == MODE_INT)
+ {
+ /* During var-tracking, try harder to find equivalences
+ for SUBREGs. If a setter sets say a DImode register
+ and user uses that register only in SImode, add a lowpart
+ subreg location. */
+ struct elt_list *lwider = NULL;
+ l = REG_VALUES (i);
+ if (l && l->elt == NULL)
+ l = l->next;
+ for (; l; l = l->next)
+ if (GET_MODE_CLASS (GET_MODE (l->elt->val_rtx)) == MODE_INT
+ && GET_MODE_SIZE (GET_MODE (l->elt->val_rtx))
+ > GET_MODE_SIZE (mode)
+ && (lwider == NULL
+ || GET_MODE_SIZE (GET_MODE (l->elt->val_rtx))
+ < GET_MODE_SIZE (GET_MODE (lwider->elt->val_rtx))))
+ {
+ struct elt_loc_list *el;
+ if (i < FIRST_PSEUDO_REGISTER
+ && hard_regno_nregs[i][GET_MODE (l->elt->val_rtx)] != 1)
+ continue;
+ for (el = l->elt->locs; el; el = el->next)
+ if (!REG_P (el->loc))
+ break;
+ if (el)
+ lwider = l;
+ }
+ if (lwider)
+ {
+ rtx sub = lowpart_subreg (mode, lwider->elt->val_rtx,
+ GET_MODE (lwider->elt->val_rtx));
+ if (sub)
+ e->locs->next = new_elt_loc_list (e->locs->next, sub);
+ }
+ }
REG_VALUES (i)->next = new_elt_list (REG_VALUES (i)->next, e);
slot = cselib_find_slot (x, e->hash, INSERT, memmode);
*slot = e;
@@ -7415,7 +7415,7 @@ vt_expand_loc (rtx loc, htab_t vars, boo
data.dummy = false;
data.cur_loc_changed = false;
data.ignore_cur_loc = ignore_cur_loc;
- loc = cselib_expand_value_rtx_cb (loc, scratch_regs, 8,
+ loc = cselib_expand_value_rtx_cb (loc, scratch_regs, 10,
vt_expand_loc_callback, &data);
if (loc && MEM_P (loc))
@@ -7437,7 +7437,7 @@ vt_expand_loc_dummy (rtx loc, htab_t var
data.dummy = true;
data.cur_loc_changed = false;
data.ignore_cur_loc = false;
- ret = cselib_dummy_expand_value_rtx_cb (loc, scratch_regs, 8,
+ ret = cselib_dummy_expand_value_rtx_cb (loc, scratch_regs, 10,
vt_expand_loc_callback, &data);
*pcur_loc_changed = data.cur_loc_changed;
return ret;
@@ -13824,6 +13824,37 @@ base_type_for_mode (enum machine_mode mo
return type_die;
}
+/* For OP descriptor assumed to be in unsigned MODE, convert it to a signed
+ type matching MODE, or, if MODE is narrower than DWARF2_ADDR_SIZE, signed
+ type matching DWARF2_ADDR_SIZE. Return NULL if the conversion is not
+ possible. */
+
+static dw_loc_descr_ref
+convert_descriptor_to_signed (enum machine_mode mode, dw_loc_descr_ref op)
+{
+ enum machine_mode outer_mode = mode;
+ dw_die_ref type_die;
+ dw_loc_descr_ref cvt;
+
+ if (GET_MODE_SIZE (mode) < DWARF2_ADDR_SIZE)
+ {
+ outer_mode = mode_for_size (DWARF2_ADDR_SIZE * BITS_PER_UNIT,
+ MODE_INT, 0);
+ if (outer_mode == BLKmode
+ || GET_MODE_SIZE (outer_mode) != DWARF2_ADDR_SIZE)
+ return NULL;
+ }
+ type_die = base_type_for_mode (outer_mode, 0);
+ if (type_die == NULL)
+ return NULL;
+ cvt = new_loc_descr (DW_OP_GNU_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 (&op, cvt);
+ return op;
+}
+
/* The following routine converts the RTL for a variable or parameter
(resident in memory) into an equivalent Dwarf representation of a
mechanism for getting the address of that same variable onto the top of a
@@ -13986,6 +14017,21 @@ mem_loc_descriptor (rtx rtl, enum machin
mem_mode, VAR_INIT_STATUS_INITIALIZED);
if (op0 == 0)
break;
+ else if (GET_CODE (rtl) == ZERO_EXTEND
+ && GET_MODE_SIZE (mode) <= DWARF2_ADDR_SIZE
+ && GET_MODE_BITSIZE (GET_MODE (XEXP (rtl, 0)))
+ < HOST_BITS_PER_WIDE_INT
+ /* If DW_OP_const{1,2,4}u won't be used, it is shorter
+ to expand zero extend as two shifts instead of
+ masking. */
+ && GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) <= 4)
+ {
+ enum machine_mode imode = GET_MODE (XEXP (rtl, 0));
+ mem_loc_result = op0;
+ add_loc_descr (&mem_loc_result,
+ int_loc_descriptor (GET_MODE_MASK (imode)));
+ add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_and, 0, 0));
+ }
else if (GET_MODE_SIZE (mode) <= DWARF2_ADDR_SIZE)
{
int shift = DWARF2_ADDR_SIZE
@@ -14239,10 +14285,15 @@ mem_loc_descriptor (rtx rtl, enum machin
do_shift:
op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
VAR_INIT_STATUS_INITIALIZED);
- op1 = mem_loc_descriptor (XEXP (rtl, 1),
- GET_MODE (XEXP (rtl, 1)) == VOIDmode
- ? mode : GET_MODE (XEXP (rtl, 1)), mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
+ {
+ rtx rtlop1 = XEXP (rtl, 1);
+ if (GET_MODE (rtlop1) != VOIDmode
+ && GET_MODE_BITSIZE (GET_MODE (rtlop1))
+ < GET_MODE_BITSIZE (mode))
+ rtlop1 = gen_rtx_ZERO_EXTEND (mode, rtlop1);
+ op1 = mem_loc_descriptor (rtlop1, mode, mem_mode,
+ VAR_INIT_STATUS_INITIALIZED);
+ }
if (op0 == 0 || op1 == 0)
break;
@@ -14279,6 +14330,16 @@ mem_loc_descriptor (rtx rtl, enum machin
break;
case MOD:
+ if (GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE && !dwarf_strict)
+ {
+ /* If MODE is wider than DWARF2_ADDR_SIZE, mem_loc_descriptor
+ should return signed typed values and therefore DW_OP_mod
+ won't be unsigned as it defaults for untyped stack values,
+ but signed. */
+ op = DW_OP_mod;
+ goto do_binop;
+ }
+
op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
VAR_INIT_STATUS_INITIALIZED);
op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, mem_mode,
@@ -14296,6 +14357,38 @@ mem_loc_descriptor (rtx rtl, enum machin
add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_minus, 0, 0));
break;
+ case UDIV:
+ if (!dwarf_strict && GET_MODE_CLASS (mode) == MODE_INT)
+ {
+ dw_die_ref type_die;
+ dw_loc_descr_ref cvt;
+
+ type_die = base_type_for_mode (mode, 1);
+ if (type_die == NULL)
+ break;
+ op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
+ VAR_INIT_STATUS_INITIALIZED);
+ op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, mem_mode,
+ VAR_INIT_STATUS_INITIALIZED);
+ if (op0 == 0 || op1 == 0)
+ break;
+ cvt = new_loc_descr (DW_OP_GNU_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 (&op0, cvt);
+ cvt = new_loc_descr (DW_OP_GNU_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 (&op1, cvt);
+ mem_loc_result = op0;
+ add_loc_descr (&mem_loc_result, op1);
+ add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_div, 0, 0));
+ mem_loc_result = convert_descriptor_to_signed (mode, mem_loc_result);
+ }
+ break;
+
case NOT:
op = DW_OP_not;
goto do_unop;
@@ -14812,31 +14905,359 @@ mem_loc_descriptor (rtx rtl, enum machin
&& (GET_CODE (rtl) == UNSIGNED_FIX
|| GET_MODE_SIZE (mode) < DWARF2_ADDR_SIZE))
{
- enum machine_mode outer_mode = mode;
- if (GET_MODE_SIZE (mode) < DWARF2_ADDR_SIZE)
- {
- outer_mode = mode_for_size (DWARF2_ADDR_SIZE * BITS_PER_UNIT,
- MODE_INT, 0);
- if (outer_mode == BLKmode
- || GET_MODE_SIZE (outer_mode) != DWARF2_ADDR_SIZE)
- break;
- }
- type_die = base_type_for_mode (outer_mode, 0);
- if (type_die == NULL)
+ op0 = convert_descriptor_to_signed (mode, op0);
+ if (op0 == NULL)
break;
- cvt = new_loc_descr (DW_OP_GNU_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 (&op0, cvt);
}
mem_loc_result = op0;
}
break;
- case COMPARE:
+ case CLZ:
+ case CTZ:
+ case FFS:
+ /* CLZ (where constV is CLZ_DEFINED_VALUE_AT_ZERO computed value,
+ const0 is DW_OP_lit0 or corresponding typed constant,
+ const1 is DW_OP_lit1 or corresponding typed constant
+ and constMSB is constant with just the MSB bit set
+ for the mode):
+ DW_OP_dup DW_OP_bra <L1> DW_OP_drop constV DW_OP_skip <L4>
+ L1: const0 DW_OP_swap
+ L2: DW_OP_dup constMSB DW_OP_and DW_OP_bra <L3> const1 DW_OP_shl
+ DW_OP_swap DW_OP_plus_uconst <1> DW_OP_swap DW_OP_skip <L2>
+ L3: DW_OP_drop
+ L4: DW_OP_nop
+
+ CTZ is similar:
+ DW_OP_dup DW_OP_bra <L1> DW_OP_drop constV DW_OP_skip <L4>
+ L1: const0 DW_OP_swap
+ L2: DW_OP_dup const1 DW_OP_and DW_OP_bra <L3> const1 DW_OP_shr
+ DW_OP_swap DW_OP_plus_uconst <1> DW_OP_swap DW_OP_skip <L2>
+ L3: DW_OP_drop
+ L4: DW_OP_nop
+
+ FFS is similar:
+ DW_OP_dup DW_OP_bra <L1> DW_OP_drop const0 DW_OP_skip <L4>
+ L1: const1 DW_OP_swap
+ L2: DW_OP_dup const1 DW_OP_and DW_OP_bra <L3> const1 DW_OP_shr
+ DW_OP_swap DW_OP_plus_uconst <1> DW_OP_swap DW_OP_skip <L2>
+ L3: DW_OP_drop
+ L4: DW_OP_nop */
+ if (GET_MODE_CLASS (mode) == MODE_INT
+ && GET_MODE (XEXP (rtl, 0)) == mode
+ && (GET_CODE (rtl) != CLZ
+ || GET_MODE_BITSIZE (mode) <= 2 * HOST_BITS_PER_WIDE_INT))
+ {
+ HOST_WIDE_INT valv;
+ dw_loc_descr_ref l1jump, l1label;
+ dw_loc_descr_ref l2jump, l2label;
+ dw_loc_descr_ref l3jump, l3label;
+ dw_loc_descr_ref l4jump, l4label;
+ rtx msb;
+
+ op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
+ VAR_INIT_STATUS_INITIALIZED);
+ if (op0 == NULL)
+ break;
+ if (GET_CODE (rtl) == CLZ)
+ {
+ if (!CLZ_DEFINED_VALUE_AT_ZERO (mode, valv))
+ valv = GET_MODE_BITSIZE (mode);
+ }
+ else if (GET_CODE (rtl) == FFS)
+ valv = 0;
+ else if (!CTZ_DEFINED_VALUE_AT_ZERO (mode, valv))
+ valv = GET_MODE_BITSIZE (mode);
+ add_loc_descr (&op0, new_loc_descr (DW_OP_dup, 0, 0));
+ l1jump = new_loc_descr (DW_OP_bra, 0, 0);
+ add_loc_descr (&op0, l1jump);
+ add_loc_descr (&op0, new_loc_descr (DW_OP_drop, 0, 0));
+ op1 = mem_loc_descriptor (GEN_INT (valv), mode, mem_mode,
+ VAR_INIT_STATUS_INITIALIZED);
+ if (op1 == NULL)
+ break;
+ add_loc_descr (&op0, op1);
+ l4jump = new_loc_descr (DW_OP_skip, 0, 0);
+ add_loc_descr (&op0, l4jump);
+ l1label = mem_loc_descriptor (GET_CODE (rtl) == FFS
+ ? const1_rtx : const0_rtx,
+ mode, mem_mode,
+ VAR_INIT_STATUS_INITIALIZED);
+ if (l1label == NULL)
+ break;
+ add_loc_descr (&op0, l1label);
+ add_loc_descr (&op0, new_loc_descr (DW_OP_swap, 0, 0));
+ l2label = new_loc_descr (DW_OP_dup, 0, 0);
+ add_loc_descr (&op0, l2label);
+ if (GET_CODE (rtl) != CLZ)
+ msb = const1_rtx;
+ else if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
+ msb = GEN_INT ((unsigned HOST_WIDE_INT) 1
+ << (GET_MODE_BITSIZE (mode) - 1));
+ else
+ msb = immed_double_const (0, (unsigned HOST_WIDE_INT) 1
+ << (GET_MODE_BITSIZE (mode)
+ - HOST_BITS_PER_WIDE_INT - 1),
+ mode);
+ if (GET_CODE (msb) == CONST_INT && INTVAL (msb) < 0)
+ op1 = new_loc_descr (HOST_BITS_PER_WIDE_INT == 32
+ ? DW_OP_const4u
+ : HOST_BITS_PER_WIDE_INT == 64
+ ? DW_OP_const8u : DW_OP_constu,
+ INTVAL (msb), 0);
+ else
+ op1 = mem_loc_descriptor (msb, mode, mem_mode,
+ VAR_INIT_STATUS_INITIALIZED);
+ if (op1 == NULL)
+ break;
+ add_loc_descr (&op0, op1);
+ add_loc_descr (&op0, new_loc_descr (DW_OP_and, 0, 0));
+ l3jump = new_loc_descr (DW_OP_bra, 0, 0);
+ add_loc_descr (&op0, l3jump);
+ op1 = mem_loc_descriptor (const1_rtx, mode, mem_mode,
+ VAR_INIT_STATUS_INITIALIZED);
+ if (op1 == NULL)
+ break;
+ add_loc_descr (&op0, op1);
+ add_loc_descr (&op0, new_loc_descr (GET_CODE (rtl) == CLZ
+ ? DW_OP_shl : DW_OP_shr, 0, 0));
+ add_loc_descr (&op0, new_loc_descr (DW_OP_swap, 0, 0));
+ add_loc_descr (&op0, new_loc_descr (DW_OP_plus_uconst, 1, 0));
+ add_loc_descr (&op0, new_loc_descr (DW_OP_swap, 0, 0));
+ l2jump = new_loc_descr (DW_OP_skip, 0, 0);
+ add_loc_descr (&op0, l2jump);
+ l3label = new_loc_descr (DW_OP_drop, 0, 0);
+ add_loc_descr (&op0, l3label);
+ l4label = new_loc_descr (DW_OP_nop, 0, 0);
+ add_loc_descr (&op0, l4label);
+ l1jump->dw_loc_oprnd1.val_class = dw_val_class_loc;
+ l1jump->dw_loc_oprnd1.v.val_loc = l1label;
+ l2jump->dw_loc_oprnd1.val_class = dw_val_class_loc;
+ l2jump->dw_loc_oprnd1.v.val_loc = l2label;
+ l3jump->dw_loc_oprnd1.val_class = dw_val_class_loc;
+ l3jump->dw_loc_oprnd1.v.val_loc = l3label;
+ l4jump->dw_loc_oprnd1.val_class = dw_val_class_loc;
+ l4jump->dw_loc_oprnd1.v.val_loc = l4label;
+ mem_loc_result = op0;
+ }
+ break;
+
+ case POPCOUNT:
+ case PARITY:
+ /* POPCOUNT (const0 is DW_OP_lit0 or corresponding typed constant,
+ const1 is DW_OP_lit1 or corresponding typed constant):
+ const0 DW_OP_swap
+ L1: DW_OP_dup DW_OP_bra <L2> DW_OP_dup DW_OP_rot const1 DW_OP_and
+ DW_OP_plus DW_OP_swap const1 DW_OP_shr DW_OP_skip <L1>
+ L2: DW_OP_drop
+
+ PARITY is similar:
+ L1: DW_OP_dup DW_OP_bra <L2> DW_OP_dup DW_OP_rot const1 DW_OP_and
+ DW_OP_xor DW_OP_swap const1 DW_OP_shr DW_OP_skip <L1>
+ L2: DW_OP_drop */
+ if (GET_MODE_CLASS (mode) == MODE_INT
+ && GET_MODE (XEXP (rtl, 0)) == mode)
+ {
+ dw_loc_descr_ref l1jump, l1label;
+ dw_loc_descr_ref l2jump, l2label;
+
+ op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
+ VAR_INIT_STATUS_INITIALIZED);
+ if (op0 == NULL)
+ break;
+ op1 = mem_loc_descriptor (const0_rtx, mode, mem_mode,
+ VAR_INIT_STATUS_INITIALIZED);
+ if (op1 == NULL)
+ break;
+ add_loc_descr (&op0, op1);
+ add_loc_descr (&op0, new_loc_descr (DW_OP_swap, 0, 0));
+ l1label = new_loc_descr (DW_OP_dup, 0, 0);
+ add_loc_descr (&op0, l1label);
+ l2jump = new_loc_descr (DW_OP_bra, 0, 0);
+ add_loc_descr (&op0, l2jump);
+ add_loc_descr (&op0, new_loc_descr (DW_OP_dup, 0, 0));
+ add_loc_descr (&op0, new_loc_descr (DW_OP_rot, 0, 0));
+ op1 = mem_loc_descriptor (const1_rtx, mode, mem_mode,
+ VAR_INIT_STATUS_INITIALIZED);
+ if (op1 == NULL)
+ break;
+ add_loc_descr (&op0, op1);
+ add_loc_descr (&op0, new_loc_descr (DW_OP_and, 0, 0));
+ add_loc_descr (&op0, new_loc_descr (GET_CODE (rtl) == POPCOUNT
+ ? DW_OP_plus : DW_OP_xor, 0, 0));
+ add_loc_descr (&op0, new_loc_descr (DW_OP_swap, 0, 0));
+ op1 = mem_loc_descriptor (const1_rtx, mode, mem_mode,
+ VAR_INIT_STATUS_INITIALIZED);
+ add_loc_descr (&op0, op1);
+ add_loc_descr (&op0, new_loc_descr (DW_OP_shr, 0, 0));
+ l1jump = new_loc_descr (DW_OP_skip, 0, 0);
+ add_loc_descr (&op0, l1jump);
+ l2label = new_loc_descr (DW_OP_drop, 0, 0);
+ add_loc_descr (&op0, l2label);
+ l1jump->dw_loc_oprnd1.val_class = dw_val_class_loc;
+ l1jump->dw_loc_oprnd1.v.val_loc = l1label;
+ l2jump->dw_loc_oprnd1.val_class = dw_val_class_loc;
+ l2jump->dw_loc_oprnd1.v.val_loc = l2label;
+ mem_loc_result = op0;
+ }
+ break;
+
+ case BSWAP:
+ /* BSWAP (constS is initial shift count, either 56 or 24):
+ constS const0
+ L1: DW_OP_pick <2> constS DW_OP_pick <3> DW_OP_minus DW_OP_shr
+ const255 DW_OP_and DW_OP_pick <2> DW_OP_shl DW_OP_or
+ DW_OP_swap DW_OP_dup const0 DW_OP_eq DW_OP_bra <L2> const8
+ DW_OP_minus DW_OP_swap DW_OP_skip <L1>
+ L2: DW_OP_drop DW_OP_swap DW_OP_drop */
+ if (GET_MODE_CLASS (mode) == MODE_INT
+ && BITS_PER_UNIT == 8
+ && (GET_MODE_BITSIZE (mode) == 32
+ || GET_MODE_BITSIZE (mode) == 64))
+ {
+ dw_loc_descr_ref l1jump, l1label;
+ dw_loc_descr_ref l2jump, l2label;
+
+ op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
+ VAR_INIT_STATUS_INITIALIZED);
+ if (op0 == NULL)
+ break;
+
+ op1 = mem_loc_descriptor (GEN_INT (GET_MODE_BITSIZE (mode) - 8),
+ mode, mem_mode,
+ VAR_INIT_STATUS_INITIALIZED);
+ if (op1 == NULL)
+ break;
+ add_loc_descr (&op0, op1);
+ op1 = mem_loc_descriptor (const0_rtx, mode, mem_mode,
+ VAR_INIT_STATUS_INITIALIZED);
+ if (op1 == NULL)
+ break;
+ add_loc_descr (&op0, op1);
+ l1label = new_loc_descr (DW_OP_pick, 2, 0);
+ add_loc_descr (&op0, l1label);
+ op1 = mem_loc_descriptor (GEN_INT (GET_MODE_BITSIZE (mode) - 8),
+ mode, mem_mode,
+ VAR_INIT_STATUS_INITIALIZED);
+ add_loc_descr (&op0, op1);
+ add_loc_descr (&op0, new_loc_descr (DW_OP_pick, 3, 0));
+ add_loc_descr (&op0, new_loc_descr (DW_OP_minus, 0, 0));
+ add_loc_descr (&op0, new_loc_descr (DW_OP_shr, 0, 0));
+ op1 = mem_loc_descriptor (GEN_INT (255), mode, mem_mode,
+ VAR_INIT_STATUS_INITIALIZED);
+ if (op1 == NULL)
+ break;
+ add_loc_descr (&op0, op1);
+ add_loc_descr (&op0, new_loc_descr (DW_OP_and, 0, 0));
+ add_loc_descr (&op0, new_loc_descr (DW_OP_pick, 2, 0));
+ add_loc_descr (&op0, new_loc_descr (DW_OP_shl, 0, 0));
+ add_loc_descr (&op0, new_loc_descr (DW_OP_or, 0, 0));
+ add_loc_descr (&op0, new_loc_descr (DW_OP_swap, 0, 0));
+ add_loc_descr (&op0, new_loc_descr (DW_OP_dup, 0, 0));
+ op1 = mem_loc_descriptor (const0_rtx, mode, mem_mode,
+ VAR_INIT_STATUS_INITIALIZED);
+ add_loc_descr (&op0, op1);
+ add_loc_descr (&op0, new_loc_descr (DW_OP_eq, 0, 0));
+ l2jump = new_loc_descr (DW_OP_bra, 0, 0);
+ add_loc_descr (&op0, l2jump);
+ op1 = mem_loc_descriptor (GEN_INT (8), mode, mem_mode,
+ VAR_INIT_STATUS_INITIALIZED);
+ add_loc_descr (&op0, op1);
+ add_loc_descr (&op0, new_loc_descr (DW_OP_minus, 0, 0));
+ add_loc_descr (&op0, new_loc_descr (DW_OP_swap, 0, 0));
+ l1jump = new_loc_descr (DW_OP_skip, 0, 0);
+ add_loc_descr (&op0, l1jump);
+ l2label = new_loc_descr (DW_OP_drop, 0, 0);
+ add_loc_descr (&op0, l2label);
+ add_loc_descr (&op0, new_loc_descr (DW_OP_swap, 0, 0));
+ add_loc_descr (&op0, new_loc_descr (DW_OP_drop, 0, 0));
+ l1jump->dw_loc_oprnd1.val_class = dw_val_class_loc;
+ l1jump->dw_loc_oprnd1.v.val_loc = l1label;
+ l2jump->dw_loc_oprnd1.val_class = dw_val_class_loc;
+ l2jump->dw_loc_oprnd1.v.val_loc = l2label;
+ mem_loc_result = op0;
+ }
+ break;
+
case ROTATE:
case ROTATERT:
+ /* ROTATE (constMASK is mode mask, BITSIZE is bitsize of mode):
+ DW_OP_over DW_OP_over DW_OP_shl [ constMASK DW_OP_and ] DW_OP_rot
+ [ DW_OP_swap constMASK DW_OP_and DW_OP_swap ] DW_OP_neg
+ DW_OP_plus_uconst <BITSIZE> DW_OP_shr DW_OP_or
+
+ ROTATERT is similar:
+ DW_OP_over DW_OP_over DW_OP_neg DW_OP_plus_uconst <BITSIZE>
+ DW_OP_shl [ constMASK DW_OP_and ] DW_OP_rot
+ [ DW_OP_swap constMASK DW_OP_and DW_OP_swap ] DW_OP_shr DW_OP_or
+ */
+ if (GET_MODE_CLASS (mode) == MODE_INT)
+ {
+ rtx rtlop1 = XEXP (rtl, 1);
+ dw_loc_descr_ref mask[2] = { NULL, NULL };
+ int i;
+
+ if (GET_MODE (rtlop1) != VOIDmode
+ && GET_MODE_BITSIZE (GET_MODE (rtlop1))
+ < GET_MODE_BITSIZE (mode))
+ rtlop1 = gen_rtx_ZERO_EXTEND (mode, rtlop1);
+ op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
+ VAR_INIT_STATUS_INITIALIZED);
+ op1 = mem_loc_descriptor (rtlop1, mode, mem_mode,
+ VAR_INIT_STATUS_INITIALIZED);
+ if (op0 == NULL || op1 == NULL)
+ break;
+ if (GET_MODE_SIZE (mode) < DWARF2_ADDR_SIZE)
+ for (i = 0; i < 2; i++)
+ {
+ if (GET_MODE_BITSIZE (mode) < HOST_BITS_PER_WIDE_INT)
+ mask[i] = mem_loc_descriptor (GEN_INT (GET_MODE_MASK (mode)),
+ mode, mem_mode,
+ VAR_INIT_STATUS_INITIALIZED);
+ else if (GET_MODE_BITSIZE (mode) == HOST_BITS_PER_WIDE_INT)
+ mask[i] = new_loc_descr (HOST_BITS_PER_WIDE_INT == 32
+ ? DW_OP_const4u
+ : HOST_BITS_PER_WIDE_INT == 64
+ ? DW_OP_const8u : DW_OP_constu,
+ GET_MODE_MASK (mode), 0);
+ else
+ mask[i] = NULL;
+ if (mask[i] == NULL)
+ return NULL;
+ add_loc_descr (&mask[i], new_loc_descr (DW_OP_and, 0, 0));
+ }
+ add_loc_descr (&op0, op1);
+ add_loc_descr (&op0, new_loc_descr (DW_OP_over, 0, 0));
+ add_loc_descr (&op0, new_loc_descr (DW_OP_over, 0, 0));
+ if (GET_CODE (rtl) == ROTATERT)
+ {
+ add_loc_descr (&op0, new_loc_descr (DW_OP_neg, 0, 0));
+ add_loc_descr (&op0, new_loc_descr (DW_OP_plus_uconst,
+ GET_MODE_BITSIZE (mode), 0));
+ }
+ add_loc_descr (&op0, new_loc_descr (DW_OP_shl, 0, 0));
+ if (mask[0] != NULL)
+ add_loc_descr (&op0, mask[0]);
+ add_loc_descr (&op0, new_loc_descr (DW_OP_rot, 0, 0));
+ if (mask[1] != NULL)
+ {
+ add_loc_descr (&op0, new_loc_descr (DW_OP_swap, 0, 0));
+ add_loc_descr (&op0, mask[1]);
+ add_loc_descr (&op0, new_loc_descr (DW_OP_swap, 0, 0));
+ }
+ if (GET_CODE (rtl) == ROTATE)
+ {
+ add_loc_descr (&op0, new_loc_descr (DW_OP_neg, 0, 0));
+ add_loc_descr (&op0, new_loc_descr (DW_OP_plus_uconst,
+ GET_MODE_BITSIZE (mode), 0));
+ }
+ add_loc_descr (&op0, new_loc_descr (DW_OP_shr, 0, 0));
+ add_loc_descr (&op0, new_loc_descr (DW_OP_or, 0, 0));
+ mem_loc_result = op0;
+ }
+ break;
+
+ case COMPARE:
case TRUNCATE:
/* In theory, we could implement the above. */
/* DWARF cannot represent the unsigned compare operations
@@ -14856,7 +15277,6 @@ mem_loc_descriptor (rtx rtl, enum machin
case US_ASHIFT:
case SS_TRUNCATE:
case US_TRUNCATE:
- case UDIV:
case UNORDERED:
case ORDERED:
case UNEQ:
@@ -14870,12 +15290,6 @@ mem_loc_descriptor (rtx rtl, enum machin
case SAT_FRACT:
case UNSIGNED_SAT_FRACT:
case SQRT:
- case BSWAP:
- case FFS:
- case CLZ:
- case CTZ:
- case POPCOUNT:
- case PARITY:
case ASM_OPERANDS:
case VEC_MERGE:
case VEC_SELECT:
@@ -0,0 +1,32 @@
+/* { dg-do run { target { x86_64-*-* && lp64 } } } */
+/* { dg-options "-g" } */
+
+volatile int vv;
+
+__attribute__((noclone, noinline)) long
+foo (long x)
+{
+ long f = __builtin_bswap64 (x);
+ long g = f;
+ asm volatile ("" : "+r" (f));
+ vv++; /* { dg-final { gdb-test 12 "g" "f" } } */
+ return f;
+}
+
+__attribute__((noclone, noinline)) int
+bar (int x)
+{
+ int f = __builtin_bswap32 (x);
+ int g = f;
+ asm volatile ("" : "+r" (f));
+ vv++; /* { dg-final { gdb-test 22 "g" "f" } } */
+ return f;
+}
+
+int
+main ()
+{
+ foo (0x123456789abcde0fUL);
+ bar (0x12345678);
+ return 0;
+}
@@ -0,0 +1,33 @@
+/* { dg-do run { target { x86_64-*-* && lp64 } } } */
+/* { dg-options "-g" } */
+
+volatile int vv;
+
+__attribute__((noinline, noclone)) long
+foo (long x)
+{
+ long f = __builtin_clzl (x);
+ long g = f;
+ asm volatile ("" : "+r" (f));
+ vv++; /* { dg-final { gdb-test 12 "g" "f" } } */
+ return f;
+}
+
+__attribute__((noinline, noclone)) long
+bar (long x)
+{
+ long f = __builtin_clzl (x);
+ long g = f;
+ asm volatile ("" : "+r" (f));
+ vv++; /* { dg-final { gdb-test 22 "g" "f" } } */
+ return f;
+}
+
+int
+main ()
+{
+ long x = vv;
+ foo (x + 0x123456UL);
+ bar (x + 0x7fffffffUL);
+ return 0;
+}
@@ -0,0 +1,33 @@
+/* { dg-do run { target { x86_64-*-* && lp64 } } } */
+/* { dg-options "-g" } */
+
+volatile int vv;
+
+__attribute__((noinline, noclone)) long
+foo (long x)
+{
+ long f = __builtin_ctzl (x);
+ long g = f;
+ asm volatile ("" : "+r" (f));
+ vv++; /* { dg-final { gdb-test 12 "g" "f" } } */
+ return f;
+}
+
+__attribute__((noinline, noclone)) long
+bar (long x)
+{
+ long f = __builtin_ctzl (x);
+ long g = f;
+ asm volatile ("" : "+r" (f));
+ vv++; /* { dg-final { gdb-test 22 "g" "f" } } */
+ return f;
+}
+
+int
+main ()
+{
+ long x = vv;
+ foo (x + 0x1234560UL);
+ bar (x + 0x7fff8000UL);
+ return 0;
+}
@@ -0,0 +1,76 @@
+/* { dg-do run { target { x86_64-*-* && lp64 } } } */
+/* { dg-options "-g" } */
+
+volatile int vv;
+
+__attribute__((noclone, noinline)) long
+f1 (unsigned long x)
+{
+ long f = (x << 12) | (x >> (64 - 12));
+ long g = f;
+ asm volatile ("" : "+r" (f));
+ vv++; /* { dg-final { gdb-test 12 "g" "f" } } */
+ return f;
+}
+
+__attribute__((noclone, noinline)) long
+f2 (unsigned long x, int y)
+{
+ long f = (x << y) | (x >> (64 - y));
+ long g = f;
+ asm volatile ("" : "+r" (f));
+ vv++; /* { dg-final { gdb-test 22 "g" "f" } } */
+ return f;
+}
+
+__attribute__((noclone, noinline)) long
+f3 (unsigned long x, int y)
+{
+ long f = (x >> y) | (x << (64 - y));
+ long g = f;
+ asm volatile ("" : "+r" (f));
+ vv++; /* { dg-final { gdb-test 32 "g" "f" } } */
+ return f;
+}
+
+__attribute__((noclone, noinline)) unsigned int
+f4 (unsigned int x)
+{
+ unsigned int f = (x << 12) | (x >> (32 - 12));
+ unsigned int g = f;
+ asm volatile ("" : "+r" (f));
+ vv++; /* { dg-final { gdb-test 42 "g" "f" } } */
+ return f;
+}
+
+__attribute__((noclone, noinline)) unsigned int
+f5 (unsigned int x, int y)
+{
+ unsigned int f = (x << y) | (x >> (64 - y));
+ unsigned int g = f;
+ asm volatile ("" : "+r" (f));
+ vv++; /* { dg-final { gdb-test 52 "g" "f" } } */
+ return f;
+}
+
+__attribute__((noclone, noinline)) unsigned int
+f6 (unsigned int x, int y)
+{
+ unsigned int f = (x >> y) | (x << (64 - y));
+ unsigned int g = f;
+ asm volatile ("" : "+r" (f));
+ vv++; /* { dg-final { gdb-test 62 "g" "f" } } */
+ return f;
+}
+
+int
+main ()
+{
+ f1 (0x123456789abcde0fUL);
+ f2 (0x123456789abcde0fUL, 18);
+ f3 (0x123456789abcde0fUL, 17);
+ f4 (0x12345678);
+ f5 (0x12345678, 18);
+ f6 (0x12345678, 17);
+ return 0;
+}