mirror of git://gcc.gnu.org/git/gcc.git
* expmed.c (extract_force_align_mem_bit_field): Remove.
From-SVN: r133858
This commit is contained in:
parent
55187c8a16
commit
9e0aebcaee
|
|
@ -1,3 +1,7 @@
|
|||
2008-04-03 Ben Elliston <bje@au.ibm.com>
|
||||
|
||||
* expmed.c (extract_force_align_mem_bit_field): Remove.
|
||||
|
||||
2008-04-03 Richard Guenther <rguenther@suse.de>
|
||||
|
||||
PR middle-end/35800
|
||||
|
|
|
|||
146
gcc/expmed.c
146
gcc/expmed.c
|
|
@ -1835,152 +1835,6 @@ lshift_value (enum machine_mode mode, rtx value, int bitpos, int bitsize)
|
|||
return immed_double_const (low, high, mode);
|
||||
}
|
||||
|
||||
/* Extract a bit field from a memory by forcing the alignment of the
|
||||
memory. This efficient only if the field spans at least 4 boundaries.
|
||||
|
||||
OP0 is the MEM.
|
||||
BITSIZE is the field width; BITPOS is the position of the first bit.
|
||||
UNSIGNEDP is true if the result should be zero-extended. */
|
||||
|
||||
static rtx
|
||||
extract_force_align_mem_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize,
|
||||
unsigned HOST_WIDE_INT bitpos,
|
||||
int unsignedp)
|
||||
{
|
||||
enum machine_mode mode, dmode;
|
||||
unsigned int m_bitsize, m_size;
|
||||
unsigned int sign_shift_up, sign_shift_dn;
|
||||
rtx base, a1, a2, v1, v2, comb, shift, result, start;
|
||||
|
||||
/* Choose a mode that will fit BITSIZE. */
|
||||
mode = smallest_mode_for_size (bitsize, MODE_INT);
|
||||
m_size = GET_MODE_SIZE (mode);
|
||||
m_bitsize = GET_MODE_BITSIZE (mode);
|
||||
|
||||
/* Choose a mode twice as wide. Fail if no such mode exists. */
|
||||
dmode = mode_for_size (m_bitsize * 2, MODE_INT, false);
|
||||
if (dmode == BLKmode)
|
||||
return NULL;
|
||||
|
||||
do_pending_stack_adjust ();
|
||||
start = get_last_insn ();
|
||||
|
||||
/* At the end, we'll need an additional shift to deal with sign/zero
|
||||
extension. By default this will be a left+right shift of the
|
||||
appropriate size. But we may be able to eliminate one of them. */
|
||||
sign_shift_up = sign_shift_dn = m_bitsize - bitsize;
|
||||
|
||||
if (STRICT_ALIGNMENT)
|
||||
{
|
||||
base = plus_constant (XEXP (op0, 0), bitpos / BITS_PER_UNIT);
|
||||
bitpos %= BITS_PER_UNIT;
|
||||
|
||||
/* We load two values to be concatenate. There's an edge condition
|
||||
that bears notice -- an aligned value at the end of a page can
|
||||
only load one value lest we segfault. So the two values we load
|
||||
are at "base & -size" and "(base + size - 1) & -size". If base
|
||||
is unaligned, the addresses will be aligned and sequential; if
|
||||
base is aligned, the addresses will both be equal to base. */
|
||||
|
||||
a1 = expand_simple_binop (Pmode, AND, force_operand (base, NULL),
|
||||
GEN_INT (-(HOST_WIDE_INT)m_size),
|
||||
NULL, true, OPTAB_LIB_WIDEN);
|
||||
mark_reg_pointer (a1, m_bitsize);
|
||||
v1 = gen_rtx_MEM (mode, a1);
|
||||
set_mem_align (v1, m_bitsize);
|
||||
v1 = force_reg (mode, validize_mem (v1));
|
||||
|
||||
a2 = plus_constant (base, GET_MODE_SIZE (mode) - 1);
|
||||
a2 = expand_simple_binop (Pmode, AND, force_operand (a2, NULL),
|
||||
GEN_INT (-(HOST_WIDE_INT)m_size),
|
||||
NULL, true, OPTAB_LIB_WIDEN);
|
||||
v2 = gen_rtx_MEM (mode, a2);
|
||||
set_mem_align (v2, m_bitsize);
|
||||
v2 = force_reg (mode, validize_mem (v2));
|
||||
|
||||
/* Combine these two values into a double-word value. */
|
||||
if (m_bitsize == BITS_PER_WORD)
|
||||
{
|
||||
comb = gen_reg_rtx (dmode);
|
||||
emit_insn (gen_rtx_CLOBBER (VOIDmode, comb));
|
||||
emit_move_insn (gen_rtx_SUBREG (mode, comb, 0), v1);
|
||||
emit_move_insn (gen_rtx_SUBREG (mode, comb, m_size), v2);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (BYTES_BIG_ENDIAN)
|
||||
comb = v1, v1 = v2, v2 = comb;
|
||||
v1 = convert_modes (dmode, mode, v1, true);
|
||||
if (v1 == NULL)
|
||||
goto fail;
|
||||
v2 = convert_modes (dmode, mode, v2, true);
|
||||
v2 = expand_simple_binop (dmode, ASHIFT, v2, GEN_INT (m_bitsize),
|
||||
NULL, true, OPTAB_LIB_WIDEN);
|
||||
if (v2 == NULL)
|
||||
goto fail;
|
||||
comb = expand_simple_binop (dmode, IOR, v1, v2, NULL,
|
||||
true, OPTAB_LIB_WIDEN);
|
||||
if (comb == NULL)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
shift = expand_simple_binop (Pmode, AND, base, GEN_INT (m_size - 1),
|
||||
NULL, true, OPTAB_LIB_WIDEN);
|
||||
shift = expand_mult (Pmode, shift, GEN_INT (BITS_PER_UNIT), NULL, 1);
|
||||
|
||||
if (bitpos != 0)
|
||||
{
|
||||
if (sign_shift_up <= bitpos)
|
||||
bitpos -= sign_shift_up, sign_shift_up = 0;
|
||||
shift = expand_simple_binop (Pmode, PLUS, shift, GEN_INT (bitpos),
|
||||
NULL, true, OPTAB_LIB_WIDEN);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned HOST_WIDE_INT offset = bitpos / BITS_PER_UNIT;
|
||||
bitpos %= BITS_PER_UNIT;
|
||||
|
||||
/* When strict alignment is not required, we can just load directly
|
||||
from memory without masking. If the remaining BITPOS offset is
|
||||
small enough, we may be able to do all operations in MODE as
|
||||
opposed to DMODE. */
|
||||
if (bitpos + bitsize <= m_bitsize)
|
||||
dmode = mode;
|
||||
comb = adjust_address (op0, dmode, offset);
|
||||
|
||||
if (sign_shift_up <= bitpos)
|
||||
bitpos -= sign_shift_up, sign_shift_up = 0;
|
||||
shift = GEN_INT (bitpos);
|
||||
}
|
||||
|
||||
/* Shift down the double-word such that the requested value is at bit 0. */
|
||||
if (shift != const0_rtx)
|
||||
comb = expand_simple_binop (dmode, unsignedp ? LSHIFTRT : ASHIFTRT,
|
||||
comb, shift, NULL, unsignedp, OPTAB_LIB_WIDEN);
|
||||
if (comb == NULL)
|
||||
goto fail;
|
||||
|
||||
/* If the field exactly matches MODE, then all we need to do is return the
|
||||
lowpart. Otherwise, shift to get the sign bits set properly. */
|
||||
result = force_reg (mode, gen_lowpart (mode, comb));
|
||||
|
||||
if (sign_shift_up)
|
||||
result = expand_simple_binop (mode, ASHIFT, result,
|
||||
GEN_INT (sign_shift_up),
|
||||
NULL_RTX, 0, OPTAB_LIB_WIDEN);
|
||||
if (sign_shift_dn)
|
||||
result = expand_simple_binop (mode, unsignedp ? LSHIFTRT : ASHIFTRT,
|
||||
result, GEN_INT (sign_shift_dn),
|
||||
NULL_RTX, 0, OPTAB_LIB_WIDEN);
|
||||
|
||||
return result;
|
||||
|
||||
fail:
|
||||
delete_insns_since (start);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Extract a bit field that is split across two words
|
||||
and return an RTX for the result.
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue