re PR target/66217 (PowerPC rotate/shift/mask instructions not optimal)
PR target/66217 * config/rs6000/constraints.md ("S", "T", "t"): Delete. Update "available letters" comment. * config/rs6000/predicates.md (mask_operand, mask_operand_wrap, mask64_operand, mask64_2_operand, any_mask_operand, and64_2_operand, and_2rld_operand): Delete. (and_operand): Adjust. (rotate_mask_operator): New. * config/rs6000/rs6000-protos.h (build_mask64_2_operands, includes_lshift_p, includes_rshift_p, includes_rldic_lshift_p, includes_rldicr_lshift_p, insvdi_rshift_rlwimi_p, extract_MB, extract_ME): Delete. (rs6000_is_valid_mask, rs6000_is_valid_and_mask, rs6000_is_valid_shift_mask, rs6000_is_valid_insert_mask, rs6000_insn_for_and_mask, rs6000_insn_for_shift_mask, rs6000_insn_for_insert_mask, rs6000_is_valid_2insn_and, rs6000_emit_2insn_and): New. * config/rs6000/rs6000.c (num_insns_constant): Adjust. (build_mask64_2_operands, includes_lshift_p, includes_rshift_p, includes_rldic_lshift_p, includes_rldicr_lshift_p, insvdi_rshift_rlwimi_p, extract_MB, extract_ME): Delete. (rs6000_is_valid_mask, rs6000_is_valid_and_mask, rs6000_insn_for_and_mask, rs6000_is_valid_shift_mask, s6000_insn_for_shift_mask, rs6000_is_valid_insert_mask, rs6000_insn_for_insert_mask, rs6000_is_valid_2insn_and, rs6000_emit_2insn_and): New. (print_operand) <'b', 'B', 'm', 'M', 's', 'S', 'W'>: Delete. (rs6000_rtx_costs) <CONST_INT>: Delete mask_operand and mask64_operand handling. <NOT>: Don't fall through to next case. <AND>: Handle the various rotate-and-mask cases directly. <IOR>: Always cost as one insn. * config/rs6000/rs6000.md (splitter for bswap:SI): Adjust. (and<mode>3): Adjust expander for the new patterns. (and<mode>3_imm, and<mode>3_imm_dot, and<mode>3_imm_dot2, and<mode>3_imm_mask_dot, and<mode>3_imm_mask_dot2): Adjust condition. (*and<mode>3_imm_dot_shifted): New. (*and<mode>3_mask): Delete, rewrite as ... (and<mode>3_mask): ... New. (*and<mode>3_mask_dot, *and<mode>3_mask_dot): Rewrite. (andsi3_internal0_nomc): Delete. (*andsi3_internal6): Delete. (*and<mode>3_2insn): New. (insv, insvsi_internal, *insvsi_internal1, *insvsi_internal2, *insvsi_internal3, *insvsi_internal4, *insvsi_internal5, *insvsi_internal6, insvdi_internal, *insvdi_internal2, *insvdi_internal3): Delete. (*rotl<mode>3_mask, *rotl<mode>3_mask_dot, *rotl<mode>3_mask_dot2, *rotl<mode>3_insert, *rotl<mode>3_insert_2, *rotl<mode>3_insert_3, *rotl<mode>3_insert_4, two splitters for multi-precision shifts, *ior<mode>_mask): New. (extzv, extzvdi_internal, *extzvdi_internal1, *extzvdi_internal2, *rotlsi3_mask, *rotlsi3_mask_dot, *rotlsi3_mask_dot2, *ashlsi3_imm_mask, *ashlsi3_imm_mask_dot, *ashlsi3_imm_mask_dot2, *lshrsi3_imm_mask, *lshrsi3_imm_mask_dot, *lshrsi3_imm_mask_dot2): Delete. (ashr<mode>3): Delete expander. (*ashr<mode>3): Rename to ... (ashr<mode>3): ... This. (ashrdi3_no_power, *ashrdisi3_noppc64be): Delete. (*rotldi3_internal4, *rotldi3_internal5 and split, *rotldi3_internal6 and split, *ashldi3_internal4, ashldi3_internal5 and split, *ashldi3_internal6 and split, *ashldi3_internal7, ashldi3_internal8 and split, *ashldi3_internal9 and split): Delete. (*anddi3_2rld, *anddi3_2rld_dot, *anddi3_2rld_dot2): Delete. (splitter for loading a mask): Adjust. * doc/md.texi (Machine Constraints): Remove q, S, T, t constraints. From-SVN: r226005
This commit is contained in:
parent
f3e9a059a7
commit
7fc5cca388
|
@ -1,3 +1,73 @@
|
|||
2015-07-20 Segher Boessenkool <segher@kernel.crashing.org>
|
||||
|
||||
PR target/66217
|
||||
* config/rs6000/constraints.md ("S", "T", "t"): Delete. Update
|
||||
"available letters" comment.
|
||||
* config/rs6000/predicates.md (mask_operand, mask_operand_wrap,
|
||||
mask64_operand, mask64_2_operand, any_mask_operand, and64_2_operand,
|
||||
and_2rld_operand): Delete.
|
||||
(and_operand): Adjust.
|
||||
(rotate_mask_operator): New.
|
||||
* config/rs6000/rs6000-protos.h (build_mask64_2_operands,
|
||||
includes_lshift_p, includes_rshift_p, includes_rldic_lshift_p,
|
||||
includes_rldicr_lshift_p, insvdi_rshift_rlwimi_p, extract_MB,
|
||||
extract_ME): Delete.
|
||||
(rs6000_is_valid_mask, rs6000_is_valid_and_mask,
|
||||
rs6000_is_valid_shift_mask, rs6000_is_valid_insert_mask,
|
||||
rs6000_insn_for_and_mask, rs6000_insn_for_shift_mask,
|
||||
rs6000_insn_for_insert_mask, rs6000_is_valid_2insn_and,
|
||||
rs6000_emit_2insn_and): New.
|
||||
* config/rs6000/rs6000.c (num_insns_constant): Adjust.
|
||||
(build_mask64_2_operands, includes_lshift_p, includes_rshift_p,
|
||||
includes_rldic_lshift_p, includes_rldicr_lshift_p,
|
||||
insvdi_rshift_rlwimi_p, extract_MB, extract_ME): Delete.
|
||||
(rs6000_is_valid_mask, rs6000_is_valid_and_mask,
|
||||
rs6000_insn_for_and_mask, rs6000_is_valid_shift_mask,
|
||||
s6000_insn_for_shift_mask, rs6000_is_valid_insert_mask,
|
||||
rs6000_insn_for_insert_mask, rs6000_is_valid_2insn_and,
|
||||
rs6000_emit_2insn_and): New.
|
||||
(print_operand) <'b', 'B', 'm', 'M', 's', 'S', 'W'>: Delete.
|
||||
(rs6000_rtx_costs) <CONST_INT>: Delete mask_operand and mask64_operand
|
||||
handling.
|
||||
<NOT>: Don't fall through to next case.
|
||||
<AND>: Handle the various rotate-and-mask cases directly.
|
||||
<IOR>: Always cost as one insn.
|
||||
* config/rs6000/rs6000.md (splitter for bswap:SI): Adjust.
|
||||
(and<mode>3): Adjust expander for the new patterns.
|
||||
(and<mode>3_imm, and<mode>3_imm_dot, and<mode>3_imm_dot2,
|
||||
and<mode>3_imm_mask_dot, and<mode>3_imm_mask_dot2): Adjust condition.
|
||||
(*and<mode>3_imm_dot_shifted): New.
|
||||
(*and<mode>3_mask): Delete, rewrite as ...
|
||||
(and<mode>3_mask): ... New.
|
||||
(*and<mode>3_mask_dot, *and<mode>3_mask_dot): Rewrite.
|
||||
(andsi3_internal0_nomc): Delete.
|
||||
(*andsi3_internal6): Delete.
|
||||
(*and<mode>3_2insn): New.
|
||||
(insv, insvsi_internal, *insvsi_internal1, *insvsi_internal2,
|
||||
*insvsi_internal3, *insvsi_internal4, *insvsi_internal5,
|
||||
*insvsi_internal6, insvdi_internal, *insvdi_internal2,
|
||||
*insvdi_internal3): Delete.
|
||||
(*rotl<mode>3_mask, *rotl<mode>3_mask_dot, *rotl<mode>3_mask_dot2,
|
||||
*rotl<mode>3_insert, *rotl<mode>3_insert_2, *rotl<mode>3_insert_3,
|
||||
*rotl<mode>3_insert_4, two splitters for multi-precision shifts,
|
||||
*ior<mode>_mask): New.
|
||||
(extzv, extzvdi_internal, *extzvdi_internal1, *extzvdi_internal2,
|
||||
*rotlsi3_mask, *rotlsi3_mask_dot, *rotlsi3_mask_dot2,
|
||||
*ashlsi3_imm_mask, *ashlsi3_imm_mask_dot, *ashlsi3_imm_mask_dot2,
|
||||
*lshrsi3_imm_mask, *lshrsi3_imm_mask_dot, *lshrsi3_imm_mask_dot2):
|
||||
Delete.
|
||||
(ashr<mode>3): Delete expander.
|
||||
(*ashr<mode>3): Rename to ...
|
||||
(ashr<mode>3): ... This.
|
||||
(ashrdi3_no_power, *ashrdisi3_noppc64be): Delete.
|
||||
(*rotldi3_internal4, *rotldi3_internal5 and split,
|
||||
*rotldi3_internal6 and split, *ashldi3_internal4, ashldi3_internal5
|
||||
and split, *ashldi3_internal6 and split, *ashldi3_internal7,
|
||||
ashldi3_internal8 and split, *ashldi3_internal9 and split): Delete.
|
||||
(*anddi3_2rld, *anddi3_2rld_dot, *anddi3_2rld_dot2): Delete.
|
||||
(splitter for loading a mask): Adjust.
|
||||
* doc/md.texi (Machine Constraints): Remove q, S, T, t constraints.
|
||||
|
||||
2015-07-20 Marek Polacek <polacek@redhat.com>
|
||||
|
||||
* genemit.c (print_code, gen_exp, gen_insn, gen_expand, gen_split,
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
;; along with GCC; see the file COPYING3. If not see
|
||||
;; <http://www.gnu.org/licenses/>.
|
||||
|
||||
;; Available constraint letters: "e", "k", "q", "u", "A", "B", "C", "D"
|
||||
;; Available constraint letters: e k q t u A B C D S T
|
||||
|
||||
;; Register constraints
|
||||
|
||||
|
@ -230,29 +230,11 @@ usually better to use @samp{m} or @samp{es} in @code{asm} statements)"
|
|||
|
||||
;; General constraints
|
||||
|
||||
(define_constraint "S"
|
||||
"Constant that can be placed into a 64-bit mask operand"
|
||||
(and (match_test "TARGET_POWERPC64")
|
||||
(match_operand 0 "mask64_operand")))
|
||||
|
||||
(define_constraint "T"
|
||||
"Constant that can be placed into a 32-bit mask operand"
|
||||
(match_operand 0 "mask_operand"))
|
||||
|
||||
(define_constraint "U"
|
||||
"V.4 small data reference"
|
||||
(and (match_test "DEFAULT_ABI == ABI_V4")
|
||||
(match_test "small_data_operand (op, mode)")))
|
||||
|
||||
(define_constraint "t"
|
||||
"AND masks that can be performed by two rldic{l,r} insns
|
||||
(but excluding those that could match other constraints of anddi3)"
|
||||
(and (and (and (match_operand 0 "mask64_2_operand")
|
||||
(match_test "(fixed_regs[CR0_REGNO]
|
||||
|| !logical_operand (op, DImode))"))
|
||||
(not (match_operand 0 "mask_operand")))
|
||||
(not (match_operand 0 "mask64_operand"))))
|
||||
|
||||
(define_constraint "W"
|
||||
"vector constant that does not require memory"
|
||||
(match_operand 0 "easy_vector_constant"))
|
||||
|
|
|
@ -751,178 +751,14 @@
|
|||
(and (not (match_operand 0 "logical_operand"))
|
||||
(match_operand 0 "reg_or_logical_cint_operand"))))
|
||||
|
||||
;; Return 1 if op is a constant that can be encoded in a 32-bit mask,
|
||||
;; suitable for use with rlwinm (no more than two 1->0 or 0->1
|
||||
;; transitions). Reject all ones and all zeros, since these should have
|
||||
;; been optimized away and confuse the making of MB and ME.
|
||||
(define_predicate "mask_operand"
|
||||
(match_code "const_int")
|
||||
{
|
||||
unsigned HOST_WIDE_INT c, lsb;
|
||||
|
||||
c = INTVAL (op);
|
||||
|
||||
if (TARGET_POWERPC64)
|
||||
{
|
||||
/* Fail if the mask is not 32-bit. */
|
||||
if (mode == DImode && (c & ~(unsigned HOST_WIDE_INT) 0xffffffff) != 0)
|
||||
return 0;
|
||||
|
||||
/* Fail if the mask wraps around because the upper 32-bits of the
|
||||
mask will all be 1s, contrary to GCC's internal view. */
|
||||
if ((c & 0x80000001) == 0x80000001)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We don't change the number of transitions by inverting,
|
||||
so make sure we start with the LS bit zero. */
|
||||
if (c & 1)
|
||||
c = ~c;
|
||||
|
||||
/* Reject all zeros or all ones. */
|
||||
if (c == 0)
|
||||
return 0;
|
||||
|
||||
/* Find the first transition. */
|
||||
lsb = c & -c;
|
||||
|
||||
/* Invert to look for a second transition. */
|
||||
c = ~c;
|
||||
|
||||
/* Erase first transition. */
|
||||
c &= -lsb;
|
||||
|
||||
/* Find the second transition (if any). */
|
||||
lsb = c & -c;
|
||||
|
||||
/* Match if all the bits above are 1's (or c is zero). */
|
||||
return c == -lsb;
|
||||
})
|
||||
|
||||
;; Return 1 for the PowerPC64 rlwinm corner case.
|
||||
(define_predicate "mask_operand_wrap"
|
||||
(match_code "const_int")
|
||||
{
|
||||
unsigned HOST_WIDE_INT c, lsb;
|
||||
|
||||
c = INTVAL (op);
|
||||
|
||||
if ((c & 0x80000001) != 0x80000001)
|
||||
return 0;
|
||||
|
||||
c = ~c;
|
||||
if (c == 0)
|
||||
return 0;
|
||||
|
||||
lsb = c & -c;
|
||||
c = ~c;
|
||||
c &= -lsb;
|
||||
lsb = c & -c;
|
||||
return c == -lsb;
|
||||
})
|
||||
|
||||
;; Return 1 if the operand is a constant that is a PowerPC64 mask
|
||||
;; suitable for use with rldicl or rldicr (no more than one 1->0 or 0->1
|
||||
;; transition). Reject all zeros, since zero should have been
|
||||
;; optimized away and confuses the making of MB and ME.
|
||||
(define_predicate "mask64_operand"
|
||||
(match_code "const_int")
|
||||
{
|
||||
unsigned HOST_WIDE_INT c, lsb;
|
||||
|
||||
c = INTVAL (op);
|
||||
|
||||
/* Reject all zeros. */
|
||||
if (c == 0)
|
||||
return 0;
|
||||
|
||||
/* We don't change the number of transitions by inverting,
|
||||
so make sure we start with the LS bit zero. */
|
||||
if (c & 1)
|
||||
c = ~c;
|
||||
|
||||
/* Find the first transition. */
|
||||
lsb = c & -c;
|
||||
|
||||
/* Match if all the bits above are 1's (or c is zero). */
|
||||
return c == -lsb;
|
||||
})
|
||||
|
||||
;; Like mask64_operand, but allow up to three transitions. This
|
||||
;; predicate is used by insn patterns that generate two rldicl or
|
||||
;; rldicr machine insns.
|
||||
(define_predicate "mask64_2_operand"
|
||||
(match_code "const_int")
|
||||
{
|
||||
unsigned HOST_WIDE_INT c, lsb;
|
||||
|
||||
c = INTVAL (op);
|
||||
|
||||
/* Disallow all zeros. */
|
||||
if (c == 0)
|
||||
return 0;
|
||||
|
||||
/* We don't change the number of transitions by inverting,
|
||||
so make sure we start with the LS bit zero. */
|
||||
if (c & 1)
|
||||
c = ~c;
|
||||
|
||||
/* Find the first transition. */
|
||||
lsb = c & -c;
|
||||
|
||||
/* Invert to look for a second transition. */
|
||||
c = ~c;
|
||||
|
||||
/* Erase first transition. */
|
||||
c &= -lsb;
|
||||
|
||||
/* Find the second transition. */
|
||||
lsb = c & -c;
|
||||
|
||||
/* Invert to look for a third transition. */
|
||||
c = ~c;
|
||||
|
||||
/* Erase second transition. */
|
||||
c &= -lsb;
|
||||
|
||||
/* Find the third transition (if any). */
|
||||
lsb = c & -c;
|
||||
|
||||
/* Match if all the bits above are 1's (or c is zero). */
|
||||
return c == -lsb;
|
||||
})
|
||||
|
||||
;; Match a mask_operand or a mask64_operand.
|
||||
(define_predicate "any_mask_operand"
|
||||
(ior (match_operand 0 "mask_operand")
|
||||
(and (match_test "TARGET_POWERPC64 && mode == DImode")
|
||||
(match_operand 0 "mask64_operand"))))
|
||||
|
||||
;; Like and_operand, but also match constants that can be implemented
|
||||
;; with two rldicl or rldicr insns.
|
||||
(define_predicate "and64_2_operand"
|
||||
(ior (match_operand 0 "mask64_2_operand")
|
||||
(if_then_else (match_test "fixed_regs[CR0_REGNO]")
|
||||
(match_operand 0 "gpc_reg_operand")
|
||||
(match_operand 0 "logical_operand"))))
|
||||
|
||||
;; Return 1 if the operand is either a non-special register or a
|
||||
;; constant that can be used as the operand of a logical AND.
|
||||
(define_predicate "and_operand"
|
||||
(ior (match_operand 0 "mask_operand")
|
||||
(and (match_test "TARGET_POWERPC64 && mode == DImode")
|
||||
(match_operand 0 "mask64_operand"))
|
||||
(ior (match_test "rs6000_is_valid_and_mask (op, mode)")
|
||||
(if_then_else (match_test "fixed_regs[CR0_REGNO]")
|
||||
(match_operand 0 "gpc_reg_operand")
|
||||
(match_operand 0 "logical_operand"))))
|
||||
|
||||
;; Return 1 if the operand is a constant that can be used as the operand
|
||||
;; of a logical AND, implemented with two rld* insns, and it cannot be done
|
||||
;; using just one insn.
|
||||
(define_predicate "and_2rld_operand"
|
||||
(and (match_operand 0 "and64_2_operand")
|
||||
(not (match_operand 0 "and_operand"))))
|
||||
|
||||
;; Return 1 if the operand is either a logical operand or a short cint operand.
|
||||
(define_predicate "scc_eq_operand"
|
||||
(ior (match_operand 0 "logical_operand")
|
||||
|
@ -1128,6 +964,10 @@
|
|||
return nonimmediate_operand (op, mode);
|
||||
})
|
||||
|
||||
;; Return true if operand is an operator used in rotate-and-mask instructions.
|
||||
(define_predicate "rotate_mask_operator"
|
||||
(match_code "rotate,ashift,lshiftrt"))
|
||||
|
||||
;; Return true if operand is boolean operator.
|
||||
(define_predicate "boolean_operator"
|
||||
(match_code "and,ior,xor"))
|
||||
|
|
|
@ -66,15 +66,18 @@ extern void altivec_expand_stvex_be (rtx, rtx, machine_mode, unsigned);
|
|||
extern void rs6000_expand_extract_even (rtx, rtx, rtx);
|
||||
extern void rs6000_expand_interleave (rtx, rtx, rtx, bool);
|
||||
extern void rs6000_scale_v2df (rtx, rtx, int);
|
||||
extern void build_mask64_2_operands (rtx, rtx *);
|
||||
extern int expand_block_clear (rtx[]);
|
||||
extern int expand_block_move (rtx[]);
|
||||
extern const char * rs6000_output_load_multiple (rtx[]);
|
||||
extern int includes_lshift_p (rtx, rtx);
|
||||
extern int includes_rshift_p (rtx, rtx);
|
||||
extern int includes_rldic_lshift_p (rtx, rtx);
|
||||
extern int includes_rldicr_lshift_p (rtx, rtx);
|
||||
extern int insvdi_rshift_rlwimi_p (rtx, rtx, rtx);
|
||||
extern bool rs6000_is_valid_mask (rtx, int *, int *, machine_mode);
|
||||
extern bool rs6000_is_valid_and_mask (rtx, machine_mode);
|
||||
extern bool rs6000_is_valid_shift_mask (rtx, rtx, machine_mode);
|
||||
extern bool rs6000_is_valid_insert_mask (rtx, rtx, machine_mode);
|
||||
extern const char *rs6000_insn_for_and_mask (machine_mode, rtx *, bool);
|
||||
extern const char *rs6000_insn_for_shift_mask (machine_mode, rtx *, bool);
|
||||
extern const char *rs6000_insn_for_insert_mask (machine_mode, rtx *, bool);
|
||||
extern bool rs6000_is_valid_2insn_and (rtx, machine_mode);
|
||||
extern void rs6000_emit_2insn_and (machine_mode, rtx *, bool, bool);
|
||||
extern int registers_ok_for_quad_peep (rtx, rtx);
|
||||
extern int mems_ok_for_quad_peep (rtx, rtx);
|
||||
extern bool gpr_or_gpr_p (rtx, rtx);
|
||||
|
@ -102,8 +105,6 @@ extern void paired_expand_vector_move (rtx operands[]);
|
|||
|
||||
|
||||
extern int ccr_bit (rtx, int);
|
||||
extern int extract_MB (rtx);
|
||||
extern int extract_ME (rtx);
|
||||
extern void rs6000_output_function_entry (FILE *, const char *);
|
||||
extern void print_operand (FILE *, rtx, int);
|
||||
extern void print_operand_address (FILE *, rtx);
|
||||
|
|
|
@ -5270,7 +5270,7 @@ num_insns_constant (rtx op, machine_mode mode)
|
|||
{
|
||||
case CONST_INT:
|
||||
if ((INTVAL (op) >> 31) != 0 && (INTVAL (op) >> 31) != -1
|
||||
&& mask64_operand (op, mode))
|
||||
&& rs6000_is_valid_and_mask (op, mode))
|
||||
return 2;
|
||||
else
|
||||
return num_insns_constant_wide (INTVAL (op));
|
||||
|
@ -5318,7 +5318,7 @@ num_insns_constant (rtx op, machine_mode mode)
|
|||
|| (high == -1 && low < 0))
|
||||
return num_insns_constant_wide (low);
|
||||
|
||||
else if (mask64_operand (op, mode))
|
||||
else if (rs6000_is_valid_and_mask (op, mode))
|
||||
return 2;
|
||||
|
||||
else if (low == 0)
|
||||
|
@ -6033,69 +6033,6 @@ rs6000_expand_vector_extract (rtx target, rtx vec, int elt)
|
|||
emit_move_insn (target, adjust_address_nv (mem, inner_mode, 0));
|
||||
}
|
||||
|
||||
/* Generates shifts and masks for a pair of rldicl or rldicr insns to
|
||||
implement ANDing by the mask IN. */
|
||||
void
|
||||
build_mask64_2_operands (rtx in, rtx *out)
|
||||
{
|
||||
unsigned HOST_WIDE_INT c, lsb, m1, m2;
|
||||
int shift;
|
||||
|
||||
gcc_assert (GET_CODE (in) == CONST_INT);
|
||||
|
||||
c = INTVAL (in);
|
||||
if (c & 1)
|
||||
{
|
||||
/* Assume c initially something like 0x00fff000000fffff. The idea
|
||||
is to rotate the word so that the middle ^^^^^^ group of zeros
|
||||
is at the MS end and can be cleared with an rldicl mask. We then
|
||||
rotate back and clear off the MS ^^ group of zeros with a
|
||||
second rldicl. */
|
||||
c = ~c; /* c == 0xff000ffffff00000 */
|
||||
lsb = c & -c; /* lsb == 0x0000000000100000 */
|
||||
m1 = -lsb; /* m1 == 0xfffffffffff00000 */
|
||||
c = ~c; /* c == 0x00fff000000fffff */
|
||||
c &= -lsb; /* c == 0x00fff00000000000 */
|
||||
lsb = c & -c; /* lsb == 0x0000100000000000 */
|
||||
c = ~c; /* c == 0xff000fffffffffff */
|
||||
c &= -lsb; /* c == 0xff00000000000000 */
|
||||
shift = 0;
|
||||
while ((lsb >>= 1) != 0)
|
||||
shift++; /* shift == 44 on exit from loop */
|
||||
m1 <<= 64 - shift; /* m1 == 0xffffff0000000000 */
|
||||
m1 = ~m1; /* m1 == 0x000000ffffffffff */
|
||||
m2 = ~c; /* m2 == 0x00ffffffffffffff */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Assume c initially something like 0xff000f0000000000. The idea
|
||||
is to rotate the word so that the ^^^ middle group of zeros
|
||||
is at the LS end and can be cleared with an rldicr mask. We then
|
||||
rotate back and clear off the LS group of ^^^^^^^^^^ zeros with
|
||||
a second rldicr. */
|
||||
lsb = c & -c; /* lsb == 0x0000010000000000 */
|
||||
m2 = -lsb; /* m2 == 0xffffff0000000000 */
|
||||
c = ~c; /* c == 0x00fff0ffffffffff */
|
||||
c &= -lsb; /* c == 0x00fff00000000000 */
|
||||
lsb = c & -c; /* lsb == 0x0000100000000000 */
|
||||
c = ~c; /* c == 0xff000fffffffffff */
|
||||
c &= -lsb; /* c == 0xff00000000000000 */
|
||||
shift = 0;
|
||||
while ((lsb >>= 1) != 0)
|
||||
shift++; /* shift == 44 on exit from loop */
|
||||
m1 = ~c; /* m1 == 0x00ffffffffffffff */
|
||||
m1 >>= shift; /* m1 == 0x0000000000000fff */
|
||||
m1 = ~m1; /* m1 == 0xfffffffffffff000 */
|
||||
}
|
||||
|
||||
/* Note that when we only have two 0->1 and 1->0 transitions, one of the
|
||||
masks will be all 1's. We are guaranteed more than one transition. */
|
||||
out[0] = GEN_INT (64 - shift);
|
||||
out[1] = GEN_INT (m1);
|
||||
out[2] = GEN_INT (shift);
|
||||
out[3] = GEN_INT (m2);
|
||||
}
|
||||
|
||||
/* Return TRUE if OP is an invalid SUBREG operation on the e500. */
|
||||
|
||||
bool
|
||||
|
@ -16423,121 +16360,495 @@ validate_condition_mode (enum rtx_code code, machine_mode mode)
|
|||
}
|
||||
|
||||
|
||||
/* Return 1 if ANDOP is a mask that has no bits on that are not in the
|
||||
mask required to convert the result of a rotate insn into a shift
|
||||
left insn of SHIFTOP bits. Both are known to be SImode CONST_INT. */
|
||||
/* Return whether MASK (a CONST_INT) is a valid mask for any rlwinm,
|
||||
rldicl, rldicr, or rldic instruction in mode MODE. If so, if E is
|
||||
not zero, store there the bit offset (counted from the right) where
|
||||
the single stretch of 1 bits begins; and similarly for B, the bit
|
||||
offset where it ends. */
|
||||
|
||||
int
|
||||
includes_lshift_p (rtx shiftop, rtx andop)
|
||||
bool
|
||||
rs6000_is_valid_mask (rtx mask, int *b, int *e, machine_mode mode)
|
||||
{
|
||||
unsigned HOST_WIDE_INT shift_mask = ~(unsigned HOST_WIDE_INT) 0;
|
||||
unsigned HOST_WIDE_INT val = INTVAL (mask);
|
||||
unsigned HOST_WIDE_INT bit;
|
||||
int nb, ne;
|
||||
int n = GET_MODE_PRECISION (mode);
|
||||
|
||||
shift_mask <<= INTVAL (shiftop);
|
||||
if (mode != DImode && mode != SImode)
|
||||
return false;
|
||||
|
||||
return (INTVAL (andop) & 0xffffffff & ~shift_mask) == 0;
|
||||
if (INTVAL (mask) >= 0)
|
||||
{
|
||||
bit = val & -val;
|
||||
ne = exact_log2 (bit);
|
||||
nb = exact_log2 (val + bit);
|
||||
}
|
||||
|
||||
/* Similar, but for right shift. */
|
||||
|
||||
int
|
||||
includes_rshift_p (rtx shiftop, rtx andop)
|
||||
else if (val + 1 == 0)
|
||||
{
|
||||
unsigned HOST_WIDE_INT shift_mask = ~(unsigned HOST_WIDE_INT) 0;
|
||||
|
||||
shift_mask >>= INTVAL (shiftop);
|
||||
|
||||
return (INTVAL (andop) & 0xffffffff & ~shift_mask) == 0;
|
||||
nb = n;
|
||||
ne = 0;
|
||||
}
|
||||
|
||||
/* Return 1 if ANDOP is a mask suitable for use with an rldic insn
|
||||
to perform a left shift. It must have exactly SHIFTOP least
|
||||
significant 0's, then one or more 1's, then zero or more 0's. */
|
||||
|
||||
int
|
||||
includes_rldic_lshift_p (rtx shiftop, rtx andop)
|
||||
else if (val & 1)
|
||||
{
|
||||
if (GET_CODE (andop) == CONST_INT)
|
||||
{
|
||||
unsigned HOST_WIDE_INT c, lsb, shift_mask;
|
||||
|
||||
c = INTVAL (andop);
|
||||
if (c == 0 || c == HOST_WIDE_INT_M1U)
|
||||
return 0;
|
||||
|
||||
shift_mask = HOST_WIDE_INT_M1U;
|
||||
shift_mask <<= INTVAL (shiftop);
|
||||
|
||||
/* Find the least significant one bit. */
|
||||
lsb = c & -c;
|
||||
|
||||
/* It must coincide with the LSB of the shift mask. */
|
||||
if (-lsb != shift_mask)
|
||||
return 0;
|
||||
|
||||
/* Invert to look for the next transition (if any). */
|
||||
c = ~c;
|
||||
|
||||
/* Remove the low group of ones (originally low group of zeros). */
|
||||
c &= -lsb;
|
||||
|
||||
/* Again find the lsb, and check we have all 1's above. */
|
||||
lsb = c & -c;
|
||||
return c == -lsb;
|
||||
val = ~val;
|
||||
bit = val & -val;
|
||||
nb = exact_log2 (bit);
|
||||
ne = exact_log2 (val + bit);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
{
|
||||
bit = val & -val;
|
||||
ne = exact_log2 (bit);
|
||||
if (val + bit == 0)
|
||||
nb = n;
|
||||
else
|
||||
nb = 0;
|
||||
}
|
||||
|
||||
/* Return 1 if ANDOP is a mask suitable for use with an rldicr insn
|
||||
to perform a left shift. It must have SHIFTOP or more least
|
||||
significant 0's, with the remainder of the word 1's. */
|
||||
nb--;
|
||||
|
||||
int
|
||||
includes_rldicr_lshift_p (rtx shiftop, rtx andop)
|
||||
if (nb < 0 || ne < 0 || nb >= n || ne >= n)
|
||||
return false;
|
||||
|
||||
if (b)
|
||||
*b = nb;
|
||||
if (e)
|
||||
*e = ne;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Return whether MASK (a CONST_INT) is a valid mask for any rlwinm, rldicl,
|
||||
or rldicr instruction, to implement an AND with it in mode MODE. */
|
||||
|
||||
bool
|
||||
rs6000_is_valid_and_mask (rtx mask, machine_mode mode)
|
||||
{
|
||||
if (GET_CODE (andop) == CONST_INT)
|
||||
int nb, ne;
|
||||
|
||||
if (!rs6000_is_valid_mask (mask, &nb, &ne, mode))
|
||||
return false;
|
||||
|
||||
/* For DImode, we need a rldicl, rldicr, or a rlwinm with mask that
|
||||
does not wrap. */
|
||||
if (mode == DImode)
|
||||
return (ne == 0 || nb == 63 || (nb < 32 && ne <= nb));
|
||||
|
||||
/* For SImode, rlwinm can do everything. */
|
||||
if (mode == SImode)
|
||||
return (nb < 32 && ne < 32);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Return the instruction template for an AND with mask in mode MODE, with
|
||||
operands OPERANDS. If DOT is true, make it a record-form instruction. */
|
||||
|
||||
const char *
|
||||
rs6000_insn_for_and_mask (machine_mode mode, rtx *operands, bool dot)
|
||||
{
|
||||
unsigned HOST_WIDE_INT c, lsb, shift_mask;
|
||||
int nb, ne;
|
||||
|
||||
shift_mask = HOST_WIDE_INT_M1U;
|
||||
shift_mask <<= INTVAL (shiftop);
|
||||
c = INTVAL (andop);
|
||||
if (!rs6000_is_valid_mask (operands[2], &nb, &ne, mode))
|
||||
gcc_unreachable ();
|
||||
|
||||
/* Find the least significant one bit. */
|
||||
lsb = c & -c;
|
||||
if (mode == DImode && ne == 0)
|
||||
{
|
||||
operands[3] = GEN_INT (63 - nb);
|
||||
if (dot)
|
||||
return "rldicl. %0,%1,0,%3";
|
||||
return "rldicl %0,%1,0,%3";
|
||||
}
|
||||
|
||||
/* It must be covered by the shift mask.
|
||||
This test also rejects c == 0. */
|
||||
if ((lsb & shift_mask) == 0)
|
||||
return 0;
|
||||
if (mode == DImode && nb == 63)
|
||||
{
|
||||
operands[3] = GEN_INT (63 - ne);
|
||||
if (dot)
|
||||
return "rldicr. %0,%1,0,%3";
|
||||
return "rldicr %0,%1,0,%3";
|
||||
}
|
||||
|
||||
/* Check we have all 1's above the transition, and reject all 1's. */
|
||||
return c == -lsb && lsb != 1;
|
||||
if (nb < 32 && ne < 32)
|
||||
{
|
||||
operands[3] = GEN_INT (31 - nb);
|
||||
operands[4] = GEN_INT (31 - ne);
|
||||
if (dot)
|
||||
return "rlwinm. %0,%1,0,%3,%4";
|
||||
return "rlwinm %0,%1,0,%3,%4";
|
||||
}
|
||||
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
/* Return whether MASK (a CONST_INT) is a valid mask for any rlw[i]nm,
|
||||
rld[i]cl, rld[i]cr, or rld[i]c instruction, to implement an AND with
|
||||
shift SHIFT (a ROTATE, ASHIFT, or LSHIFTRT) in mode MODE. */
|
||||
|
||||
bool
|
||||
rs6000_is_valid_shift_mask (rtx mask, rtx shift, machine_mode mode)
|
||||
{
|
||||
int nb, ne;
|
||||
|
||||
if (!rs6000_is_valid_mask (mask, &nb, &ne, mode))
|
||||
return false;
|
||||
|
||||
int n = GET_MODE_PRECISION (mode);
|
||||
int sh = -1;
|
||||
|
||||
if (CONST_INT_P (XEXP (shift, 1)))
|
||||
{
|
||||
sh = INTVAL (XEXP (shift, 1));
|
||||
if (sh < 0 || sh >= n)
|
||||
return false;
|
||||
}
|
||||
|
||||
rtx_code code = GET_CODE (shift);
|
||||
|
||||
/* Convert any shift by 0 to a rotate, to simplify below code. */
|
||||
if (sh == 0)
|
||||
code = ROTATE;
|
||||
|
||||
/* Convert rotate to simple shift if we can, to make analysis simpler. */
|
||||
if (code == ROTATE && sh >= 0 && nb >= ne && ne >= sh)
|
||||
code = ASHIFT;
|
||||
if (code == ROTATE && sh >= 0 && nb >= ne && nb < sh)
|
||||
{
|
||||
code = LSHIFTRT;
|
||||
sh = n - sh;
|
||||
}
|
||||
|
||||
/* DImode rotates need rld*. */
|
||||
if (mode == DImode && code == ROTATE)
|
||||
return (nb == 63 || ne == 0 || ne == sh);
|
||||
|
||||
/* SImode rotates need rlw*. */
|
||||
if (mode == SImode && code == ROTATE)
|
||||
return (nb < 32 && ne < 32 && sh < 32);
|
||||
|
||||
/* Wrap-around masks are only okay for rotates. */
|
||||
if (ne > nb)
|
||||
return false;
|
||||
|
||||
/* Variable shifts are only okay for rotates. */
|
||||
if (sh < 0)
|
||||
return false;
|
||||
|
||||
/* Don't allow ASHIFT if the mask is wrong for that. */
|
||||
if (code == ASHIFT && ne < sh)
|
||||
return false;
|
||||
|
||||
/* If we can do it with an rlw*, we can do it. Don't allow LSHIFTRT
|
||||
if the mask is wrong for that. */
|
||||
if (nb < 32 && ne < 32 && sh < 32
|
||||
&& !(code == LSHIFTRT && nb >= 32 - sh))
|
||||
return true;
|
||||
|
||||
/* If we can do it with an rld*, we can do it. Don't allow LSHIFTRT
|
||||
if the mask is wrong for that. */
|
||||
if (code == LSHIFTRT)
|
||||
sh = 64 - sh;
|
||||
if (nb == 63 || ne == 0 || ne == sh)
|
||||
return !(code == LSHIFTRT && nb >= sh);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Return the instruction template for a shift with mask in mode MODE, with
|
||||
operands OPERANDS. If DOT is true, make it a record-form instruction. */
|
||||
|
||||
const char *
|
||||
rs6000_insn_for_shift_mask (machine_mode mode, rtx *operands, bool dot)
|
||||
{
|
||||
int nb, ne;
|
||||
|
||||
if (!rs6000_is_valid_mask (operands[3], &nb, &ne, mode))
|
||||
gcc_unreachable ();
|
||||
|
||||
if (mode == DImode && ne == 0)
|
||||
{
|
||||
if (GET_CODE (operands[4]) == LSHIFTRT && INTVAL (operands[2]))
|
||||
operands[2] = GEN_INT (64 - INTVAL (operands[2]));
|
||||
operands[3] = GEN_INT (63 - nb);
|
||||
if (dot)
|
||||
return "rld%I2cl. %0,%1,%2,%3";
|
||||
return "rld%I2cl %0,%1,%2,%3";
|
||||
}
|
||||
|
||||
if (mode == DImode && nb == 63)
|
||||
{
|
||||
operands[3] = GEN_INT (63 - ne);
|
||||
if (dot)
|
||||
return "rld%I2cr. %0,%1,%2,%3";
|
||||
return "rld%I2cr %0,%1,%2,%3";
|
||||
}
|
||||
|
||||
if (mode == DImode
|
||||
&& GET_CODE (operands[4]) != LSHIFTRT
|
||||
&& CONST_INT_P (operands[2])
|
||||
&& ne == INTVAL (operands[2]))
|
||||
{
|
||||
operands[3] = GEN_INT (63 - nb);
|
||||
if (dot)
|
||||
return "rld%I2c. %0,%1,%2,%3";
|
||||
return "rld%I2c %0,%1,%2,%3";
|
||||
}
|
||||
|
||||
if (nb < 32 && ne < 32)
|
||||
{
|
||||
if (GET_CODE (operands[4]) == LSHIFTRT && INTVAL (operands[2]))
|
||||
operands[2] = GEN_INT (32 - INTVAL (operands[2]));
|
||||
operands[3] = GEN_INT (31 - nb);
|
||||
operands[4] = GEN_INT (31 - ne);
|
||||
if (dot)
|
||||
return "rlw%I2nm. %0,%1,%2,%3,%4";
|
||||
return "rlw%I2nm %0,%1,%2,%3,%4";
|
||||
}
|
||||
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
/* Return whether MASK (a CONST_INT) is a valid mask for any rlwimi or
|
||||
rldimi instruction, to implement an insert with shift SHIFT (a ROTATE,
|
||||
ASHIFT, or LSHIFTRT) in mode MODE. */
|
||||
|
||||
bool
|
||||
rs6000_is_valid_insert_mask (rtx mask, rtx shift, machine_mode mode)
|
||||
{
|
||||
int nb, ne;
|
||||
|
||||
if (!rs6000_is_valid_mask (mask, &nb, &ne, mode))
|
||||
return false;
|
||||
|
||||
int n = GET_MODE_PRECISION (mode);
|
||||
|
||||
int sh = INTVAL (XEXP (shift, 1));
|
||||
if (sh < 0 || sh >= n)
|
||||
return false;
|
||||
|
||||
rtx_code code = GET_CODE (shift);
|
||||
|
||||
/* Convert any shift by 0 to a rotate, to simplify below code. */
|
||||
if (sh == 0)
|
||||
code = ROTATE;
|
||||
|
||||
/* Convert rotate to simple shift if we can, to make analysis simpler. */
|
||||
if (code == ROTATE && sh >= 0 && nb >= ne && ne >= sh)
|
||||
code = ASHIFT;
|
||||
if (code == ROTATE && sh >= 0 && nb >= ne && nb < sh)
|
||||
{
|
||||
code = LSHIFTRT;
|
||||
sh = n - sh;
|
||||
}
|
||||
|
||||
/* DImode rotates need rldimi. */
|
||||
if (mode == DImode && code == ROTATE)
|
||||
return (ne == sh);
|
||||
|
||||
/* SImode rotates need rlwimi. */
|
||||
if (mode == SImode && code == ROTATE)
|
||||
return (nb < 32 && ne < 32 && sh < 32);
|
||||
|
||||
/* Wrap-around masks are only okay for rotates. */
|
||||
if (ne > nb)
|
||||
return false;
|
||||
|
||||
/* Don't allow ASHIFT if the mask is wrong for that. */
|
||||
if (code == ASHIFT && ne < sh)
|
||||
return false;
|
||||
|
||||
/* If we can do it with an rlwimi, we can do it. Don't allow LSHIFTRT
|
||||
if the mask is wrong for that. */
|
||||
if (nb < 32 && ne < 32 && sh < 32
|
||||
&& !(code == LSHIFTRT && nb >= 32 - sh))
|
||||
return true;
|
||||
|
||||
/* If we can do it with an rldimi, we can do it. Don't allow LSHIFTRT
|
||||
if the mask is wrong for that. */
|
||||
if (code == LSHIFTRT)
|
||||
sh = 64 - sh;
|
||||
if (ne == sh)
|
||||
return !(code == LSHIFTRT && nb >= sh);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Return the instruction template for an insert with mask in mode MODE, with
|
||||
operands OPERANDS. If DOT is true, make it a record-form instruction. */
|
||||
|
||||
const char *
|
||||
rs6000_insn_for_insert_mask (machine_mode mode, rtx *operands, bool dot)
|
||||
{
|
||||
int nb, ne;
|
||||
|
||||
if (!rs6000_is_valid_mask (operands[3], &nb, &ne, mode))
|
||||
gcc_unreachable ();
|
||||
|
||||
/* Prefer rldimi because rlwimi is cracked. */
|
||||
if (TARGET_POWERPC64
|
||||
&& (!dot || mode == DImode)
|
||||
&& GET_CODE (operands[4]) != LSHIFTRT
|
||||
&& ne == INTVAL (operands[2]))
|
||||
{
|
||||
operands[3] = GEN_INT (63 - nb);
|
||||
if (dot)
|
||||
return "rldimi. %0,%1,%2,%3";
|
||||
return "rldimi %0,%1,%2,%3";
|
||||
}
|
||||
|
||||
if (nb < 32 && ne < 32)
|
||||
{
|
||||
if (GET_CODE (operands[4]) == LSHIFTRT && INTVAL (operands[2]))
|
||||
operands[2] = GEN_INT (32 - INTVAL (operands[2]));
|
||||
operands[3] = GEN_INT (31 - nb);
|
||||
operands[4] = GEN_INT (31 - ne);
|
||||
if (dot)
|
||||
return "rlwimi. %0,%1,%2,%3,%4";
|
||||
return "rlwimi %0,%1,%2,%3,%4";
|
||||
}
|
||||
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
/* Return whether an AND with C (a CONST_INT) in mode MODE can be done
|
||||
using two machine instructions. */
|
||||
|
||||
bool
|
||||
rs6000_is_valid_2insn_and (rtx c, machine_mode mode)
|
||||
{
|
||||
/* There are two kinds of AND we can handle with two insns:
|
||||
1) those we can do with two rl* insn;
|
||||
2) ori[s];xori[s].
|
||||
|
||||
We do not handle that last case yet. */
|
||||
|
||||
/* If there is just one stretch of ones, we can do it. */
|
||||
if (rs6000_is_valid_mask (c, NULL, NULL, mode))
|
||||
return true;
|
||||
|
||||
/* Otherwise, fill in the lowest "hole"; if we can do the result with
|
||||
one insn, we can do the whole thing with two. */
|
||||
unsigned HOST_WIDE_INT val = INTVAL (c);
|
||||
unsigned HOST_WIDE_INT bit1 = val & -val;
|
||||
unsigned HOST_WIDE_INT bit2 = (val + bit1) & ~val;
|
||||
unsigned HOST_WIDE_INT val1 = (val + bit1) & val;
|
||||
unsigned HOST_WIDE_INT bit3 = val1 & -val1;
|
||||
return rs6000_is_valid_and_mask (GEN_INT (val + bit3 - bit2), mode);
|
||||
}
|
||||
|
||||
/* Emit the two insns to do an AND in mode MODE, with operands OPERANDS.
|
||||
If EXPAND is true, split rotate-and-mask instructions we generate to
|
||||
their constituent parts as well (this is used during expand); if DOT
|
||||
is true, make the last insn a record-form instruction. */
|
||||
|
||||
void
|
||||
rs6000_emit_2insn_and (machine_mode mode, rtx *operands, bool expand, bool dot)
|
||||
{
|
||||
gcc_assert (!(expand && dot));
|
||||
|
||||
/* We do not actually handle record form yet. */
|
||||
if (dot)
|
||||
gcc_unreachable ();
|
||||
|
||||
unsigned HOST_WIDE_INT val = INTVAL (operands[2]);
|
||||
|
||||
/* If it is one stretch of ones, it is DImode; shift left, mask, then
|
||||
shift right. This generates better code than doing the masks without
|
||||
shifts, or shifting first right and then left. */
|
||||
int nb, ne;
|
||||
if (rs6000_is_valid_mask (operands[2], &nb, &ne, mode) && nb >= ne)
|
||||
{
|
||||
gcc_assert (mode == DImode);
|
||||
|
||||
int shift = 63 - nb;
|
||||
if (expand)
|
||||
{
|
||||
rtx tmp1 = gen_reg_rtx (DImode);
|
||||
rtx tmp2 = gen_reg_rtx (DImode);
|
||||
emit_insn (gen_ashldi3 (tmp1, operands[1], GEN_INT (shift)));
|
||||
emit_insn (gen_anddi3 (tmp2, tmp1, GEN_INT (val << shift)));
|
||||
emit_insn (gen_lshrdi3 (operands[0], tmp2, GEN_INT (shift)));
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return 1 if operands will generate a valid arguments to rlwimi
|
||||
instruction for insert with right shift in 64-bit mode. The mask may
|
||||
not start on the first bit or stop on the last bit because wrap-around
|
||||
effects of instruction do not correspond to semantics of RTL insn. */
|
||||
|
||||
int
|
||||
insvdi_rshift_rlwimi_p (rtx sizeop, rtx startop, rtx shiftop)
|
||||
{
|
||||
if (INTVAL (startop) > 32
|
||||
&& INTVAL (startop) < 64
|
||||
&& INTVAL (sizeop) > 1
|
||||
&& INTVAL (sizeop) + INTVAL (startop) < 64
|
||||
&& INTVAL (shiftop) > 0
|
||||
&& INTVAL (sizeop) + INTVAL (shiftop) < 32
|
||||
&& (64 - (INTVAL (shiftop) & 63)) >= INTVAL (sizeop))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
rtx tmp = gen_rtx_ASHIFT (mode, operands[1], GEN_INT (shift));
|
||||
tmp = gen_rtx_AND (mode, tmp, GEN_INT (val << shift));
|
||||
emit_move_insn (operands[0], tmp);
|
||||
emit_insn (gen_lshrdi3 (operands[0], operands[0], GEN_INT (shift)));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Otherwise, make a mask2 that cuts out the lowest "hole", and a mask1
|
||||
that does the rest. */
|
||||
unsigned HOST_WIDE_INT bit1 = val & -val;
|
||||
unsigned HOST_WIDE_INT bit2 = (val + bit1) & ~val;
|
||||
unsigned HOST_WIDE_INT val1 = (val + bit1) & val;
|
||||
unsigned HOST_WIDE_INT bit3 = val1 & -val1;
|
||||
|
||||
unsigned HOST_WIDE_INT mask1 = -bit3 + bit2 - 1;
|
||||
unsigned HOST_WIDE_INT mask2 = val + bit3 - bit2;
|
||||
|
||||
gcc_assert (rs6000_is_valid_and_mask (GEN_INT (mask2), mode));
|
||||
|
||||
/* Two "no-rotate"-and-mask instructions, for SImode. */
|
||||
if (rs6000_is_valid_and_mask (GEN_INT (mask1), mode))
|
||||
{
|
||||
gcc_assert (mode == SImode);
|
||||
|
||||
rtx reg = expand ? gen_reg_rtx (mode) : operands[0];
|
||||
rtx tmp = gen_rtx_AND (mode, operands[1], GEN_INT (mask1));
|
||||
emit_move_insn (reg, tmp);
|
||||
tmp = gen_rtx_AND (mode, reg, GEN_INT (mask2));
|
||||
emit_move_insn (operands[0], tmp);
|
||||
return;
|
||||
}
|
||||
|
||||
gcc_assert (mode == DImode);
|
||||
|
||||
/* Two "no-rotate"-and-mask instructions, for DImode: both are rlwinm
|
||||
insns; we have to do the first in SImode, because it wraps. */
|
||||
if (mask2 <= 0xffffffff
|
||||
&& rs6000_is_valid_and_mask (GEN_INT (mask1), SImode))
|
||||
{
|
||||
rtx reg = expand ? gen_reg_rtx (mode) : operands[0];
|
||||
rtx tmp = gen_rtx_AND (SImode, gen_lowpart (SImode, operands[1]),
|
||||
GEN_INT (mask1));
|
||||
rtx reg_low = gen_lowpart (SImode, reg);
|
||||
emit_move_insn (reg_low, tmp);
|
||||
tmp = gen_rtx_AND (mode, reg, GEN_INT (mask2));
|
||||
emit_move_insn (operands[0], tmp);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Two rld* insns: rotate, clear the hole in the middle (which now is
|
||||
at the top end), rotate back and clear the other hole. */
|
||||
int right = exact_log2 (bit3);
|
||||
int left = 64 - right;
|
||||
|
||||
/* Rotate the mask too. */
|
||||
mask1 = (mask1 >> right) | ((bit2 - 1) << left);
|
||||
|
||||
if (expand)
|
||||
{
|
||||
rtx tmp1 = gen_reg_rtx (DImode);
|
||||
rtx tmp2 = gen_reg_rtx (DImode);
|
||||
rtx tmp3 = gen_reg_rtx (DImode);
|
||||
emit_insn (gen_rotldi3 (tmp1, operands[1], GEN_INT (left)));
|
||||
emit_insn (gen_anddi3 (tmp2, tmp1, GEN_INT (mask1)));
|
||||
emit_insn (gen_rotldi3 (tmp3, tmp2, GEN_INT (right)));
|
||||
emit_insn (gen_anddi3 (operands[0], tmp3, GEN_INT (mask2)));
|
||||
}
|
||||
else
|
||||
{
|
||||
rtx tmp = gen_rtx_ROTATE (mode, operands[1], GEN_INT (left));
|
||||
tmp = gen_rtx_AND (mode, tmp, GEN_INT (mask1));
|
||||
emit_move_insn (operands[0], tmp);
|
||||
tmp = gen_rtx_ROTATE (mode, operands[0], GEN_INT (right));
|
||||
tmp = gen_rtx_AND (mode, tmp, GEN_INT (mask2));
|
||||
emit_move_insn (operands[0], tmp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return 1 if REGNO (reg1) == REGNO (reg2) - 1 making them candidates
|
||||
for lfq and stfq insns iff the registers are hard registers. */
|
||||
|
||||
|
@ -18422,71 +18733,6 @@ rs6000_init_machine_status (void)
|
|||
|
||||
#define INT_P(X) (GET_CODE (X) == CONST_INT && GET_MODE (X) == VOIDmode)
|
||||
|
||||
int
|
||||
extract_MB (rtx op)
|
||||
{
|
||||
int i;
|
||||
unsigned long val = INTVAL (op);
|
||||
|
||||
/* If the high bit is zero, the value is the first 1 bit we find
|
||||
from the left. */
|
||||
if ((val & 0x80000000) == 0)
|
||||
{
|
||||
gcc_assert (val & 0xffffffff);
|
||||
|
||||
i = 1;
|
||||
while (((val <<= 1) & 0x80000000) == 0)
|
||||
++i;
|
||||
return i;
|
||||
}
|
||||
|
||||
/* If the high bit is set and the low bit is not, or the mask is all
|
||||
1's, the value is zero. */
|
||||
if ((val & 1) == 0 || (val & 0xffffffff) == 0xffffffff)
|
||||
return 0;
|
||||
|
||||
/* Otherwise we have a wrap-around mask. Look for the first 0 bit
|
||||
from the right. */
|
||||
i = 31;
|
||||
while (((val >>= 1) & 1) != 0)
|
||||
--i;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
int
|
||||
extract_ME (rtx op)
|
||||
{
|
||||
int i;
|
||||
unsigned long val = INTVAL (op);
|
||||
|
||||
/* If the low bit is zero, the value is the first 1 bit we find from
|
||||
the right. */
|
||||
if ((val & 1) == 0)
|
||||
{
|
||||
gcc_assert (val & 0xffffffff);
|
||||
|
||||
i = 30;
|
||||
while (((val >>= 1) & 1) == 0)
|
||||
--i;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/* If the low bit is set and the high bit is not, or the mask is all
|
||||
1's, the value is 31. */
|
||||
if ((val & 0x80000000) == 0 || (val & 0xffffffff) == 0xffffffff)
|
||||
return 31;
|
||||
|
||||
/* Otherwise we have a wrap-around mask. Look for the first 0 bit
|
||||
from the left. */
|
||||
i = 0;
|
||||
while (((val <<= 1) & 0x80000000) != 0)
|
||||
++i;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Write out a function code label. */
|
||||
|
||||
void
|
||||
|
@ -18536,21 +18782,6 @@ print_operand (FILE *file, rtx x, int code)
|
|||
{
|
||||
/* %a is output_address. */
|
||||
|
||||
case 'b':
|
||||
/* If constant, low-order 16 bits of constant, unsigned.
|
||||
Otherwise, write normally. */
|
||||
if (INT_P (x))
|
||||
fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) & 0xffff);
|
||||
else
|
||||
print_operand (file, x, 0);
|
||||
return;
|
||||
|
||||
case 'B':
|
||||
/* If the low-order bit is zero, write 'r'; otherwise, write 'l'
|
||||
for 64-bit mask direction. */
|
||||
putc (((INTVAL (x) & 1) == 0 ? 'r' : 'l'), file);
|
||||
return;
|
||||
|
||||
/* %c is output_addr_const if a CONSTANT_ADDRESS_P, otherwise
|
||||
output_operand. */
|
||||
|
||||
|
@ -18713,24 +18944,6 @@ print_operand (FILE *file, rtx x, int code)
|
|||
}
|
||||
return;
|
||||
|
||||
case 'm':
|
||||
/* MB value for a mask operand. */
|
||||
if (! mask_operand (x, SImode))
|
||||
output_operand_lossage ("invalid %%m value");
|
||||
|
||||
fprintf (file, "%d", extract_MB (x));
|
||||
return;
|
||||
|
||||
case 'M':
|
||||
/* ME value for a mask operand. */
|
||||
if (! mask_operand (x, SImode))
|
||||
output_operand_lossage ("invalid %%M value");
|
||||
|
||||
fprintf (file, "%d", extract_ME (x));
|
||||
return;
|
||||
|
||||
/* %n outputs the negative of its operand. */
|
||||
|
||||
case 'N':
|
||||
/* Write the number of elements in the vector times 4. */
|
||||
if (GET_CODE (x) != PARALLEL)
|
||||
|
@ -18819,44 +19032,6 @@ print_operand (FILE *file, rtx x, int code)
|
|||
fprintf (file, "%d", 128 >> (REGNO (x) - CR0_REGNO));
|
||||
return;
|
||||
|
||||
case 's':
|
||||
/* Low 5 bits of 32 - value */
|
||||
if (! INT_P (x))
|
||||
output_operand_lossage ("invalid %%s value");
|
||||
else
|
||||
fprintf (file, HOST_WIDE_INT_PRINT_DEC, (32 - INTVAL (x)) & 31);
|
||||
return;
|
||||
|
||||
case 'S':
|
||||
/* PowerPC64 mask position. All 0's is excluded.
|
||||
CONST_INT 32-bit mask is considered sign-extended so any
|
||||
transition must occur within the CONST_INT, not on the boundary. */
|
||||
if (! mask64_operand (x, DImode))
|
||||
output_operand_lossage ("invalid %%S value");
|
||||
|
||||
uval = INTVAL (x);
|
||||
|
||||
if (uval & 1) /* Clear Left */
|
||||
{
|
||||
#if HOST_BITS_PER_WIDE_INT > 64
|
||||
uval &= ((unsigned HOST_WIDE_INT) 1 << 64) - 1;
|
||||
#endif
|
||||
i = 64;
|
||||
}
|
||||
else /* Clear Right */
|
||||
{
|
||||
uval = ~uval;
|
||||
#if HOST_BITS_PER_WIDE_INT > 64
|
||||
uval &= ((unsigned HOST_WIDE_INT) 1 << 64) - 1;
|
||||
#endif
|
||||
i = 63;
|
||||
}
|
||||
while (uval != 0)
|
||||
--i, uval >>= 1;
|
||||
gcc_assert (i >= 0);
|
||||
fprintf (file, "%d", i);
|
||||
return;
|
||||
|
||||
case 't':
|
||||
/* Like 'J' but get to the OVERFLOW/UNORDERED bit. */
|
||||
gcc_assert (REG_P (x) && GET_MODE (x) == CCmode);
|
||||
|
@ -18962,13 +19137,6 @@ print_operand (FILE *file, rtx x, int code)
|
|||
print_operand (file, x, 0);
|
||||
return;
|
||||
|
||||
case 'W':
|
||||
/* MB value for a PowerPC64 rldic operand. */
|
||||
i = clz_hwi (INTVAL (x));
|
||||
|
||||
fprintf (file, "%d", i);
|
||||
return;
|
||||
|
||||
case 'x':
|
||||
/* X is a FPR or Altivec register used in a VSX context. */
|
||||
if (GET_CODE (x) != REG || !VSX_REGNO_P (REGNO (x)))
|
||||
|
@ -30671,10 +30839,7 @@ rs6000_rtx_costs (rtx x, machine_mode mode, int outer_code,
|
|||
&& (satisfies_constraint_K (x)
|
||||
|| (mode == SImode
|
||||
? satisfies_constraint_L (x)
|
||||
: satisfies_constraint_J (x))
|
||||
|| mask_operand (x, mode)
|
||||
|| (mode == DImode
|
||||
&& mask64_operand (x, DImode))))
|
||||
: satisfies_constraint_J (x))))
|
||||
|| ((outer_code == IOR || outer_code == XOR)
|
||||
&& (satisfies_constraint_K (x)
|
||||
|| (mode == SImode
|
||||
|
@ -30823,15 +30988,60 @@ rs6000_rtx_costs (rtx x, machine_mode mode, int outer_code,
|
|||
|
||||
case NOT:
|
||||
if (outer_code == AND || outer_code == IOR || outer_code == XOR)
|
||||
{
|
||||
*total = 0;
|
||||
else
|
||||
*total = COSTS_N_INSNS (1);
|
||||
return false;
|
||||
}
|
||||
/* FALLTHRU */
|
||||
|
||||
case AND:
|
||||
case CLZ:
|
||||
if (CONST_INT_P (XEXP (x, 1)))
|
||||
{
|
||||
rtx left = XEXP (x, 0);
|
||||
rtx_code left_code = GET_CODE (left);
|
||||
|
||||
/* rotate-and-mask: 1 insn. */
|
||||
if ((left_code == ROTATE
|
||||
|| left_code == ASHIFT
|
||||
|| left_code == LSHIFTRT)
|
||||
&& rs6000_is_valid_shift_mask (XEXP (x, 1), left, mode))
|
||||
{
|
||||
*total = rtx_cost (XEXP (left, 0), mode, left_code, 0, speed);
|
||||
if (!CONST_INT_P (XEXP (left, 1)))
|
||||
*total += rtx_cost (XEXP (left, 1), SImode, left_code, 1, speed);
|
||||
*total += COSTS_N_INSNS (1);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* rotate-and-mask (no rotate), andi., andis.: 1 insn. */
|
||||
HOST_WIDE_INT val = INTVAL (XEXP (x, 1));
|
||||
if (rs6000_is_valid_and_mask (XEXP (x, 1), mode)
|
||||
|| (val & 0xffff) == val
|
||||
|| (val & 0xffff0000) == val
|
||||
|| ((val & 0xffff) == 0 && mode == SImode))
|
||||
{
|
||||
*total = rtx_cost (left, mode, AND, 0, speed);
|
||||
*total += COSTS_N_INSNS (1);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* 2 insns. */
|
||||
if (rs6000_is_valid_2insn_and (XEXP (x, 1), mode))
|
||||
{
|
||||
*total = rtx_cost (left, mode, AND, 0, speed);
|
||||
*total += COSTS_N_INSNS (2);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
*total = COSTS_N_INSNS (1);
|
||||
return false;
|
||||
|
||||
case IOR:
|
||||
/* FIXME */
|
||||
*total = COSTS_N_INSNS (1);
|
||||
return true;
|
||||
|
||||
case CLZ:
|
||||
case XOR:
|
||||
case ZERO_EXTRACT:
|
||||
*total = COSTS_N_INSNS (1);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -3173,9 +3173,6 @@ instructions.
|
|||
@item h
|
||||
@samp{MQ}, @samp{CTR}, or @samp{LINK} register
|
||||
|
||||
@item q
|
||||
@samp{MQ} register
|
||||
|
||||
@item c
|
||||
@samp{CTR} register
|
||||
|
||||
|
@ -3268,18 +3265,9 @@ AIX TOC entry
|
|||
Address operand that is an indexed or indirect from a register (@samp{p} is
|
||||
preferable for @code{asm} statements)
|
||||
|
||||
@item S
|
||||
Constant suitable as a 64-bit mask operand
|
||||
|
||||
@item T
|
||||
Constant suitable as a 32-bit mask operand
|
||||
|
||||
@item U
|
||||
System V Release 4 small data area reference
|
||||
|
||||
@item t
|
||||
AND masks that can be performed by two rldic@{l, r@} instructions
|
||||
|
||||
@item W
|
||||
Vector constant that does not require memory
|
||||
|
||||
|
|
Loading…
Reference in New Issue