lower-subreg.c (resolve_subreg_use): Remove assertion.

2007-08-07  Andreas Krebbel  <krebbel1@de.ibm.com>

	* lower-subreg.c (resolve_subreg_use): Remove assertion.
	(find_decomposable_shift_zext, resolve_shift_zext): New functions.
	(decompose_multiword_subregs): Use the functions above to decompose
	multiword shifts and zero-extends.

2007-08-07  Andreas Krebbel  <krebbel1@de.ibm.com>

	* gcc.dg/multiword-1.c: New testcase.

From-SVN: r127270
This commit is contained in:
Andreas Krebbel 2007-08-07 10:43:11 +00:00 committed by Andreas Krebbel
parent e492980b73
commit e0892570a8
4 changed files with 246 additions and 2 deletions

View File

@ -1,3 +1,10 @@
2007-08-07 Andreas Krebbel <krebbel1@de.ibm.com>
* lower-subreg.c (resolve_subreg_use): Remove assertion.
(find_decomposable_shift_zext, resolve_shift_zext): New functions.
(decompose_multiword_subregs): Use the functions above to decompose
multiword shifts and zero-extends.
2007-08-07 Rask Ingemann Lambertsen <rask@sygehus.dk>
* doc/sourcebuild.texi (Test Directives): Fix "compile" and

View File

@ -525,8 +525,8 @@ resolve_subreg_use (rtx *px, void *data)
{
/* Return 1 to the caller to indicate that we found a direct
reference to a register which is being decomposed. This can
happen inside notes. */
gcc_assert (!insn);
happen inside notes, multiword shift or zero-extend
instructions. */
return 1;
}
@ -944,6 +944,155 @@ resolve_use (rtx pat, rtx insn)
return false;
}
/* Checks if INSN is a decomposable multiword-shift or zero-extend and
sets the decomposable_context bitmap accordingly. A non-zero value
is returned if a decomposable insn has been found. */
static int
find_decomposable_shift_zext (rtx insn)
{
rtx set;
rtx op;
rtx op_operand;
set = single_set (insn);
if (!set)
return 0;
op = SET_SRC (set);
if (GET_CODE (op) != ASHIFT
&& GET_CODE (op) != LSHIFTRT
&& GET_CODE (op) != ZERO_EXTEND)
return 0;
op_operand = XEXP (op, 0);
if (!REG_P (SET_DEST (set)) || !REG_P (op_operand)
|| HARD_REGISTER_NUM_P (REGNO (SET_DEST (set)))
|| HARD_REGISTER_NUM_P (REGNO (op_operand))
|| !SCALAR_INT_MODE_P (GET_MODE (op)))
return 0;
if (GET_CODE (op) == ZERO_EXTEND)
{
if (GET_MODE (op_operand) != word_mode
|| GET_MODE_BITSIZE (GET_MODE (op)) != 2 * BITS_PER_WORD)
return 0;
}
else /* left or right shift */
{
if (GET_CODE (XEXP (op, 1)) != CONST_INT
|| INTVAL (XEXP (op, 1)) < BITS_PER_WORD
|| GET_MODE_BITSIZE (GET_MODE (op_operand)) != 2 * BITS_PER_WORD)
return 0;
}
bitmap_set_bit (decomposable_context, REGNO (SET_DEST (set)));
if (GET_CODE (op) != ZERO_EXTEND)
bitmap_set_bit (decomposable_context, REGNO (op_operand));
return 1;
}
/* Decompose a more than word wide shift (in INSN) of a multiword
pseudo or a multiword zero-extend of a wordmode pseudo into a move
and 'set to zero' insn. Return a pointer to the new insn when a
replacement was done. */
static rtx
resolve_shift_zext (rtx insn)
{
rtx set;
rtx op;
rtx op_operand;
rtx insns;
rtx src_reg, dest_reg, dest_zero;
int src_reg_num, dest_reg_num, offset1, offset2, src_offset;
set = single_set (insn);
if (!set)
return NULL_RTX;
op = SET_SRC (set);
if (GET_CODE (op) != ASHIFT
&& GET_CODE (op) != LSHIFTRT
&& GET_CODE (op) != ZERO_EXTEND)
return NULL_RTX;
op_operand = XEXP (op, 0);
if (!resolve_reg_p (SET_DEST (set)) && !resolve_reg_p (op_operand))
return NULL_RTX;
/* src_reg_num is the number of the word mode register which we
are operating on. For a left shift and a zero_extend on little
endian machines this is register 0. */
src_reg_num = GET_CODE (op) == LSHIFTRT ? 1 : 0;
if (WORDS_BIG_ENDIAN)
src_reg_num = 1 - src_reg_num;
if (GET_CODE (op) == ZERO_EXTEND)
dest_reg_num = src_reg_num;
else
dest_reg_num = 1 - src_reg_num;
offset1 = UNITS_PER_WORD * dest_reg_num;
offset2 = UNITS_PER_WORD * (1 - dest_reg_num);
src_offset = UNITS_PER_WORD * src_reg_num;
if (WORDS_BIG_ENDIAN != BYTES_BIG_ENDIAN)
{
offset1 += UNITS_PER_WORD - 1;
offset2 += UNITS_PER_WORD - 1;
src_offset += UNITS_PER_WORD - 1;
}
start_sequence ();
dest_reg = simplify_gen_subreg_concatn (word_mode, SET_DEST (set),
GET_MODE (SET_DEST (set)),
offset1);
dest_zero = simplify_gen_subreg_concatn (word_mode, SET_DEST (set),
GET_MODE (SET_DEST (set)),
offset2);
src_reg = simplify_gen_subreg_concatn (word_mode, op_operand,
GET_MODE (op_operand),
src_offset);
if (GET_CODE (op) != ZERO_EXTEND)
{
int shift_count = INTVAL (XEXP (op, 1));
if (shift_count > BITS_PER_WORD)
src_reg = expand_shift (GET_CODE (op) == ASHIFT ?
LSHIFT_EXPR : RSHIFT_EXPR,
word_mode, src_reg,
build_int_cst (NULL_TREE,
shift_count - BITS_PER_WORD),
dest_reg, 1);
}
if (dest_reg != src_reg)
emit_move_insn (dest_reg, src_reg);
emit_move_insn (dest_zero, CONST0_RTX (word_mode));
insns = get_insns ();
end_sequence ();
emit_insn_before (insns, insn);
if (dump_file)
{
rtx in;
fprintf (dump_file, "; Replacing insn: %d with insns: ", INSN_UID (insn));
for (in = insns; in != insn; in = NEXT_INSN (in))
fprintf (dump_file, "%d ", INSN_UID (in));
fprintf (dump_file, "\n");
}
delete_insn (insn);
return insns;
}
/* Look for registers which are always accessed via word-sized SUBREGs
or via copies. Decompose these registers into several word-sized
pseudo-registers. */
@ -1003,6 +1152,9 @@ decompose_multiword_subregs (void)
|| GET_CODE (PATTERN (insn)) == USE)
continue;
if (find_decomposable_shift_zext (insn))
continue;
recog_memoized (insn);
extract_insn (insn);
@ -1152,6 +1304,19 @@ decompose_multiword_subregs (void)
SET_BIT (sub_blocks, bb->index);
}
}
else
{
rtx decomposed_shift;
decomposed_shift = resolve_shift_zext (insn);
if (decomposed_shift != NULL_RTX)
{
changed = true;
insn = decomposed_shift;
recog_memoized (insn);
extract_insn (insn);
}
}
for (i = recog_data.n_operands - 1; i >= 0; --i)
for_each_rtx (recog_data.operand_loc[i],

View File

@ -1,3 +1,7 @@
2007-08-07 Andreas Krebbel <krebbel1@de.ibm.com>
* gcc.dg/multiword-1.c: New testcase.
2007-08-07 Daniel Franke <franke.daniel@gmail.com>
* gfortran.dg/namelist_33.f90: Improved tests, adjusted error

View File

@ -0,0 +1,68 @@
/* { dg-do run } */
/* { dg-options "-O3" } */
/* { dg-require-effective-target ilp32 } */
typedef unsigned int u32;
typedef unsigned long long u64;
u64 __attribute__((noinline))
foo (u32 high, u32 low)
{
return ((u64)high << 32) | low;
}
u32 __attribute__((noinline))
right (u64 t)
{
return (u32)(t >> 32);
}
u64 __attribute__((noinline))
left (u32 t)
{
return (u64)t << 32;
}
u32 __attribute__((noinline))
right2 (u64 t)
{
return (u32)(t >> 40);
}
u64 __attribute__((noinline))
left2 (u32 t)
{
return (u64)t << 40;
}
u64 __attribute__((noinline))
zeroextend (u32 t)
{
return (u64)t;
}
extern void abort ();
int
main ()
{
if (foo (13000, 12000) != 55834574860000ULL)
abort ();
if (right (55834574860000ULL) != 13000)
abort ();
if (left (13000) != 55834574848000ULL)
abort ();
if (right2 (55834574860000ULL) != 50)
abort ();
if (left2 (13000) != 14293651161088000ULL)
abort ();
if (zeroextend (13000) != 13000ULL)
abort ();
return 0;
}