rs6000-string.c (select_block_compare_mode): Check TARGET_EFFICIENT_OVERLAPPING_UNALIGNED here instead of in caller.

2018-06-19  Aaron Sawdey  <acsawdey@linux.ibm.com>

	* config/rs6000/rs6000-string.c (select_block_compare_mode): Check
	TARGET_EFFICIENT_OVERLAPPING_UNALIGNED here instead of in caller.
	(do_and3, do_and3_mask, do_compb3, do_rotl3): New functions.
	(expand_block_compare): Change select_block_compare_mode call.
	(expand_strncmp_align_check): Use new functions, fix comment.
	(emit_final_str_compare_gpr): New function.
	(expand_strn_compare): Refactor and clean up code.
	* config/rs6000/vsx.md (vsx_mov<mode>_64bit): Remove *.

From-SVN: r261769
This commit is contained in:
Aaron Sawdey 2018-06-19 21:23:39 +00:00 committed by Aaron Sawdey
parent 6a513e2a1b
commit f7e94dfb68
3 changed files with 185 additions and 190 deletions

View File

@ -1,3 +1,14 @@
2018-06-19 Aaron Sawdey <acsawdey@linux.ibm.com>
* config/rs6000/rs6000-string.c (select_block_compare_mode): Check
TARGET_EFFICIENT_OVERLAPPING_UNALIGNED here instead of in caller.
(do_and3, do_and3_mask, do_compb3, do_rotl3): New functions.
(expand_block_compare): Change select_block_compare_mode call.
(expand_strncmp_align_check): Use new functions, fix comment.
(emit_final_str_compare_gpr): New function.
(expand_strn_compare): Refactor and clean up code.
* config/rs6000/vsx.md (vsx_mov<mode>_64bit): Remove *.
2018-06-19 Tony Reix <tony.reix@atos.com>
Damien Bergamini <damien.bergamini@atos.com>
David Edelsohn <dje.gcc@gmail.com>

View File

@ -264,6 +264,7 @@ select_block_compare_mode (unsigned HOST_WIDE_INT offset,
else if (bytes == GET_MODE_SIZE (QImode))
return QImode;
else if (bytes < GET_MODE_SIZE (SImode)
&& TARGET_EFFICIENT_OVERLAPPING_UNALIGNED
&& offset >= GET_MODE_SIZE (SImode) - bytes)
/* This matches the case were we have SImode and 3 bytes
and offset >= 1 and permits us to move back one and overlap
@ -271,6 +272,7 @@ select_block_compare_mode (unsigned HOST_WIDE_INT offset,
unwanted bytes off of the input. */
return SImode;
else if (word_mode_ok && bytes < UNITS_PER_WORD
&& TARGET_EFFICIENT_OVERLAPPING_UNALIGNED
&& offset >= UNITS_PER_WORD-bytes)
/* Similarly, if we can use DImode it will get matched here and
can do an overlapping read that ends at the end of the block. */
@ -406,6 +408,54 @@ do_add3 (rtx dest, rtx src1, rtx src2)
emit_insn (gen_addsi3 (dest, src1, src2));
}
/* Emit an and of the proper mode for DEST.
DEST is the destination register for the and.
SRC1 is the first and input.
SRC2 is the second and input.
Computes DEST = SRC1&SRC2. */
static void
do_and3 (rtx dest, rtx src1, rtx src2)
{
if (GET_MODE (dest) == DImode)
emit_insn (gen_anddi3 (dest, src1, src2));
else
emit_insn (gen_andsi3 (dest, src1, src2));
}
/* Emit an cmpb of the proper mode for DEST.
DEST is the destination register for the cmpb.
SRC1 is the first input.
SRC2 is the second input.
Computes cmpb of SRC1, SRC2. */
static void
do_cmpb3 (rtx dest, rtx src1, rtx src2)
{
if (GET_MODE (dest) == DImode)
emit_insn (gen_cmpbdi3 (dest, src1, src2));
else
emit_insn (gen_cmpbsi3 (dest, src1, src2));
}
/* Emit a rotl of the proper mode for DEST.
DEST is the destination register for the and.
SRC1 is the first and input.
SRC2 is the second and input.
Computes DEST = SRC1 rotated left by SRC2. */
static void
do_rotl3 (rtx dest, rtx src1, rtx src2)
{
if (GET_MODE (dest) == DImode)
emit_insn (gen_rotldi3 (dest, src1, src2));
else
emit_insn (gen_rotlsi3 (dest, src1, src2));
}
/* Generate rtl for a load, shift, and compare of less than a full word.
LOAD_MODE is the machine mode for the loads.
@ -1393,11 +1443,8 @@ expand_block_compare (rtx operands[])
while (bytes > 0)
{
unsigned int align = compute_current_alignment (base_align, offset);
if (TARGET_EFFICIENT_OVERLAPPING_UNALIGNED)
load_mode = select_block_compare_mode (offset, bytes, align,
word_mode_ok);
else
load_mode = select_block_compare_mode (0, bytes, align, word_mode_ok);
load_mode = select_block_compare_mode (offset, bytes,
align, word_mode_ok);
load_mode_size = GET_MODE_SIZE (load_mode);
if (bytes >= load_mode_size)
cmp_bytes = load_mode_size;
@ -1625,22 +1672,19 @@ expand_block_compare (rtx operands[])
return true;
}
/* Generate alignment check and branch code to set up for
/* Generate page crossing check and branch code to set up for
strncmp when we don't have DI alignment.
STRNCMP_LABEL is the label to branch if there is a page crossing.
SRC is the string pointer to be examined.
SRC_ADDR is the string address to be examined.
BYTES is the max number of bytes to compare. */
static void
expand_strncmp_align_check (rtx strncmp_label, rtx src, HOST_WIDE_INT bytes)
expand_strncmp_align_check (rtx strncmp_label, rtx src_addr, HOST_WIDE_INT bytes)
{
rtx lab_ref = gen_rtx_LABEL_REF (VOIDmode, strncmp_label);
rtx src_check = copy_addr_to_reg (XEXP (src, 0));
if (GET_MODE (src_check) == SImode)
emit_insn (gen_andsi3 (src_check, src_check, GEN_INT (0xfff)));
else
emit_insn (gen_anddi3 (src_check, src_check, GEN_INT (0xfff)));
rtx src_pgoff = gen_reg_rtx (GET_MODE (src_addr));
do_and3 (src_pgoff, src_addr, GEN_INT (0xfff));
rtx cond = gen_reg_rtx (CCmode);
emit_move_insn (cond, gen_rtx_COMPARE (CCmode, src_check,
emit_move_insn (cond, gen_rtx_COMPARE (CCmode, src_pgoff,
GEN_INT (4096 - bytes)));
rtx cmp_rtx = gen_rtx_GE (VOIDmode, cond, const0_rtx);
@ -1652,6 +1696,76 @@ expand_strncmp_align_check (rtx strncmp_label, rtx src, HOST_WIDE_INT bytes)
LABEL_NUSES (strncmp_label) += 1;
}
/* Generate the final sequence that identifies the differing
byte and generates the final result, taking into account
zero bytes:
cmpb cmpb_result1, src1, src2
cmpb cmpb_result2, src1, zero
orc cmpb_result1, cmp_result1, cmpb_result2
cntlzd get bit of first zero/diff byte
addi convert for rldcl use
rldcl rldcl extract diff/zero byte
subf subtract for final result
STR1 is the reg rtx for data from string 1.
STR2 is the reg rtx for data from string 2.
RESULT is the reg rtx for the comparison result. */
static void
emit_final_str_compare_gpr (rtx str1, rtx str2, rtx result)
{
machine_mode m = GET_MODE (str1);
rtx cmpb_diff = gen_reg_rtx (m);
rtx cmpb_zero = gen_reg_rtx (m);
rtx rot_amt = gen_reg_rtx (m);
rtx zero_reg = gen_reg_rtx (m);
rtx rot1_1 = gen_reg_rtx (m);
rtx rot1_2 = gen_reg_rtx (m);
rtx rot2_1 = gen_reg_rtx (m);
rtx rot2_2 = gen_reg_rtx (m);
if (m == SImode)
{
emit_insn (gen_cmpbsi3 (cmpb_diff, str1, str2));
emit_insn (gen_movsi (zero_reg, GEN_INT (0)));
emit_insn (gen_cmpbsi3 (cmpb_zero, str1, zero_reg));
emit_insn (gen_one_cmplsi2 (cmpb_diff,cmpb_diff));
emit_insn (gen_iorsi3 (cmpb_diff, cmpb_diff, cmpb_zero));
emit_insn (gen_clzsi2 (rot_amt, cmpb_diff));
emit_insn (gen_addsi3 (rot_amt, rot_amt, GEN_INT (8)));
emit_insn (gen_rotlsi3 (rot1_1, str1,
gen_lowpart (SImode, rot_amt)));
emit_insn (gen_andsi3_mask (rot1_2, rot1_1, GEN_INT (0xff)));
emit_insn (gen_rotlsi3 (rot2_1, str2,
gen_lowpart (SImode, rot_amt)));
emit_insn (gen_andsi3_mask (rot2_2, rot2_1, GEN_INT (0xff)));
emit_insn (gen_subsi3 (result, rot1_2, rot2_2));
}
else if (m == DImode)
{
emit_insn (gen_cmpbdi3 (cmpb_diff, str1, str2));
emit_insn (gen_movdi (zero_reg, GEN_INT (0)));
emit_insn (gen_cmpbdi3 (cmpb_zero, str1, zero_reg));
emit_insn (gen_one_cmpldi2 (cmpb_diff,cmpb_diff));
emit_insn (gen_iordi3 (cmpb_diff, cmpb_diff, cmpb_zero));
emit_insn (gen_clzdi2 (rot_amt, cmpb_diff));
emit_insn (gen_adddi3 (rot_amt, rot_amt, GEN_INT (8)));
emit_insn (gen_rotldi3 (rot1_1, str1,
gen_lowpart (SImode, rot_amt)));
emit_insn (gen_anddi3_mask (rot1_2, rot1_1, GEN_INT (0xff)));
emit_insn (gen_rotldi3 (rot2_1, str2,
gen_lowpart (SImode, rot_amt)));
emit_insn (gen_anddi3_mask (rot2_2, rot2_1, GEN_INT (0xff)));
emit_insn (gen_subdi3 (result, rot1_2, rot2_2));
}
else
gcc_unreachable ();
return;
}
/* Expand a string compare operation with length, and return
true if successful. Return false if we should let the
compiler generate normal code, probably a strncmp call.
@ -1682,8 +1796,8 @@ expand_strn_compare (rtx operands[], int no_length)
align_rtx = operands[4];
}
unsigned HOST_WIDE_INT cmp_bytes = 0;
rtx src1 = orig_src1;
rtx src2 = orig_src2;
rtx src1_addr = force_reg (Pmode, XEXP (orig_src1, 0));
rtx src2_addr = force_reg (Pmode, XEXP (orig_src2, 0));
/* If we have a length, it must be constant. This simplifies things
a bit as we don't have to generate code to check if we've exceeded
@ -1696,8 +1810,8 @@ expand_strn_compare (rtx operands[], int no_length)
return false;
unsigned int base_align = UINTVAL (align_rtx);
int align1 = MEM_ALIGN (orig_src1) / BITS_PER_UNIT;
int align2 = MEM_ALIGN (orig_src2) / BITS_PER_UNIT;
unsigned int align1 = MEM_ALIGN (orig_src1) / BITS_PER_UNIT;
unsigned int align2 = MEM_ALIGN (orig_src2) / BITS_PER_UNIT;
/* targetm.slow_unaligned_access -- don't do unaligned stuff. */
if (targetm.slow_unaligned_access (word_mode, align1)
@ -1749,8 +1863,9 @@ expand_strn_compare (rtx operands[], int no_length)
rtx final_move_label = gen_label_rtx ();
rtx final_label = gen_label_rtx ();
rtx begin_compare_label = NULL;
unsigned int required_align = 8;
if (base_align < 8)
if (base_align < required_align)
{
/* Generate code that checks distance to 4k boundary for this case. */
begin_compare_label = gen_label_rtx ();
@ -1773,14 +1888,14 @@ expand_strn_compare (rtx operands[], int no_length)
}
else
{
align_test = ROUND_UP (align_test, 8);
base_align = 8;
align_test = ROUND_UP (align_test, required_align);
base_align = required_align;
}
if (align1 < 8)
expand_strncmp_align_check (strncmp_label, src1, align_test);
if (align2 < 8)
expand_strncmp_align_check (strncmp_label, src2, align_test);
if (align1 < required_align)
expand_strncmp_align_check (strncmp_label, src1_addr, align_test);
if (align2 < required_align)
expand_strncmp_align_check (strncmp_label, src2_addr, align_test);
/* Now generate the following sequence:
- branch to begin_compare
@ -1797,25 +1912,13 @@ expand_strn_compare (rtx operands[], int no_length)
emit_label (strncmp_label);
if (!REG_P (XEXP (src1, 0)))
{
rtx src1_reg = copy_addr_to_reg (XEXP (src1, 0));
src1 = replace_equiv_address (src1, src1_reg);
}
if (!REG_P (XEXP (src2, 0)))
{
rtx src2_reg = copy_addr_to_reg (XEXP (src2, 0));
src2 = replace_equiv_address (src2, src2_reg);
}
if (no_length)
{
tree fun = builtin_decl_explicit (BUILT_IN_STRCMP);
emit_library_call_value (XEXP (DECL_RTL (fun), 0),
target, LCT_NORMAL, GET_MODE (target),
force_reg (Pmode, XEXP (src1, 0)), Pmode,
force_reg (Pmode, XEXP (src2, 0)), Pmode);
force_reg (Pmode, src1_addr), Pmode,
force_reg (Pmode, src2_addr), Pmode);
}
else
{
@ -1833,8 +1936,8 @@ expand_strn_compare (rtx operands[], int no_length)
tree fun = builtin_decl_explicit (BUILT_IN_STRNCMP);
emit_library_call_value (XEXP (DECL_RTL (fun), 0),
target, LCT_NORMAL, GET_MODE (target),
force_reg (Pmode, XEXP (src1, 0)), Pmode,
force_reg (Pmode, XEXP (src2, 0)), Pmode,
force_reg (Pmode, src1_addr), Pmode,
force_reg (Pmode, src2_addr), Pmode,
len_rtx, GET_MODE (len_rtx));
}
@ -1850,12 +1953,12 @@ expand_strn_compare (rtx operands[], int no_length)
rtx tmp_reg_src1 = gen_reg_rtx (word_mode);
rtx tmp_reg_src2 = gen_reg_rtx (word_mode);
/* Generate sequence of ld/ldbrx, cmpb to compare out
/* Generate a sequence of GPR or VEC/VSX instructions to compare out
to the length specified. */
unsigned HOST_WIDE_INT bytes_to_compare = compare_length;
while (bytes_to_compare > 0)
{
/* Compare sequence:
/* GPR compare sequence:
check each 8B with: ld/ld cmpd bne
If equal, use rldicr/cmpb to check for zero byte.
cleanup code at end:
@ -1869,13 +1972,10 @@ expand_strn_compare (rtx operands[], int no_length)
The last compare can branch around the cleanup code if the
result is zero because the strings are exactly equal. */
unsigned int align = compute_current_alignment (base_align, offset);
if (TARGET_EFFICIENT_OVERLAPPING_UNALIGNED)
load_mode = select_block_compare_mode (offset, bytes_to_compare, align,
word_mode_ok);
else
load_mode = select_block_compare_mode (0, bytes_to_compare, align,
word_mode_ok);
load_mode = select_block_compare_mode (offset, bytes_to_compare,
align, word_mode_ok);
load_mode_size = GET_MODE_SIZE (load_mode);
if (bytes_to_compare >= load_mode_size)
cmp_bytes = load_mode_size;
@ -1898,25 +1998,10 @@ expand_strn_compare (rtx operands[], int no_length)
rid of the extra bytes. */
cmp_bytes = bytes_to_compare;
src1 = adjust_address (orig_src1, load_mode, offset);
src2 = adjust_address (orig_src2, load_mode, offset);
if (!REG_P (XEXP (src1, 0)))
{
rtx src1_reg = copy_addr_to_reg (XEXP (src1, 0));
src1 = replace_equiv_address (src1, src1_reg);
}
set_mem_size (src1, load_mode_size);
if (!REG_P (XEXP (src2, 0)))
{
rtx src2_reg = copy_addr_to_reg (XEXP (src2, 0));
src2 = replace_equiv_address (src2, src2_reg);
}
set_mem_size (src2, load_mode_size);
do_load_for_compare (tmp_reg_src1, src1, load_mode);
do_load_for_compare (tmp_reg_src2, src2, load_mode);
rtx addr1 = gen_rtx_PLUS (Pmode, src1_addr, GEN_INT (offset));
do_load_for_compare_from_addr (load_mode, tmp_reg_src1, addr1, orig_src1);
rtx addr2 = gen_rtx_PLUS (Pmode, src2_addr, GEN_INT (offset));
do_load_for_compare_from_addr (load_mode, tmp_reg_src2, addr2, orig_src2);
/* We must always left-align the data we read, and
clear any bytes to the right that are beyond the string.
@ -1929,16 +2014,8 @@ expand_strn_compare (rtx operands[], int no_length)
{
/* Rotate left first. */
rtx sh = GEN_INT (BITS_PER_UNIT * (word_mode_size - load_mode_size));
if (word_mode == DImode)
{
emit_insn (gen_rotldi3 (tmp_reg_src1, tmp_reg_src1, sh));
emit_insn (gen_rotldi3 (tmp_reg_src2, tmp_reg_src2, sh));
}
else
{
emit_insn (gen_rotlsi3 (tmp_reg_src1, tmp_reg_src1, sh));
emit_insn (gen_rotlsi3 (tmp_reg_src2, tmp_reg_src2, sh));
}
do_rotl3 (tmp_reg_src1, tmp_reg_src1, sh);
do_rotl3 (tmp_reg_src2, tmp_reg_src2, sh);
}
if (cmp_bytes < word_mode_size)
@ -1947,16 +2024,8 @@ expand_strn_compare (rtx operands[], int no_length)
turned into a rldicr instruction. */
HOST_WIDE_INT mb = BITS_PER_UNIT * (word_mode_size - cmp_bytes);
rtx mask = GEN_INT (HOST_WIDE_INT_M1U << mb);
if (word_mode == DImode)
{
emit_insn (gen_anddi3_mask (tmp_reg_src1, tmp_reg_src1, mask));
emit_insn (gen_anddi3_mask (tmp_reg_src2, tmp_reg_src2, mask));
}
else
{
emit_insn (gen_andsi3_mask (tmp_reg_src1, tmp_reg_src1, mask));
emit_insn (gen_andsi3_mask (tmp_reg_src2, tmp_reg_src2, mask));
}
do_and3 (tmp_reg_src1, tmp_reg_src1, mask);
do_and3 (tmp_reg_src2, tmp_reg_src2, mask);
}
/* Cases to handle. A and B are chunks of the two strings.
@ -2013,31 +2082,16 @@ expand_strn_compare (rtx operands[], int no_length)
rtx lab_ref_fin = gen_rtx_LABEL_REF (VOIDmode, final_move_label);
rtx condz = gen_reg_rtx (CCmode);
rtx zero_reg = gen_reg_rtx (word_mode);
if (word_mode == SImode)
emit_move_insn (zero_reg, GEN_INT (0));
do_cmpb3 (cmpb_zero, tmp_reg_src1, zero_reg);
if (cmp_bytes < word_mode_size)
{
emit_insn (gen_movsi (zero_reg, GEN_INT (0)));
emit_insn (gen_cmpbsi3 (cmpb_zero, tmp_reg_src1, zero_reg));
if (cmp_bytes < word_mode_size)
{
/* Don't want to look at zero bytes past end. */
HOST_WIDE_INT mb =
BITS_PER_UNIT * (word_mode_size - cmp_bytes);
rtx mask = GEN_INT (HOST_WIDE_INT_M1U << mb);
emit_insn (gen_andsi3_mask (cmpb_zero, cmpb_zero, mask));
}
}
else
{
emit_insn (gen_movdi (zero_reg, GEN_INT (0)));
emit_insn (gen_cmpbdi3 (cmpb_zero, tmp_reg_src1, zero_reg));
if (cmp_bytes < word_mode_size)
{
/* Don't want to look at zero bytes past end. */
HOST_WIDE_INT mb =
BITS_PER_UNIT * (word_mode_size - cmp_bytes);
rtx mask = GEN_INT (HOST_WIDE_INT_M1U << mb);
emit_insn (gen_anddi3_mask (cmpb_zero, cmpb_zero, mask));
}
/* Don't want to look at zero bytes past end. */
HOST_WIDE_INT mb =
BITS_PER_UNIT * (word_mode_size - cmp_bytes);
rtx mask = GEN_INT (HOST_WIDE_INT_M1U << mb);
do_and3 (cmpb_zero, cmpb_zero, mask);
}
emit_move_insn (condz, gen_rtx_COMPARE (CCmode, cmpb_zero, zero_reg));
@ -2057,22 +2111,10 @@ expand_strn_compare (rtx operands[], int no_length)
if (equality_compare_rest)
{
/* Update pointers past what has been compared already. */
src1 = adjust_address (orig_src1, load_mode, offset);
src2 = adjust_address (orig_src2, load_mode, offset);
if (!REG_P (XEXP (src1, 0)))
{
rtx src1_reg = copy_addr_to_reg (XEXP (src1, 0));
src1 = replace_equiv_address (src1, src1_reg);
}
set_mem_size (src1, load_mode_size);
if (!REG_P (XEXP (src2, 0)))
{
rtx src2_reg = copy_addr_to_reg (XEXP (src2, 0));
src2 = replace_equiv_address (src2, src2_reg);
}
set_mem_size (src2, load_mode_size);
rtx src1 = force_reg (Pmode,
gen_rtx_PLUS (Pmode, src1_addr, GEN_INT (offset)));
rtx src2 = force_reg (Pmode,
gen_rtx_PLUS (Pmode, src2_addr, GEN_INT (offset)));
/* Construct call to strcmp/strncmp to compare the rest of the string. */
if (no_length)
@ -2080,8 +2122,7 @@ expand_strn_compare (rtx operands[], int no_length)
tree fun = builtin_decl_explicit (BUILT_IN_STRCMP);
emit_library_call_value (XEXP (DECL_RTL (fun), 0),
target, LCT_NORMAL, GET_MODE (target),
force_reg (Pmode, XEXP (src1, 0)), Pmode,
force_reg (Pmode, XEXP (src2, 0)), Pmode);
src1, Pmode, src2, Pmode);
}
else
{
@ -2095,8 +2136,7 @@ expand_strn_compare (rtx operands[], int no_length)
tree fun = builtin_decl_explicit (BUILT_IN_STRNCMP);
emit_library_call_value (XEXP (DECL_RTL (fun), 0),
target, LCT_NORMAL, GET_MODE (target),
force_reg (Pmode, XEXP (src1, 0)), Pmode,
force_reg (Pmode, XEXP (src2, 0)), Pmode,
src1, Pmode, src2, Pmode,
len_rtx, GET_MODE (len_rtx));
}
@ -2110,63 +2150,7 @@ expand_strn_compare (rtx operands[], int no_length)
if (cleanup_label)
emit_label (cleanup_label);
/* Generate the final sequence that identifies the differing
byte and generates the final result, taking into account
zero bytes:
cmpb cmpb_result1, src1, src2
cmpb cmpb_result2, src1, zero
orc cmpb_result1, cmp_result1, cmpb_result2
cntlzd get bit of first zero/diff byte
addi convert for rldcl use
rldcl rldcl extract diff/zero byte
subf subtract for final result
*/
rtx cmpb_diff = gen_reg_rtx (word_mode);
rtx cmpb_zero = gen_reg_rtx (word_mode);
rtx rot_amt = gen_reg_rtx (word_mode);
rtx zero_reg = gen_reg_rtx (word_mode);
rtx rot1_1 = gen_reg_rtx (word_mode);
rtx rot1_2 = gen_reg_rtx (word_mode);
rtx rot2_1 = gen_reg_rtx (word_mode);
rtx rot2_2 = gen_reg_rtx (word_mode);
if (word_mode == SImode)
{
emit_insn (gen_cmpbsi3 (cmpb_diff, tmp_reg_src1, tmp_reg_src2));
emit_insn (gen_movsi (zero_reg, GEN_INT (0)));
emit_insn (gen_cmpbsi3 (cmpb_zero, tmp_reg_src1, zero_reg));
emit_insn (gen_one_cmplsi2 (cmpb_diff,cmpb_diff));
emit_insn (gen_iorsi3 (cmpb_diff, cmpb_diff, cmpb_zero));
emit_insn (gen_clzsi2 (rot_amt, cmpb_diff));
emit_insn (gen_addsi3 (rot_amt, rot_amt, GEN_INT (8)));
emit_insn (gen_rotlsi3 (rot1_1, tmp_reg_src1,
gen_lowpart (SImode, rot_amt)));
emit_insn (gen_andsi3_mask (rot1_2, rot1_1, GEN_INT (0xff)));
emit_insn (gen_rotlsi3 (rot2_1, tmp_reg_src2,
gen_lowpart (SImode, rot_amt)));
emit_insn (gen_andsi3_mask (rot2_2, rot2_1, GEN_INT (0xff)));
emit_insn (gen_subsi3 (result_reg, rot1_2, rot2_2));
}
else
{
emit_insn (gen_cmpbdi3 (cmpb_diff, tmp_reg_src1, tmp_reg_src2));
emit_insn (gen_movdi (zero_reg, GEN_INT (0)));
emit_insn (gen_cmpbdi3 (cmpb_zero, tmp_reg_src1, zero_reg));
emit_insn (gen_one_cmpldi2 (cmpb_diff,cmpb_diff));
emit_insn (gen_iordi3 (cmpb_diff, cmpb_diff, cmpb_zero));
emit_insn (gen_clzdi2 (rot_amt, cmpb_diff));
emit_insn (gen_adddi3 (rot_amt, rot_amt, GEN_INT (8)));
emit_insn (gen_rotldi3 (rot1_1, tmp_reg_src1,
gen_lowpart (SImode, rot_amt)));
emit_insn (gen_anddi3_mask (rot1_2, rot1_1, GEN_INT (0xff)));
emit_insn (gen_rotldi3 (rot2_1, tmp_reg_src2,
gen_lowpart (SImode, rot_amt)));
emit_insn (gen_anddi3_mask (rot2_2, rot2_1, GEN_INT (0xff)));
emit_insn (gen_subdi3 (result_reg, rot1_2, rot2_2));
}
emit_final_str_compare_gpr (tmp_reg_src1, tmp_reg_src2, result_reg);
emit_label (final_move_label);
emit_insn (gen_movsi (target,

View File

@ -1194,7 +1194,7 @@
;; VSX store VSX load VSX move VSX->GPR GPR->VSX LQ (GPR)
;; STQ (GPR) GPR load GPR store GPR move XXSPLTIB VSPLTISW
;; VSX 0/-1 GPR 0/-1 VMX const GPR const LVX (VMX) STVX (VMX)
(define_insn "*vsx_mov<mode>_64bit"
(define_insn "vsx_mov<mode>_64bit"
[(set (match_operand:VSX_M 0 "nonimmediate_operand"
"=ZwO, <VSa>, <VSa>, r, we, ?wQ,
?&r, ??r, ??Y, <??r>, wo, v,