Hi! This patch contains a bunch of smaller debug info improvements: 1) on the typeddwarf.c testcase on x86_64 there were completely needlessly many DW_OP_GNU_entry_value ops emitted, while the corresponding argument registers were still live. Fixed by the cselib_subst_to_values hunk. 2) var-tracking wasn't doing a good job with hard registers changing their mode, which happens very often e.g. on x86_64-linux. E.g. a DImode setter sets some register, but the following user can use just SImode from that register. cselib created a completely new VALUE for the SImode access, and cselib for a short time and var-tracking afterwards only knew that the VALUE was live in the corresponding hard register. Fixed by adding an additional location to the new VALUE, that it is the same thing as lowpart SUBREG of the older reg VALUE, from which we can find how it was set and where else the value might be live. 3) we can optimize ZERO_EXTEND, instead of using 6 bytes in location description for DW_OP_const1u <shift> DW_OP_shl DW_OP_const1u <shift> DW_OP_shr we can emit DW_OP_const{1,2,4}u <mask> DW_OP_and. For 4u it is already the same size, but at least fewer ops, for 8u it would be larger. 4) for signed modulo, if the operands are typed, we know the types are signed and thus can just use DW_OP_mod (which is unsigned modulo only for untyped operands, for typed ones the sign of operands matters) 5) this patch adds code to handle 9 new RTL codes
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2011-05-16 Jakub Jelinek <ja...@redhat.com> * cselib.c (promote_debug_loc): Allow l->next non-NULL for cselib_preserve_constants. (cselib_lookup_1): If cselib_preserve_constants, a new VALUE is being created for REG and there is a VALUE for the same register in wider mode, add another loc with lowpart SUBREG of the wider VALUE. (cselib_subst_to_values): Handle ENTRY_VALUE. * var-tracking.c (vt_expand_loc, vt_expand_loc_dummy): Increase max_depth from 8 to 10. * dwarf2out.c (convert_descriptor_to_signed): New function. (mem_loc_descriptor) <case ZERO_EXTEND>: Optimize using DW_OP_and instead of two shifts. (mem_loc_descriptor) <do_shift>: ZERO_EXTEND second argument to the right mode if needed. (mem_loc_descriptor) <case MOD>: For typed ops just use DW_OP_mod. (mem_loc_descriptor) <case UNSIGNED_FIX>: Use convert_descriptor_to_signed. (mem_loc_descriptor) <case UDIV, CLZ, CTZ, FFS, POPCOUNT, PARITY, BSWAP, ROTATE, ROTATERT>: Handle these rtls. * gcc.dg/guality/bswaptest.c: New test. * gcc.dg/guality/clztest.c: New test. * gcc.dg/guality/ctztest.c: New test. * gcc.dg/guality/rotatetest.c: New test. --- gcc/cselib.c.jj 2011-05-02 18:39:28.000000000 +0200 +++ gcc/cselib.c 2011-05-13 17:55:24.000000000 +0200 @@ -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; --- gcc/var-tracking.c.jj 2011-05-11 19:51:48.000000000 +0200 +++ gcc/var-tracking.c 2011-05-13 10:52:25.000000000 +0200 @@ -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; --- gcc/dwarf2out.c.jj 2011-05-11 19:39:04.000000000 +0200 +++ gcc/dwarf2out.c 2011-05-16 10:52:47.000000000 +0200 @@ -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: --- gcc/testsuite/gcc.dg/guality/bswaptest.c.jj 2011-05-13 22:20:24.000000000 +0200 +++ gcc/testsuite/gcc.dg/guality/bswaptest.c 2011-05-13 22:20:40.000000000 +0200 @@ -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; +} --- gcc/testsuite/gcc.dg/guality/clztest.c.jj 2011-05-13 14:09:41.000000000 +0200 +++ gcc/testsuite/gcc.dg/guality/clztest.c 2011-05-13 14:07:02.000000000 +0200 @@ -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; +} --- gcc/testsuite/gcc.dg/guality/ctztest.c.jj 2011-05-13 14:29:43.000000000 +0200 +++ gcc/testsuite/gcc.dg/guality/ctztest.c 2011-05-13 14:28:25.000000000 +0200 @@ -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; +} --- gcc/testsuite/gcc.dg/guality/rotatetest.c.jj 2011-05-16 10:58:45.000000000 +0200 +++ gcc/testsuite/gcc.dg/guality/rotatetest.c 2011-05-16 10:57:43.000000000 +0200 @@ -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; +} Jakub