/* Subroutines used for code generation on IBM RS/6000.
- Copyright (C) 1991, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
+ Copyright (C) 1991, 93-7, 1998 Free Software Foundation, Inc.
Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
This file is part of GNU CC.
POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
{"620", PROCESSOR_PPC620,
MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
- POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
+ POWER_MASKS | MASK_PPC_GPOPT},
{"801", PROCESSOR_MPCCORE,
MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS,
POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
}
}
+ if (flag_pic && (DEFAULT_ABI == ABI_AIX))
+ {
+ warning ("-f%s ignored for AIX (all code is position independent)",
+ (flag_pic > 1) ? "PIC" : "pic");
+ flag_pic = 0;
+ }
+
/* Set debug flags */
if (rs6000_debug_name)
{
REAL_VALUE_TYPE value = REAL_VALUE_ATOF (string, mode);
return immed_real_const_1 (value, mode);
}
-
-\f
-/* Create a CONST_DOUBLE like immed_double_const, except reverse the
- two parts of the constant if the target is little endian. */
-
-struct rtx_def *
-rs6000_immed_double_const (i0, i1, mode)
- HOST_WIDE_INT i0, i1;
- enum machine_mode mode;
-{
- if (! WORDS_BIG_ENDIAN)
- return immed_double_const (i1, i0, mode);
-
- return immed_double_const (i0, i1, mode);
-}
-
\f
/* Return non-zero if this function is known to have a null epilogue. */
register rtx op;
enum machine_mode mode;
{
- return (GET_CODE (op) == CONST_INT && (INTVAL (op) & 0xffff0000) == 0);
+ return (GET_CODE (op) == CONST_INT
+ && (INTVAL (op) & (~ (HOST_WIDE_INT) 0xffff)) == 0);
}
/* Return 1 if OP is a CONST_INT that cannot fit in a signed D field. */
enum machine_mode mode;
{
if (GET_CODE (op) == CONST_INT
- && (INTVAL (op) & 0xffff0000) == 0)
+ && (INTVAL (op) & (~ (HOST_WIDE_INT) 0xffff)) == 0)
return 1;
return gpc_reg_operand (op, mode);
&& ((low & 0x80000000) != 0))
return num_insns_constant_wide (low);
+ else if (mask64_operand (op, mode))
+ return 2;
+
else if (low == 0)
return num_insns_constant_wide (high) + 1;
return num_insns_constant_wide (l) == 1;
}
- else if (mode == DImode && TARGET_32BIT)
- return num_insns_constant (op, DImode) == 2;
+ else if (mode == DImode)
+ return ((TARGET_64BIT
+ && GET_CODE (op) == CONST_DOUBLE && CONST_DOUBLE_LOW (op) == 0)
+ || (num_insns_constant (op, DImode) <= 2));
else
abort ();
{
return (gpc_reg_operand (op, mode)
|| (GET_CODE (op) == CONST_INT
- && ((INTVAL (op) & 0xffff0000) == 0
+ && ((INTVAL (op) & (~ (HOST_WIDE_INT) 0xffff)) == 0
|| (INTVAL (op) & 0xffff) == 0)));
}
enum machine_mode mode;
{
return (GET_CODE (op) == CONST_INT
- && (INTVAL (op) & 0xffff0000) != 0
+ && (INTVAL (op) & (~ (HOST_WIDE_INT) 0xffff)) != 0
&& (INTVAL (op) & 0xffff) != 0);
}
int
mask_constant (c)
- register int c;
+ register HOST_WIDE_INT c;
{
int i;
int last_bit_value;
return GET_CODE (op) == CONST_INT && mask_constant (INTVAL (op));
}
-/* Return 1 if the operand is either a non-special register or a
- constant that can be used as the operand of an RS/6000 logical AND insn. */
+/* Return 1 if the operand is a constant that is a PowerPC64 mask.
+ It is if there are no more than one 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. */
int
-and_operand (op, mode)
+mask64_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ if (GET_CODE (op) == CONST_INT)
+ {
+ HOST_WIDE_INT c = INTVAL (op);
+ int i;
+ int last_bit_value;
+ int transitions = 0;
+
+ if (c == 0 || c == ~0)
+ return 0;
+
+ last_bit_value = c & 1;
+
+ for (i = 1; i < HOST_BITS_PER_WIDE_INT; i++)
+ if (((c >>= 1) & 1) != last_bit_value)
+ last_bit_value ^= 1, transitions++;
+
+#if HOST_BITS_PER_INT == 32
+ /* Consider CONST_INT sign-extended. */
+ transitions += (last_bit_value != 1);
+#endif
+
+ return transitions <= 1;
+ }
+ else if (GET_CODE (op) == CONST_DOUBLE
+ && (mode == VOIDmode || mode == DImode))
+ {
+ HOST_WIDE_INT low = CONST_DOUBLE_LOW (op);
+#if HOST_BITS_PER_INT == 32
+ HOST_WIDE_INT high = CONST_DOUBLE_HIGH (op);
+#endif
+ int i;
+ int last_bit_value;
+ int transitions = 0;
+
+ if ((low == 0
+#if HOST_BITS_PER_INT == 32
+ && high == 0
+#endif
+ )
+ || (low == ~0
+#if HOST_BITS_PER_INT == 32
+ && high == ~0
+#endif
+ ))
+ return 0;
+
+ last_bit_value = low & 1;
+
+ for (i = 1; i < HOST_BITS_PER_WIDE_INT; i++)
+ if (((low >>= 1) & 1) != last_bit_value)
+ last_bit_value ^= 1, transitions++;
+
+#if HOST_BITS_PER_INT == 32
+ if ((high & 1) != last_bit_value)
+ last_bit_value ^= 1, transitions++;
+
+ for (i = 1; i < HOST_BITS_PER_WIDE_INT; i++)
+ if (((high >>= 1) & 1) != last_bit_value)
+ last_bit_value ^= 1, transitions++;
+#endif
+
+ return transitions <= 1;
+ }
+ else
+ return 0;
+}
+
+/* Return 1 if the operand is either a non-special register or a constant
+ that can be used as the operand of a PowerPC64 logical AND insn. */
+
+int
+and64_operand (op, mode)
register rtx op;
enum machine_mode mode;
{
return (logical_operand (op, mode)
- || mask_operand (op, mode));
+ || mask64_operand (op, mode));
}
-/* Return 1 if the operand is a constant but not a valid operand for an AND
- insn. */
+/* Return 1 if the operand is either a non-special register or a
+ constant that can be used as the operand of an RS/6000 logical AND insn. */
int
-non_and_cint_operand (op, mode)
- register rtx op;
- enum machine_mode mode;
+and_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode;
{
- return GET_CODE (op) == CONST_INT && ! and_operand (op, mode);
+ return (logical_operand (op, mode)
+ || mask_operand (op, mode));
}
/* Return 1 if the operand is a general register or memory operand. */
tree type;
int named;
{
- int align = ((cum->words & 1) != 0 && function_arg_boundary (mode, type) == 64) ? 1 : 0;
+ int align = (TARGET_32BIT && (cum->words & 1) != 0
+ && function_arg_boundary (mode, type) == 64) ? 1 : 0;
cum->words += align;
cum->nargs_prototype--;
tree type;
int named;
{
- int align = ((cum->words & 1) != 0 && function_arg_boundary (mode, type) == 64) ? 1 : 0;
+ int align = (TARGET_32BIT && (cum->words & 1) != 0
+ && function_arg_boundary (mode, type) == 64) ? 1 : 0;
int align_words = cum->words + align;
if (TARGET_DEBUG_ARG)
{
rtx save_area = virtual_incoming_args_rtx;
- int reg_size = (TARGET_64BIT) ? 8 : 4;
+ int reg_size = TARGET_32BIT ? 4 : 8;
if (TARGET_DEBUG_ARG)
fprintf (stderr,
char code;
{
int i;
- int val;
+ HOST_WIDE_INT val;
/* These macros test for integers and extract the low-order bits. */
#define INT_P(X) \
fprintf (file, "%d", INT_LOWPART (x) & 0xffff);
return;
+ case 'B':
+ /* If the low-order bit is zero, write 'r'; otherwise, write 'l'
+ for 64-bit mask direction. */
+ putc ((INT_LOWPART(x) & 1 == 0 ? 'r' : 'l'), file);
+
case 'C':
/* This is an optional cror needed for LE or GE floating-point
comparisons. Otherwise write nothing. */
if (((val >>= 1) & 1) == 0)
break;
- /* If we ended in ...01, I would be 0. The correct value is 31, so
+ /* If we ended in ...01, i would be 0. The correct value is 31, so
we want 31 - i. */
fprintf (file, "%d", 31 - i);
return;
case 'M':
/* ME value for a mask operand. */
if (! mask_operand (x, VOIDmode))
- output_operand_lossage ("invalid %%m value");
+ output_operand_lossage ("invalid %%M value");
val = INT_LOWPART (x);
if ((val >>= 1) & 1)
break;
- /* If we had ....10, I would be 0. The result should be
+ /* If we had ....10, i would be 0. The result should be
30, so we need 30 - i. */
fprintf (file, "%d", 30 - i);
return;
fprintf (file, "%d", (32 - INT_LOWPART (x)) & 31);
return;
+ case 'S':
+ /* PowerPC64 mask position. All 0's and all 1's are 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, VOIDmode))
+ output_operand_lossage ("invalid %%S value");
+
+ val = INT_LOWPART (x);
+
+ if (val & 1) /* Clear Left */
+ {
+ if (val == 1)
+ i = 0;
+ else
+ for (i = 1; i < HOST_BITS_PER_WIDE_INT; i++)
+ if (!((val >>= 1) & 1))
+ break;
+
+#if HOST_BITS_PER_INT == 32
+ if (GET_CODE (x) == CONST_DOUBLE && i == 32)
+ {
+ val = CONST_DOUBLE_HIGH (x);
+
+ if (val == 0)
+ --i;
+ else if (val == 1)
+ ;
+ else
+ for (i = 33; i < 64; i++)
+ if (!((val >>= 1) & 1))
+ break;
+ }
+#endif
+ fprintf (file, "%d", 63 - i);
+ return;
+ }
+ else /* Clear Right */
+ {
+ val = (GET_CODE (x) == CONST_INT ? INTVAL (x) : CONST_DOUBLE_HIGH (x));
+
+ if (val == (-1 << (HOST_BITS_PER_WIDE_INT-1)))
+ i = 0;
+ else
+ for (i = 1; i < HOST_BITS_PER_WIDE_INT; i++)
+ if ((val <<= 1) < 0)
+ break;
+
+#if HOST_BITS_PER_INT == 32
+ if (GET_CODE (x) == CONST_DOUBLE && i == 32)
+ {
+ val = CONST_DOUBLE_LOW (x);
+
+ if (val == 0)
+ --i;
+ else if (val == (-1 << (HOST_BITS_PER_WIDE_INT-1)))
+ ;
+ else
+ for (i = 33; i < 64; i++)
+ if ((val <<= 1) < 0)
+ break;
+ }
+#endif
+ fprintf (file, "%d", i);
+ return;
+ }
+
case 't':
/* Write 12 if this jump operation will branch if true, 4 otherwise.
All floating-point operations except NE branch true and integer
sequence and the V.4 calling sequence.
AIX stack frames look like:
-
+ 32-bit 64-bit
SP----> +---------------------------------------+
- | back chain to caller | 0
+ | back chain to caller | 0 0
+---------------------------------------+
- | saved CR | 4
+ | saved CR | 4 8 (8-11)
+---------------------------------------+
- | saved LR | 8
+ | saved LR | 8 16
+---------------------------------------+
- | reserved for compilers | 12
+ | reserved for compilers | 12 24
+---------------------------------------+
- | reserved for binders | 16
+ | reserved for binders | 16 32
+---------------------------------------+
- | saved TOC pointer | 20
+ | saved TOC pointer | 20 40
+---------------------------------------+
- | Parameter save area (P) | 24
+ | Parameter save area (P) | 24 48
+---------------------------------------+
- | Alloca space (A) | 24+P
+ | Alloca space (A) | 24+P etc.
+---------------------------------------+
| Local variable space (L) | 24+P+A
+---------------------------------------+
{
static rs6000_stack_t info, zero_info;
rs6000_stack_t *info_ptr = &info;
- int reg_size = TARGET_64BIT ? 8 : 4;
+ int reg_size = TARGET_32BIT ? 4 : 8;
enum rs6000_abi abi;
int total_raw_size;
else
info_ptr->push_p = (frame_pointer_needed
|| write_symbols != NO_DEBUG
- || ((info_ptr->total_size - info_ptr->fixed_size)
+ || ((total_raw_size - info_ptr->fixed_size)
> (TARGET_32BIT ? 220 : 296)));
/* Calculate the offsets */
info_ptr->fp_save_offset = - info_ptr->fp_size;
info_ptr->gp_save_offset = info_ptr->fp_save_offset - info_ptr->gp_size;
info_ptr->main_save_offset = info_ptr->gp_save_offset - info_ptr->main_size;
- info_ptr->cr_save_offset = 4;
- info_ptr->lr_save_offset = 8;
+ info_ptr->cr_save_offset = reg_size; /* first word when 64-bit. */
+ info_ptr->lr_save_offset = 2*reg_size;
break;
case ABI_V4:
break;
case ABI_NT:
- info_ptr->lr_save_offset = -4;
+ info_ptr->lr_save_offset = -reg_size;
info_ptr->toc_save_offset = info_ptr->lr_save_offset - info_ptr->lr_size;
info_ptr->cr_save_offset = info_ptr->toc_save_offset - info_ptr->toc_size;
info_ptr->gp_save_offset = info_ptr->cr_save_offset - info_ptr->cr_size - info_ptr->gp_size + reg_size;
info_ptr->fp_save_offset = info_ptr->gp_save_offset - info_ptr->fp_size;
if (info_ptr->fp_size && ((- info_ptr->fp_save_offset) % 8) != 0)
- info_ptr->fp_save_offset -= 4;
+ info_ptr->fp_save_offset -= reg_size;
info_ptr->main_save_offset = info_ptr->fp_save_offset - info_ptr->main_size;
break;
{
info_ptr->fpmem_offset = info_ptr->main_save_offset - info_ptr->fpmem_size;
rs6000_fpmem_size = info_ptr->fpmem_size;
- rs6000_fpmem_offset = info_ptr->push_p
- ? info_ptr->total_size + info_ptr->fpmem_offset
- : info_ptr->fpmem_offset;
+ rs6000_fpmem_offset = (info_ptr->push_p
+ ? info_ptr->total_size + info_ptr->fpmem_offset
+ : info_ptr->fpmem_offset);
}
else
info_ptr->fpmem_offset = 0;
address before loading. */
if (rs6000_pic_func_labelno != rs6000_pic_labelno)
{
- char *init_ptr = (TARGET_64BIT) ? ".quad" : ".long";
+ char *init_ptr = TARGET_32BIT ? ".long" : ".quad";
char *buf_ptr;
ASM_OUTPUT_INTERNAL_LABEL (file, "LCL", rs6000_pic_labelno);
fprintf (file, "\tmflr %s\n", reg_names[reg]);
if (rs6000_pic_func_labelno != rs6000_pic_labelno)
- {
- if (TARGET_POWERPC64)
- fprintf (file, "\taddi %s,%s,8\n", reg_names[reg], reg_names[reg]);
- else if (TARGET_NEW_MNEMONICS)
- fprintf (file, "\taddi %s,%s,4\n", reg_names[reg], reg_names[reg]);
- else
- fprintf (file, "\tcal %s,4(%s)\n", reg_names[reg], reg_names[reg]);
- }
+ asm_fprintf(file, "\t{cal|la} %s,%d(%s)\n", reg_names[reg],
+ (TARGET_32BIT ? 4 : 8), reg_names[reg]);
- if (TARGET_POWERPC64)
- fprintf (file, "\tld");
- else if (TARGET_NEW_MNEMONICS)
- fprintf (file, "\tlwz");
- else
- fprintf (file, "\tl");
-
- fprintf (file, " %s,(", reg_names[0]);
+ asm_fprintf (file, (TARGET_32BIT) ? "\t{l|lwz} %s,(" : "\tld %s,(",
+ reg_names[0]);
ASM_GENERATE_INTERNAL_LABEL (buf, "LCL", rs6000_pic_labelno);
assemble_name (file, buf);
- fprintf (file, "-");
+ fputs ("-", file);
ASM_GENERATE_INTERNAL_LABEL (buf, "LCF", rs6000_pic_labelno);
assemble_name (file, buf);
fprintf (file, ")(%s)\n", reg_names[reg]);
else if (!TARGET_64BIT)
{
ASM_GENERATE_INTERNAL_LABEL (buf, "LCTOC", 1);
- asm_fprintf (file, "\t{cau|addis} %s,%s,", reg_names[reg], reg_names[0]);
+ asm_fprintf (file, "\t{liu|lis} %s,", reg_names[reg]);
assemble_name (file, buf);
asm_fprintf (file, "@ha\n");
- if (TARGET_NEW_MNEMONICS)
- {
- asm_fprintf (file, "\taddi %s,%s,", reg_names[reg], reg_names[reg]);
- assemble_name (file, buf);
- asm_fprintf (file, "@l\n");
- }
- else
- {
- asm_fprintf (file, "\tcal %s,", reg_names[reg]);
- assemble_name (file, buf);
- asm_fprintf (file, "@l(%s)\n", reg_names[reg]);
- }
+ asm_fprintf (file, "\t{cal|la} %s,", reg_names[reg]);
+ assemble_name (file, buf);
+ asm_fprintf (file, "@l(%s)\n", reg_names[reg]);
}
else
abort ();
{
fprintf (file, "\tmr %s,%s\n", reg_names[12], reg_names[1]);
if (size < 32767)
- {
- if (TARGET_NEW_MNEMONICS)
- fprintf (file, "\taddi %s,%s,%d\n", reg_names[1], reg_names[1], neg_size);
- else
- fprintf (file, "\tcal %s,%d(%s)\n", reg_names[1], neg_size, reg_names[1]);
- }
+ fprintf (file, "\t{cal|la} %s,%d(%s)\n",
+ reg_names[1], neg_size, reg_names[1]);
else
{
asm_fprintf (file, "\t{liu|lis} %s,%d\n\t{oril|ori} %s,%s,%d\n",
{
if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)
sp_offset = info->total_size;
- else if (TARGET_NEW_MNEMONICS)
- asm_fprintf (file, "\taddi %s,%s,%d\n", reg_names[1], reg_names[1], info->total_size);
else
- asm_fprintf (file, "\tcal %s,%d(%s)\n", reg_names[1], info->total_size, reg_names[1]);
+ asm_fprintf (file, "\t{cal|la} %s,%d(%s)\n",
+ reg_names[1], info->total_size, reg_names[1]);
}
/* Get the old lr if we saved it. */
/* If this is V.4, unwind the stack pointer after all of the loads have been done */
if (sp_offset)
- {
- if (TARGET_NEW_MNEMONICS)
- asm_fprintf (file, "\taddi %s,%s,%d\n", reg_names[1], reg_names[1], sp_offset);
- else
- asm_fprintf (file, "\tcal %s,%d(%s)\n", reg_names[1], sp_offset, reg_names[1]);
- }
+ asm_fprintf (file, "\t{cal|la} %s,%d(%s)\n",
+ reg_names[1], sp_offset, reg_names[1]);
else if (sp_reg != 1)
asm_fprintf (file, "\tmr %s,%s\n", reg_names[1], reg_names[sp_reg]);
fputs ("\n\t.previous\n", file);
}
#endif
- else if (TARGET_NEW_MNEMONICS)
- {
- fprintf (file, "\taddis %s,%s,", reg_names[11], reg_names[11]);
- assemble_name (file, buf);
- fprintf (file, "@ha\n");
- fprintf (file, "\tstw %s,4(%s)\n", reg_names[0], reg_names[1]);
- fprintf (file, "\taddi %s,%s,", reg_names[0], reg_names[11]);
- assemble_name (file, buf);
- fputs ("@l\n", file);
- }
else
{
- fprintf (file, "\tcau %s,%s,", reg_names[11], reg_names[11]);
+ asm_fprintf (file, "\t{liu|lis} %s,", reg_names[11]);
assemble_name (file, buf);
- fprintf (file, "@ha\n");
- fprintf (file, "\tst %s,4(%s)\n", reg_names[0], reg_names[1]);
- fprintf (file, "\tcal %s,", reg_names[11]);
+ asm_fprintf (file, "@ha\n");
+ asm_fprintf (file, "\t{st|stw} %s,4(%s)\n", reg_names[0], reg_names[1]);
+ asm_fprintf (file, "\t{cal|la} %s,", reg_names[0]);
assemble_name (file, buf);
- fprintf (file, "@l(%s)\n", reg_names[11]);
+ asm_fprintf (file, "@l(%s)\n", reg_names[11]);
}
fprintf (file, "\tbl %s\n", RS6000_MCOUNT);
ASM_GENERATE_INTERNAL_LABEL (buf, "LPC", labelno);
asm_fprintf (file, "\t{l|lwz} %s,", reg_names[3]);
assemble_name (file, buf);
- asm_fprintf (file, "(%s)\n\tbl %s\n", reg_names[2], RS6000_MCOUNT);
+ asm_fprintf (file, "(%s)\n\tbl %s\n\t%s\n",
+ reg_names[2], RS6000_MCOUNT, RS6000_CALL_GLUE);
/* Restore parameter registers. */
call. For real AIX and NT calling sequences, we also replace the
function name with the real name (1 or 2 leading .'s), rather than
the function descriptor name. This saves a lot of overriding code
- to readd the prefixes. */
+ to read the prefixes. */
void
rs6000_encode_section_info (decl)
;; Machine description for IBM RISC System 6000 (POWER) for GNU C compiler
-;; Copyright (C) 1990, 91-96, 1997, 1998 Free Software Foundation, Inc.
+;; Copyright (C) 1990, 91-97, 1998 Free Software Foundation, Inc.
;; Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
;; This file is part of GNU CC.
|| rtx_equal_p (operands[0], operands[1]))
? operands[0] : gen_reg_rtx (SImode));
- emit_insn (gen_iorsi3 (tmp, operands[1], GEN_INT (value & 0xffff0000)));
- emit_insn (gen_iorsi3 (operands[0], tmp, GEN_INT (value & 0x0000ffff)));
+ emit_insn (gen_iorsi3 (tmp, operands[1],
+ GEN_INT (value & (~ (HOST_WIDE_INT) 0xffff))));
+ emit_insn (gen_iorsi3 (operands[0], tmp, GEN_INT (value & 0xffff)));
DONE;
}
}")
"or. %0,%1,%2"
[(set_attr "type" "compare")])
+;; Split an IOR that we can't do in one insn into two insns, each of which
+;; does one 16-bit part. This is used by combine.
+
+(define_split
+ [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (ior:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "non_logical_cint_operand" "")))]
+ ""
+ [(set (match_dup 0) (ior:SI (match_dup 1) (match_dup 3)))
+ (set (match_dup 0) (ior:SI (match_dup 0) (match_dup 4)))]
+"
+{
+ operands[3] = GEN_INT (INTVAL (operands[2]) & (~ (HOST_WIDE_INT) 0xffff));
+ operands[4] = GEN_INT (INTVAL (operands[2]) & 0xffff);
+}")
+
(define_expand "xorsi3"
[(set (match_operand:SI 0 "gpc_reg_operand" "")
(xor:SI (match_operand:SI 1 "gpc_reg_operand" "")
|| rtx_equal_p (operands[0], operands[1]))
? operands[0] : gen_reg_rtx (SImode));
- emit_insn (gen_xorsi3 (tmp, operands[1], GEN_INT (value & 0xffff0000)));
- emit_insn (gen_xorsi3 (operands[0], tmp, GEN_INT (value & 0x0000ffff)));
+ emit_insn (gen_xorsi3 (tmp, operands[1],
+ GEN_INT (value & (~ (HOST_WIDE_INT) 0xffff))));
+ emit_insn (gen_xorsi3 (operands[0], tmp, GEN_INT (value & 0xffff)));
DONE;
}
}")
"xor. %0,%1,%2"
[(set_attr "type" "compare")])
-(define_insn "*eqv_internal1"
+;; Split an XOR that we can't do in one insn into two insns, each of which
+;; does one 16-bit part. This is used by combine.
+
+(define_split
+ [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (xor:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "non_logical_cint_operand" "")))]
+ ""
+ [(set (match_dup 0) (xor:SI (match_dup 1) (match_dup 3)))
+ (set (match_dup 0) (xor:SI (match_dup 0) (match_dup 4)))]
+"
+{
+ operands[3] = GEN_INT (INTVAL (operands[2]) & (~ (HOST_WIDE_INT) 0xffff));
+ operands[4] = GEN_INT (INTVAL (operands[2]) & 0xffff);
+}")
+
+(define_insn "*eqvsi3_internal1"
[(set (match_operand:SI 0 "gpc_reg_operand" "=r")
(not:SI (xor:SI (match_operand:SI 1 "gpc_reg_operand" "%r")
(match_operand:SI 2 "gpc_reg_operand" "r"))))]
""
"eqv %0,%1,%2")
-(define_insn "*eqv_internal2"
+(define_insn "*eqvsi3_internal2"
[(set (match_operand:CC 0 "cc_reg_operand" "=x")
(compare:CC (not:SI (xor:SI (match_operand:SI 1 "gpc_reg_operand" "%r")
(match_operand:SI 2 "gpc_reg_operand" "r")))
"eqv. %3,%1,%2"
[(set_attr "type" "compare")])
-(define_insn "*eqv_internal3"
+(define_insn "*eqvsi3_internal3"
[(set (match_operand:CC 3 "cc_reg_operand" "=x")
(compare:CC (not:SI (xor:SI (match_operand:SI 1 "gpc_reg_operand" "%r")
(match_operand:SI 2 "gpc_reg_operand" "r")))
"eqv. %0,%1,%2"
[(set_attr "type" "compare")])
-(define_insn "*andc_internal1"
+(define_insn "*andcsi3_internal1"
[(set (match_operand:SI 0 "gpc_reg_operand" "=r")
(and:SI (not:SI (match_operand:SI 1 "gpc_reg_operand" "r"))
(match_operand:SI 2 "gpc_reg_operand" "r")))]
""
"andc %0,%2,%1")
-(define_insn "*andc_internal2"
+(define_insn "*andcsi3_internal2"
[(set (match_operand:CC 0 "cc_reg_operand" "=x")
(compare:CC (and:SI (not:SI (match_operand:SI 1 "gpc_reg_operand" "r"))
(match_operand:SI 2 "gpc_reg_operand" "r"))
"andc. %3,%2,%1"
[(set_attr "type" "compare")])
-(define_insn "*andc_internal3"
+(define_insn "*andcsi3_internal3"
[(set (match_operand:CC 3 "cc_reg_operand" "=x")
(compare:CC (and:SI (not:SI (match_operand:SI 1 "gpc_reg_operand" "r"))
(match_operand:SI 2 "gpc_reg_operand" "r"))
"andc. %0,%2,%1"
[(set_attr "type" "compare")])
-(define_insn "*iorc_internal1"
+(define_insn "*iorcsi3_internal1"
[(set (match_operand:SI 0 "gpc_reg_operand" "=r")
(ior:SI (not:SI (match_operand:SI 1 "gpc_reg_operand" "r"))
(match_operand:SI 2 "gpc_reg_operand" "r")))]
""
"orc %0,%2,%1")
-(define_insn "*iorc_internal2"
+(define_insn "*iorcsi3_internal2"
[(set (match_operand:CC 0 "cc_reg_operand" "=x")
(compare:CC (ior:SI (not:SI (match_operand:SI 1 "gpc_reg_operand" "r"))
(match_operand:SI 2 "gpc_reg_operand" "r"))
"orc. %3,%2,%1"
[(set_attr "type" "compare")])
-(define_insn "*iorc_internal3"
+(define_insn "*iorcsi3_internal3"
[(set (match_operand:CC 3 "cc_reg_operand" "=x")
(compare:CC (ior:SI (not:SI (match_operand:SI 1 "gpc_reg_operand" "r"))
(match_operand:SI 2 "gpc_reg_operand" "r"))
"orc. %0,%2,%1"
[(set_attr "type" "compare")])
-(define_insn "*nand_internal1"
+(define_insn "*nandsi3_internal1"
[(set (match_operand:SI 0 "gpc_reg_operand" "=r")
(ior:SI (not:SI (match_operand:SI 1 "gpc_reg_operand" "%r"))
(not:SI (match_operand:SI 2 "gpc_reg_operand" "r"))))]
""
"nand %0,%1,%2")
-(define_insn "*nand_internal2"
+(define_insn "*nandsi3_internal2"
[(set (match_operand:CC 0 "cc_reg_operand" "=x")
(compare:CC (ior:SI (not:SI (match_operand:SI 1 "gpc_reg_operand" "%r"))
(not:SI (match_operand:SI 2 "gpc_reg_operand" "r")))
"nand. %3,%1,%2"
[(set_attr "type" "compare")])
-(define_insn "*nand_internal3"
+(define_insn "*nandsi3_internal3"
[(set (match_operand:CC 3 "cc_reg_operand" "=x")
(compare:CC (ior:SI (not:SI (match_operand:SI 1 "gpc_reg_operand" "%r"))
(not:SI (match_operand:SI 2 "gpc_reg_operand" "r")))
"nand. %0,%1,%2"
[(set_attr "type" "compare")])
-(define_insn "*nor_internal1"
+(define_insn "*norsi3_internal1"
[(set (match_operand:SI 0 "gpc_reg_operand" "=r")
(and:SI (not:SI (match_operand:SI 1 "gpc_reg_operand" "%r"))
(not:SI (match_operand:SI 2 "gpc_reg_operand" "r"))))]
""
"nor %0,%1,%2")
-(define_insn "*nor_internal2"
+(define_insn "*norsi3_internal2"
[(set (match_operand:CC 0 "cc_reg_operand" "=x")
(compare:CC (and:SI (not:SI (match_operand:SI 1 "gpc_reg_operand" "%r"))
(not:SI (match_operand:SI 2 "gpc_reg_operand" "r")))
"nor. %3,%1,%2"
[(set_attr "type" "compare")])
-(define_insn "*nor_internal3"
+(define_insn "*norsi3_internal3"
[(set (match_operand:CC 3 "cc_reg_operand" "=x")
(compare:CC (and:SI (not:SI (match_operand:SI 1 "gpc_reg_operand" "%r"))
(not:SI (match_operand:SI 2 "gpc_reg_operand" "r")))
""
"{rl%I2nm|rlw%I2nm} %0,%1,%h2,0xffffffff")
-(define_insn ""
+(define_insn "*rotlsi3_internal2"
[(set (match_operand:CC 0 "cc_reg_operand" "=x")
(compare:CC (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "r")
(match_operand:SI 2 "reg_or_cint_operand" "ri"))
"{rl%I2nm.|rlw%I2nm.} %3,%1,%h2,0xffffffff"
[(set_attr "type" "delayed_compare")])
-(define_insn ""
+(define_insn "*rotlsi3_internal3"
[(set (match_operand:CC 3 "cc_reg_operand" "=x")
(compare:CC (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "r")
(match_operand:SI 2 "reg_or_cint_operand" "ri"))
"{rl%I2nm.|rlw%I2nm.} %0,%1,%h2,0xffffffff"
[(set_attr "type" "delayed_compare")])
-(define_insn ""
+(define_insn "*rotlsi3_internal4"
[(set (match_operand:SI 0 "gpc_reg_operand" "=r")
(and:SI (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "r")
(match_operand:SI 2 "reg_or_cint_operand" "ri"))
""
"{rl%I2nm|rlw%I2nm} %0,%1,%h2,%m3,%M3")
-(define_insn ""
+(define_insn "*rotlsi3_internal5"
[(set (match_operand:CC 0 "cc_reg_operand" "=x")
(compare:CC (and:SI
(rotate:SI (match_operand:SI 1 "gpc_reg_operand" "r")
"{rl%I2nm.|rlw%I2nm.} %4,%1,%h2,%m3,%M3"
[(set_attr "type" "delayed_compare")])
-(define_insn ""
+(define_insn "*rotlsi3_internal6"
[(set (match_operand:CC 4 "cc_reg_operand" "=x")
(compare:CC (and:SI
(rotate:SI (match_operand:SI 1 "gpc_reg_operand" "r")
"{rl%I2nm.|rlw%I2nm.} %0,%1,%h2,%m3,%M3"
[(set_attr "type" "delayed_compare")])
-(define_insn ""
+(define_insn "*rotlsi3_internal7"
[(set (match_operand:SI 0 "gpc_reg_operand" "=r")
(zero_extend:SI
(subreg:QI
""
"{rl%I2nm|rlw%I2nm} %0,%1,%h2,0xff")
-(define_insn ""
+(define_insn "*rotlsi3_internal8"
[(set (match_operand:CC 0 "cc_reg_operand" "=x")
(compare:CC (zero_extend:SI
(subreg:QI
"{rl%I2nm.|rlw%I2nm.} %3,%1,%h2,0xff"
[(set_attr "type" "delayed_compare")])
-(define_insn ""
+(define_insn "*rotlsi3_internal9"
[(set (match_operand:CC 3 "cc_reg_operand" "=x")
(compare:CC (zero_extend:SI
(subreg:QI
"{rl%I2nm.|rlw%I2nm.} %0,%1,%h2,0xff"
[(set_attr "type" "delayed_compare")])
-(define_insn ""
+(define_insn "*rotlsi3_internal10"
[(set (match_operand:SI 0 "gpc_reg_operand" "=r")
(zero_extend:SI
(subreg:HI
""
"{rl%I2nm|rlw%I2nm} %0,%1,%h2,0xffff")
-(define_insn ""
+(define_insn "*rotlsi3_internal11"
[(set (match_operand:CC 0 "cc_reg_operand" "=x")
(compare:CC (zero_extend:SI
(subreg:HI
"{rl%I2nm.|rlw%I2nm.} %3,%1,%h2,0xffff"
[(set_attr "type" "delayed_compare")])
-(define_insn ""
+(define_insn "*rotlsi3_internal12"
[(set (match_operand:CC 3 "cc_reg_operand" "=x")
(compare:CC (zero_extend:SI
(subreg:HI
(clobber (match_dup 4))
(clobber (match_dup 5))
(clobber (reg:DF 76))])]
- "! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
+ "TARGET_HARD_FLOAT"
"
{
operands[2] = force_reg (SImode, GEN_INT (0x43300000));
(use (match_operand:SI 2 "gpc_reg_operand" "r"))
(use (match_operand:DF 3 "gpc_reg_operand" "f"))
(clobber (match_operand:SI 4 "gpc_reg_operand" "=r"))
- (clobber (match_operand:SI 5 "gpc_reg_operand" "=b"))
+ (clobber (match_operand 5 "gpc_reg_operand" "=b"))
(clobber (reg:DF 76))]
- "! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
+ "TARGET_HARD_FLOAT"
"#"
[(set_attr "length" "24")])
(use (match_operand:SI 2 "gpc_reg_operand" ""))
(use (match_operand:DF 3 "gpc_reg_operand" ""))
(clobber (match_operand:SI 4 "gpc_reg_operand" ""))
- (clobber (match_operand:SI 5 "gpc_reg_operand" ""))
+ (clobber (match_operand 5 "gpc_reg_operand" ""))
(clobber (reg:DF 76))]
- "! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
+ "TARGET_HARD_FLOAT"
[(set (match_dup 4)
(xor:SI (match_dup 1)
(match_dup 6)))
(use (match_dup 3))
(clobber (match_dup 4))
(clobber (reg:DF 76))])]
- "! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
+ "TARGET_HARD_FLOAT"
"
{
operands[2] = force_reg (SImode, GEN_INT (0x43300000));
(unsigned_float:DF (match_operand:SI 1 "gpc_reg_operand" "r")))
(use (match_operand:SI 2 "gpc_reg_operand" "r"))
(use (match_operand:DF 3 "gpc_reg_operand" "f"))
- (clobber (match_operand:SI 4 "gpc_reg_operand" "=b"))
+ (clobber (match_operand 4 "gpc_reg_operand" "=b"))
(clobber (reg:DF 76))]
- "! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
+ "TARGET_HARD_FLOAT"
"#"
[(set_attr "length" "20")])
(unsigned_float:DF (match_operand:SI 1 "gpc_reg_operand" "")))
(use (match_operand:SI 2 "gpc_reg_operand" ""))
(use (match_operand:DF 3 "gpc_reg_operand" ""))
- (clobber (match_operand:SI 4 "gpc_reg_operand" "=b"))
+ (clobber (match_operand 4 "gpc_reg_operand" "=b"))
(clobber (reg:DF 76))]
- "! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
+ "TARGET_HARD_FLOAT"
[(set (match_dup 4)
(unspec [(const_int 0)] 11))
(set (match_dup 5)
;; Load up scratch register with base address + offset if needed
(define_insn "*floatsidf2_loadaddr"
- [(set (match_operand:SI 0 "gpc_reg_operand" "=b")
+ [(set (match_operand 0 "gpc_reg_operand" "=b")
(unspec [(const_int 0)] 11))]
"TARGET_HARD_FLOAT"
"*
(define_insn "*floatsidf2_store1"
[(set (reg:DF 76)
(unspec [(match_operand:SI 0 "gpc_reg_operand" "r")
- (match_operand:SI 1 "gpc_reg_operand" "r")] 12))]
- "! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
+ (match_operand 1 "gpc_reg_operand" "b")] 12))]
+ "TARGET_HARD_FLOAT"
"*
{
rtx indx;
(define_insn "*floatsidf2_store2"
[(set (reg:DF 76)
(unspec [(match_operand:SI 0 "gpc_reg_operand" "r")
- (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand 1 "gpc_reg_operand" "b")
(reg:DF 76)] 13))]
- "! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
+ "TARGET_HARD_FLOAT"
"*
{
rtx indx;
(define_insn "*floatsidf2_load"
[(set (match_operand:DF 0 "gpc_reg_operand" "=f")
(unspec [(reg:DF 76)
- (match_operand:SI 1 "gpc_reg_operand" "b")] 14))]
- "! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
+ (match_operand 1 "gpc_reg_operand" "b")] 14))]
+ "TARGET_HARD_FLOAT"
"*
{
rtx indx;
[(set (match_operand:SI 0 "gpc_reg_operand" "=r")
(fix:SI (match_operand:DF 1 "gpc_reg_operand" "f")))
(clobber (match_operand:DI 2 "gpc_reg_operand" "=f"))
- (clobber (match_operand:SI 3 "gpc_reg_operand" "=b"))
+ (clobber (match_operand 3 "gpc_reg_operand" "=b"))
(clobber (reg:DI 76))]
"TARGET_HARD_FLOAT"
"#"
[(set (match_operand:SI 0 "gpc_reg_operand" "")
(fix:SI (match_operand:DF 1 "gpc_reg_operand" "f")))
(clobber (match_operand:DI 2 "gpc_reg_operand" ""))
- (clobber (match_operand:SI 3 "gpc_reg_operand" ""))
+ (clobber (match_operand 3 "gpc_reg_operand" ""))
(clobber (reg:DI 76))]
"TARGET_HARD_FLOAT"
[(set (match_dup 2)
(match_dup 3)] 16))]
"operands[4] = gen_rtx (REG, DImode, FPMEM_REGNUM);")
-(define_insn "*fctiwz"
- [(set (match_operand:DI 0 "gpc_reg_operand" "=f")
- (sign_extend:DI (fix:SI (match_operand:DF 1 "gpc_reg_operand" "f"))))]
- "(TARGET_POWER2 || TARGET_POWERPC) && TARGET_HARD_FLOAT"
- "{fcirz|fctiwz} %0,%1"
- [(set_attr "type" "fp")])
-
(define_insn "*fix_truncdfsi2_store"
[(set (reg:DI 76)
(unspec [(match_operand:DI 0 "gpc_reg_operand" "f")
- (match_operand:SI 1 "gpc_reg_operand" "b")] 15))]
+ (match_operand 1 "gpc_reg_operand" "b")] 15))]
"(TARGET_POWER2 || TARGET_POWERPC) && TARGET_HARD_FLOAT"
"*
{
(define_insn "*fix_truncdfsi2_load"
[(set (match_operand:SI 0 "gpc_reg_operand" "=r")
(unspec [(reg:DI 76)
- (match_operand:SI 1 "gpc_reg_operand" "b")] 16))]
+ (match_operand 1 "gpc_reg_operand" "b")] 16))]
"(TARGET_POWER2 || TARGET_POWERPC) && TARGET_HARD_FLOAT"
"*
{
rs6000_trunc_used = 1;
}")
+(define_insn "*fctiwz"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=f")
+ (sign_extend:DI (fix:SI (match_operand:DF 1 "gpc_reg_operand" "f"))))]
+ "(TARGET_POWER2 || TARGET_POWERPC) && TARGET_HARD_FLOAT"
+ "{fcirz|fctiwz} %0,%1"
+ [(set_attr "type" "fp")])
+
(define_insn "floatdidf2"
[(set (match_operand:DF 0 "gpc_reg_operand" "=f")
(float:DF (match_operand:DI 1 "gpc_reg_operand" "f")))]
(define_expand "adddi3"
[(set (match_operand:DI 0 "gpc_reg_operand" "")
(plus:DI (match_operand:DI 1 "gpc_reg_operand" "")
- (match_operand:DI 2 "add_operand" "")))]
+ (match_operand:DI 2 "reg_or_cint_operand" "")))]
""
"
{
- if (! TARGET_POWERPC64 && non_short_cint_operand (operands[2], DImode))
- FAIL;
+ if (! TARGET_POWERPC64)
+ {
+ if (non_short_cint_operand (operands[2], DImode))
+ FAIL;
+ }
+ else
+ if (GET_CODE (operands[2]) == CONST_INT
+ && !add_operand (operands[2], DImode))
+ {
+ rtx tmp = ((reload_in_progress || reload_completed
+ || rtx_equal_p (operands[0], operands[1]))
+ ? operands[0] : gen_reg_rtx (DImode));
+
+ HOST_WIDE_INT low = INTVAL (operands[2]) & 0xffff;
+ HOST_WIDE_INT high = INTVAL (operands[2]) & (~ (HOST_WIDE_INT) 0xffff);
+
+ if (low & 0x8000)
+ high += 0x10000, low |= ((HOST_WIDE_INT) -1) << 16;
+
+ emit_insn (gen_adddi3 (tmp, operands[1], GEN_INT (high)));
+ emit_insn (gen_adddi3 (operands[0], tmp, GEN_INT (low)));
+ DONE;
+ }
}")
;; Discourage ai/addic because of carry but provide it in an alternative
;; allowing register zero as source.
-(define_insn ""
+(define_insn "*adddi3_internal1"
[(set (match_operand:DI 0 "gpc_reg_operand" "=r,r,?r,r")
(plus:DI (match_operand:DI 1 "gpc_reg_operand" "%r,b,r,b")
(match_operand:DI 2 "add_operand" "r,I,I,J")))]
addic %0,%1,%2
addis %0,%1,%v2")
-(define_insn ""
+(define_insn "*adddi3_internal2"
[(set (match_operand:CC 0 "cc_reg_operand" "=x,x")
(compare:CC (plus:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r")
(match_operand:DI 2 "reg_or_short_operand" "r,I"))
addic. %3,%1,%2"
[(set_attr "type" "compare")])
-(define_insn ""
+(define_insn "*adddi3_internal3"
[(set (match_operand:CC 3 "cc_reg_operand" "=x,x")
(compare:CC (plus:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r")
(match_operand:DI 2 "reg_or_short_operand" "r,I"))
(abs:DI (match_operand:DI 1 "gpc_reg_operand" "r,0")))
(clobber (match_scratch:DI 2 "=&r,&r"))]
"TARGET_POWERPC64"
- "sradi %2,%1,31\;xor %0,%2,%1\;subf %0,%2,%0"
+ "sradi %2,%1,63\;xor %0,%2,%1\;subf %0,%2,%0"
[(set_attr "length" "12")])
(define_split
(abs:DI (match_operand:DI 1 "gpc_reg_operand" "r,0")))
(clobber (match_scratch:DI 2 "=&r,&r"))]
"TARGET_POWERPC64 && reload_completed"
- [(set (match_dup 2) (ashiftrt:DI (match_dup 1) (const_int 31)))
+ [(set (match_dup 2) (ashiftrt:DI (match_dup 1) (const_int 63)))
(set (match_dup 0) (xor:DI (match_dup 2) (match_dup 1)))
(set (match_dup 0) (minus:DI (match_dup 2) (match_dup 0)))]
"")
(neg:DI (abs:DI (match_operand:DI 1 "gpc_reg_operand" "r,0"))))
(clobber (match_scratch:DI 2 "=&r,&r"))]
"TARGET_POWERPC64"
- "sradi %2,%1,31\;xor %0,%2,%1\;subf %0,%0,%2"
+ "sradi %2,%1,63\;xor %0,%2,%1\;subf %0,%0,%2"
[(set_attr "length" "12")])
(define_split
(neg:DI (abs:DI (match_operand:DI 1 "gpc_reg_operand" "r,0"))))
(clobber (match_scratch:DI 2 "=&r,&r"))]
"TARGET_POWERPC64 && reload_completed"
- [(set (match_dup 2) (ashiftrt:DI (match_dup 1) (const_int 31)))
+ [(set (match_dup 2) (ashiftrt:DI (match_dup 1) (const_int 63)))
(set (match_dup 0) (xor:DI (match_dup 2) (match_dup 1)))
(set (match_dup 0) (minus:DI (match_dup 0) (match_dup 2)))]
"")
"mulld %0,%1,%2"
[(set_attr "type" "imul")])
+(define_insn "*mulsidi3_ppc64"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (mult:DI (sign_extend:DI (match_operand:SI 1 "gpc_reg_operand" "%r"))
+ (sign_extend:DI (match_operand:SI 2 "gpc_reg_operand" "r"))))]
+ "TARGET_POWERPC64"
+ "mulld %0,%1,%2"
+ [(set_attr "type" "imul")])
+
(define_insn "smuldi3_highpart"
[(set (match_operand:DI 0 "gpc_reg_operand" "=r")
(truncate:DI
(define_insn ""
[(set (match_operand:DI 0 "gpc_reg_operand" "=r")
(div:DI (match_operand:DI 1 "gpc_reg_operand" "r")
- (match_operand:DI 2 "gpc_reg_operand" "r")))]
+ (match_operand:DI 2 "gpc_reg_operand" "r")))]
"TARGET_POWERPC64"
"divd %0,%1,%2"
[(set_attr "type" "idiv")])
"TARGET_POWERPC64"
"rld%I2cl %0,%1,%H2,0")
-(define_insn ""
+(define_insn "*rotldi3_internal2"
[(set (match_operand:CC 0 "cc_reg_operand" "=x")
(compare:CC (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r")
(match_operand:DI 2 "reg_or_cint_operand" "ri"))
"rld%I2cl. %3,%1,%H2,0"
[(set_attr "type" "delayed_compare")])
-(define_insn ""
+(define_insn "*rotldi3_internal3"
[(set (match_operand:CC 3 "cc_reg_operand" "=x")
(compare:CC (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r")
(match_operand:DI 2 "reg_or_cint_operand" "ri"))
"rld%I2cl. %0,%1,%H2,0"
[(set_attr "type" "delayed_compare")])
+(define_insn "*rotldi3_internal4"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (and:DI (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r")
+ (match_operand:DI 2 "reg_or_cint_operand" "ri"))
+ (match_operand:DI 3 "mask64_operand" "S")))]
+ "TARGET_POWERPC64"
+ "rld%I2c%B3 %0,%1,%H2,%S3")
+
+(define_insn "*rotldi3_internal5"
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x")
+ (compare:CC (and:DI
+ (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r")
+ (match_operand:DI 2 "reg_or_cint_operand" "ri"))
+ (match_operand:DI 3 "mask64_operand" "S"))
+ (const_int 0)))
+ (clobber (match_scratch:DI 4 "=r"))]
+ "TARGET_POWERPC64"
+ "rld%I2c%B3. %4,%1,%H2,%S3"
+ [(set_attr "type" "delayed_compare")])
+
+(define_insn "*rotldi3_internal6"
+ [(set (match_operand:CC 4 "cc_reg_operand" "=x")
+ (compare:CC (and:DI
+ (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r")
+ (match_operand:DI 2 "reg_or_cint_operand" "ri"))
+ (match_operand:DI 3 "mask64_operand" "S"))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (and:DI (rotate:DI (match_dup 1) (match_dup 2)) (match_dup 3)))]
+ "TARGET_POWERPC64"
+ "rld%I2c%B3. %0,%1,%H2,%S3"
+ [(set_attr "type" "delayed_compare")])
+
+(define_insn "*rotldi3_internal7"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (zero_extend:DI
+ (subreg:QI
+ (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r")
+ (match_operand:DI 2 "reg_or_cint_operand" "ri")) 0)))]
+ "TARGET_POWERPC64"
+ "rld%I2cl %0,%1,%H2,56")
+
+(define_insn "*rotldi3_internal8"
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x")
+ (compare:CC (zero_extend:DI
+ (subreg:QI
+ (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r")
+ (match_operand:DI 2 "reg_or_cint_operand" "ri")) 0))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 "=r"))]
+ "TARGET_POWERPC64"
+ "rld%I2cl. %3,%1,%H2,56"
+ [(set_attr "type" "delayed_compare")])
+
+(define_insn "*rotldi3_internal9"
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x")
+ (compare:CC (zero_extend:DI
+ (subreg:QI
+ (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r")
+ (match_operand:DI 2 "reg_or_cint_operand" "ri")) 0))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (zero_extend:DI (subreg:QI (rotate:DI (match_dup 1) (match_dup 2)) 0)))]
+ "TARGET_POWERPC64"
+ "rld%I2cl. %0,%1,%H2,56"
+ [(set_attr "type" "delayed_compare")])
+
+(define_insn "*rotldi3_internal10"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (zero_extend:DI
+ (subreg:HI
+ (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r")
+ (match_operand:DI 2 "reg_or_cint_operand" "ri")) 0)))]
+ "TARGET_POWERPC64"
+ "rld%I2cl %0,%1,%H2,48")
+
+(define_insn "*rotldi3_internal11"
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x")
+ (compare:CC (zero_extend:DI
+ (subreg:HI
+ (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r")
+ (match_operand:DI 2 "reg_or_cint_operand" "ri")) 0))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 "=r"))]
+ "TARGET_POWERPC64"
+ "rld%I2cl. %3,%1,%H2,48"
+ [(set_attr "type" "delayed_compare")])
+
+(define_insn "*rotldi3_internal12"
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x")
+ (compare:CC (zero_extend:DI
+ (subreg:HI
+ (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r")
+ (match_operand:DI 2 "reg_or_cint_operand" "ri")) 0))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (zero_extend:DI (subreg:HI (rotate:DI (match_dup 1) (match_dup 2)) 0)))]
+ "TARGET_POWERPC64"
+ "rld%I2cl. %0,%1,%H2,48"
+ [(set_attr "type" "delayed_compare")])
+
+(define_insn "*rotldi3_internal13"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (zero_extend:DI
+ (subreg:SI
+ (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r")
+ (match_operand:DI 2 "reg_or_cint_operand" "ri")) 0)))]
+ "TARGET_POWERPC64"
+ "rld%I2cl %0,%1,%H2,32")
+
+(define_insn "*rotldi3_internal14"
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x")
+ (compare:CC (zero_extend:DI
+ (subreg:SI
+ (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r")
+ (match_operand:DI 2 "reg_or_cint_operand" "ri")) 0))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 "=r"))]
+ "TARGET_POWERPC64"
+ "rld%I2cl. %3,%1,%H2,32"
+ [(set_attr "type" "delayed_compare")])
+
+(define_insn "*rotldi3_internal15"
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x")
+ (compare:CC (zero_extend:DI
+ (subreg:SI
+ (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r")
+ (match_operand:DI 2 "reg_or_cint_operand" "ri")) 0))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (zero_extend:DI (subreg:SI (rotate:DI (match_dup 1) (match_dup 2)) 0)))]
+ "TARGET_POWERPC64"
+ "rld%I2cl. %0,%1,%H2,32"
+ [(set_attr "type" "delayed_compare")])
+
(define_expand "ashldi3"
[(set (match_operand:DI 0 "gpc_reg_operand" "")
(ashift:DI (match_operand:DI 1 "gpc_reg_operand" "")
[(set_attr "type" "delayed_compare")])
(define_insn "anddi3"
- [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r")
- (and:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r,r")
- (match_operand:DI 2 "and_operand" "?r,K,J")))
- (clobber (match_scratch:CC 3 "=X,x,x"))]
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r,r")
+ (and:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r,r,r")
+ (match_operand:DI 2 "and64_operand" "?r,S,K,J")))
+ (clobber (match_scratch:CC 3 "=X,X,x,x"))]
"TARGET_POWERPC64"
"@
and %0,%1,%2
+ rldic%B2 %0,%1,0,%S2
andi. %0,%1,%b2
andis. %0,%1,%u2")
-(define_insn ""
- [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,x")
- (compare:CC (and:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r,r")
- (match_operand:DI 2 "and_operand" "r,K,J"))
+(define_insn "*anddi3_internal2"
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,x,x")
+ (compare:CC (and:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r,r,r")
+ (match_operand:DI 2 "and64_operand" "r,K,J,S"))
(const_int 0)))
- (clobber (match_scratch:DI 3 "=r,r,r"))]
+ (clobber (match_scratch:DI 3 "=r,r,r,r"))]
"TARGET_POWERPC64"
"@
and. %3,%1,%2
andi. %3,%1,%b2
- andis. %3,%1,%u2"
- [(set_attr "type" "compare,compare,compare")])
+ andis. %3,%1,%u2
+ rldic%B2. %3,%1,0,%S2"
+ [(set_attr "type" "compare,compare,compare,delayed_compare")])
-(define_insn ""
- [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,x")
- (compare:CC (and:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r,r")
- (match_operand:DI 2 "and_operand" "r,K,J"))
+(define_insn "*anddi3_internal3"
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,x,x")
+ (compare:CC (and:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r,r,r")
+ (match_operand:DI 2 "and64_operand" "r,K,J,S"))
(const_int 0)))
- (set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r")
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r,r")
(and:DI (match_dup 1) (match_dup 2)))]
"TARGET_POWERPC64"
"@
and. %0,%1,%2
andi. %0,%1,%b2
- andis. %0,%1,%u2"
- [(set_attr "type" "compare,compare,compare")])
-
-;; Take a AND with a constant that cannot be done in a single insn and try to
-;; split it into two insns. This does not verify that the insns are valid
-;; since this need not be done as combine will do it.
+ andis. %0,%1,%u2
+ rldic%B2. %3,%1,0,%S2"
+ [(set_attr "type" "compare,compare,compare,delayed_compare")])
-(define_split
+(define_expand "iordi3"
[(set (match_operand:DI 0 "gpc_reg_operand" "")
- (and:DI (match_operand:DI 1 "gpc_reg_operand" "")
- (match_operand:DI 2 "non_and_cint_operand" "")))]
+ (ior:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "reg_or_cint_operand" "")))]
"TARGET_POWERPC64"
- [(set (match_dup 0) (and:DI (match_dup 1) (match_dup 3)))
- (set (match_dup 0) (and:DI (match_dup 0) (match_dup 4)))]
"
{
- int maskval = INTVAL (operands[2]);
- int i, transitions, last_bit_value;
- int orig = maskval, first_c = maskval, second_c;
-
- /* We know that MASKVAL must have more than 2 bit-transitions. Start at
- the low-order bit and count for the third transition. When we get there,
- make a first mask that has everything to the left of that position
- a one. Then make the second mask to turn off whatever else is needed. */
-
- for (i = 1, transitions = 0, last_bit_value = maskval & 1; i < 32; i++)
+ if (GET_CODE (operands[2]) == CONST_INT
+ && !logical_operand (operands[2], DImode))
{
- if (((maskval >>= 1) & 1) != last_bit_value)
- last_bit_value ^= 1, transitions++;
+ HOST_WIDE_INT value = INTVAL (operands[2]);
+ rtx tmp = ((reload_in_progress || reload_completed
+ || rtx_equal_p (operands[0], operands[1]))
+ ? operands[0] : gen_reg_rtx (DImode));
- if (transitions > 2)
- {
- first_c |= (~0) << i;
- break;
- }
+ emit_insn (gen_iordi3 (tmp, operands[1],
+ GEN_INT (value & (~ (HOST_WIDE_INT) 0xffff))));
+ emit_insn (gen_iordi3 (operands[0], tmp, GEN_INT (value & 0xffff)));
+ DONE;
}
-
- second_c = orig | ~ first_c;
-
- operands[3] = GEN_INT (first_c);
- operands[4] = GEN_INT (second_c);
}")
-(define_insn "iordi3"
+(define_insn "*iordi3_internal1"
[(set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r")
(ior:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r,r")
(match_operand:DI 2 "logical_operand" "r,K,J")))]
ori %0,%1,%b2
oris %0,%1,%u2")
-(define_insn ""
+(define_insn "*iordi3_internal2"
[(set (match_operand:CC 0 "cc_reg_operand" "=x")
(compare:CC (ior:DI (match_operand:DI 1 "gpc_reg_operand" "%r")
(match_operand:DI 2 "gpc_reg_operand" "r"))
"or. %3,%1,%2"
[(set_attr "type" "compare")])
-(define_insn ""
+(define_insn "*iordi3_internal3"
[(set (match_operand:CC 3 "cc_reg_operand" "=x")
(compare:CC (ior:DI (match_operand:DI 1 "gpc_reg_operand" "%r")
(match_operand:DI 2 "gpc_reg_operand" "r"))
operands[4] = GEN_INT (INTVAL (operands[2]) & 0xffff);
}")
-(define_insn "xordi3"
+(define_expand "xordi3"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (xor:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "reg_or_cint_operand" "")))]
+ "TARGET_POWERPC64"
+ "
+{
+ if (GET_CODE (operands[2]) == CONST_INT
+ && !logical_operand (operands[2], DImode))
+ {
+ HOST_WIDE_INT value = INTVAL (operands[2]);
+ rtx tmp = ((reload_in_progress || reload_completed
+ || rtx_equal_p (operands[0], operands[1]))
+ ? operands[0] : gen_reg_rtx (DImode));
+
+ emit_insn (gen_xordi3 (tmp, operands[1],
+ GEN_INT (value & (~ (HOST_WIDE_INT) 0xffff))));
+ emit_insn (gen_xordi3 (operands[0], tmp, GEN_INT (value & 0xffff)));
+ DONE;
+ }
+}")
+
+(define_insn "*xordi3_internal1"
[(set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r")
(xor:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r,r")
(match_operand:DI 2 "logical_operand" "r,K,J")))]
xori %0,%1,%b2
xoris %0,%1,%u2")
-(define_insn ""
+(define_insn "*xordi3_internal2"
[(set (match_operand:CC 0 "cc_reg_operand" "=x")
(compare:CC (xor:DI (match_operand:DI 1 "gpc_reg_operand" "%r")
(match_operand:DI 2 "gpc_reg_operand" "r"))
"xor. %3,%1,%2"
[(set_attr "type" "compare")])
-(define_insn ""
+(define_insn "*xordi3_internal3"
[(set (match_operand:CC 3 "cc_reg_operand" "=x")
(compare:CC (xor:DI (match_operand:DI 1 "gpc_reg_operand" "%r")
(match_operand:DI 2 "gpc_reg_operand" "r"))
(define_split
[(set (match_operand:DI 0 "gpc_reg_operand" "")
- (xor:DI (match_operand:DI 1 "gpc_reg_operand" "")
- (match_operand:DI 2 "non_logical_cint_operand" "")))]
+ (xor:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "non_logical_cint_operand" "")))]
"TARGET_POWERPC64"
[(set (match_dup 0) (xor:DI (match_dup 1) (match_dup 3)))
(set (match_dup 0) (xor:DI (match_dup 0) (match_dup 4)))]
"
{
- operands[3] = GEN_INT (INTVAL (operands[2]) & 0xffff0000);
+ operands[3] = GEN_INT (INTVAL (operands[2]) & (~ (HOST_WIDE_INT) 0xffff));
operands[4] = GEN_INT (INTVAL (operands[2]) & 0xffff);
}")
-(define_insn ""
+(define_insn "*eqvdi3_internal1"
[(set (match_operand:DI 0 "gpc_reg_operand" "=r")
(not:DI (xor:DI (match_operand:DI 1 "gpc_reg_operand" "%r")
(match_operand:DI 2 "gpc_reg_operand" "r"))))]
"TARGET_POWERPC64"
"eqv %0,%1,%2")
-(define_insn ""
+(define_insn "*eqvdi3_internal2"
[(set (match_operand:CC 0 "cc_reg_operand" "=x")
(compare:CC (not:DI (xor:DI (match_operand:DI 1 "gpc_reg_operand" "%r")
(match_operand:DI 2 "gpc_reg_operand" "r")))
"eqv. %3,%1,%2"
[(set_attr "type" "compare")])
-(define_insn ""
+(define_insn "*eqvdi3_internal3"
[(set (match_operand:CC 3 "cc_reg_operand" "=x")
(compare:CC (not:DI (xor:DI (match_operand:DI 1 "gpc_reg_operand" "%r")
(match_operand:DI 2 "gpc_reg_operand" "r")))
"eqv. %0,%1,%2"
[(set_attr "type" "compare")])
-(define_insn ""
+(define_insn "*andcdi3_internal1"
[(set (match_operand:DI 0 "gpc_reg_operand" "=r")
(and:DI (not:DI (match_operand:DI 1 "gpc_reg_operand" "r"))
(match_operand:DI 2 "gpc_reg_operand" "r")))]
"TARGET_POWERPC64"
"andc %0,%2,%1")
-(define_insn ""
+(define_insn "*andcdi3_internal2"
[(set (match_operand:CC 0 "cc_reg_operand" "=x")
(compare:CC (and:DI (not:DI (match_operand:DI 1 "gpc_reg_operand" "r"))
(match_operand:DI 2 "gpc_reg_operand" "r"))
"andc. %3,%2,%1"
[(set_attr "type" "compare")])
-(define_insn ""
+(define_insn "*andcdi3_internal3"
[(set (match_operand:CC 3 "cc_reg_operand" "=x")
(compare:CC (and:DI (not:DI (match_operand:DI 1 "gpc_reg_operand" "r"))
(match_operand:DI 2 "gpc_reg_operand" "r"))
"andc. %0,%2,%1"
[(set_attr "type" "compare")])
-(define_insn ""
+(define_insn "*iorcdi3_internal1"
[(set (match_operand:DI 0 "gpc_reg_operand" "=r")
(ior:DI (not:DI (match_operand:DI 1 "gpc_reg_operand" "r"))
(match_operand:DI 2 "gpc_reg_operand" "r")))]
"TARGET_POWERPC64"
"orc %0,%2,%1")
-(define_insn ""
+(define_insn "*iorcdi3_inernal2"
[(set (match_operand:CC 0 "cc_reg_operand" "=x")
(compare:CC (ior:DI (not:DI (match_operand:DI 1 "gpc_reg_operand" "r"))
(match_operand:DI 2 "gpc_reg_operand" "r"))
"orc. %3,%2,%1"
[(set_attr "type" "compare")])
-(define_insn ""
+(define_insn "*iorcdi3_internal3"
[(set (match_operand:CC 3 "cc_reg_operand" "=x")
(compare:CC (ior:DI (not:DI (match_operand:DI 1 "gpc_reg_operand" "r"))
(match_operand:DI 2 "gpc_reg_operand" "r"))
"orc. %0,%2,%1"
[(set_attr "type" "compare")])
-(define_insn ""
+(define_insn "*nanddi3_internal1"
[(set (match_operand:DI 0 "gpc_reg_operand" "=r")
(ior:DI (not:DI (match_operand:DI 1 "gpc_reg_operand" "%r"))
(not:DI (match_operand:DI 2 "gpc_reg_operand" "r"))))]
"TARGET_POWERPC64"
"nand %0,%1,%2")
-(define_insn ""
+(define_insn "*nanddi3_internal2"
[(set (match_operand:CC 0 "cc_reg_operand" "=x")
(compare:CC (ior:DI (not:DI (match_operand:DI 1 "gpc_reg_operand" "%r"))
(not:DI (match_operand:DI 2 "gpc_reg_operand" "r")))
"nand. %3,%1,%2"
[(set_attr "type" "compare")])
-(define_insn ""
+(define_insn "*nanddi3_internal3"
[(set (match_operand:CC 3 "cc_reg_operand" "=x")
(compare:CC (ior:DI (not:DI (match_operand:DI 1 "gpc_reg_operand" "%r"))
(not:DI (match_operand:DI 2 "gpc_reg_operand" "r")))
"nand. %0,%1,%2"
[(set_attr "type" "compare")])
-(define_insn ""
+(define_insn "*nordi3_internal1"
[(set (match_operand:DI 0 "gpc_reg_operand" "=r")
(and:DI (not:DI (match_operand:DI 1 "gpc_reg_operand" "%r"))
(not:DI (match_operand:DI 2 "gpc_reg_operand" "r"))))]
"TARGET_POWERPC64"
"nor %0,%1,%2")
-(define_insn ""
+(define_insn "*nordi3_internal2"
[(set (match_operand:CC 0 "cc_reg_operand" "=x")
(compare:CC (and:DI (not:DI (match_operand:DI 1 "gpc_reg_operand" "%r"))
(not:DI (match_operand:DI 2 "gpc_reg_operand" "r")))
"nor. %3,%1,%2"
[(set_attr "type" "compare")])
-(define_insn ""
+(define_insn "*nordi3_internal3"
[(set (match_operand:CC 3 "cc_reg_operand" "=x")
(compare:CC (and:DI (not:DI (match_operand:DI 1 "gpc_reg_operand" "%r"))
(not:DI (match_operand:DI 2 "gpc_reg_operand" "r")))
}")
(define_insn ""
- [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,r,m,r,r,r,r,r,*q,*c*l,*h")
- (match_operand:SI 1 "input_operand" "r,S,T,U,m,r,I,J,n,R,*h,r,r,0"))]
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,m,r,r,r,r,r,*q,*c*l,*h")
+ (match_operand:SI 1 "input_operand" "r,U,m,r,I,J,n,R,*h,r,r,0"))]
"gpc_reg_operand (operands[0], SImode)
|| gpc_reg_operand (operands[1], SImode)"
"@
mr %0,%1
- {l|lwz} %0,[toc]%1(2)
- {l|lwz} %0,[toc]%l1(2)
{cal|la} %0,%a1
{l%U1%X1|lwz%U1%X1} %0,%1
{st%U0%X0|stw%U0%X0} %1,%0
mt%0 %1
mt%0 %1
cror 0,0,0"
- [(set_attr "type" "*,load,load,*,load,store,*,*,*,*,*,*,mtjmpr,*")
- (set_attr "length" "4,4,4,4,4,4,4,4,8,4,4,4,4,4")])
+ [(set_attr "type" "*,*,load,store,*,*,*,*,*,*,mtjmpr,*")
+ (set_attr "length" "4,4,4,4,4,4,8,4,4,4,4,4")])
;; Split a load of a large constant into the appropriate two-insn
;; sequence.
(define_split
[(set (match_operand:SF 0 "gpc_reg_operand" "")
(match_operand:SF 1 "const_double_operand" ""))]
- "TARGET_32BIT && reload_completed
+ "! TARGET_POWERPC64 && reload_completed
&& ((GET_CODE (operands[0]) == REG && REGNO (operands[0]) <= 31)
|| (GET_CODE (operands[0]) == SUBREG
&& GET_CODE (SUBREG_REG (operands[0])) == REG
operands[3] = GEN_INT(l);
}")
+(define_split
+ [(set (match_operand:SF 0 "gpc_reg_operand" "")
+ (match_operand:SF 1 "const_double_operand" ""))]
+ "TARGET_POWERPC64 && reload_completed
+ && ((GET_CODE (operands[0]) == REG && REGNO (operands[0]) <= 31)
+ || (GET_CODE (operands[0]) == SUBREG
+ && GET_CODE (SUBREG_REG (operands[0])) == REG
+ && REGNO (SUBREG_REG (operands[0])) <= 31))"
+ [(set (match_dup 2) (match_dup 3))]
+ "
+{
+ long l;
+ REAL_VALUE_TYPE rv;
+
+ REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
+ REAL_VALUE_TO_TARGET_SINGLE (rv, l);
+
+ operands[2] = gen_lowpart (SImode, operands[0]);
+ operands[3] = GEN_INT(l);
+}")
+
(define_insn "*movsf_hardfloat"
[(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,m,!r,!r")
(match_operand:SF 1 "input_operand" "f,m,f,G,Fn"))]
(define_split
[(set (match_operand:DF 0 "gpc_reg_operand" "")
(match_operand:DF 1 "const_int_operand" ""))]
- "TARGET_32BIT && reload_completed
+ "! TARGET_POWERPC64 && reload_completed
&& ((GET_CODE (operands[0]) == REG && REGNO (operands[0]) <= 31)
|| (GET_CODE (operands[0]) == SUBREG
&& GET_CODE (SUBREG_REG (operands[0])) == REG
(define_split
[(set (match_operand:DF 0 "gpc_reg_operand" "")
(match_operand:DF 1 "const_double_operand" ""))]
- "TARGET_32BIT && reload_completed
+ "! TARGET_POWERPC64 && reload_completed
&& ((GET_CODE (operands[0]) == REG && REGNO (operands[0]) <= 31)
|| (GET_CODE (operands[0]) == SUBREG
&& GET_CODE (SUBREG_REG (operands[0])) == REG
(define_split
[(set (match_operand:DF 0 "gpc_reg_operand" "")
(match_operand:DF 1 "easy_fp_constant" ""))]
- "TARGET_64BIT && reload_completed
+ "TARGET_POWERPC64 && reload_completed
&& ((GET_CODE (operands[0]) == REG && REGNO (operands[0]) <= 31)
|| (GET_CODE (operands[0]) == SUBREG
&& GET_CODE (SUBREG_REG (operands[0])) == REG
&& REGNO (SUBREG_REG (operands[0])) <= 31))"
- [(set (match_dup 2) (subreg:DI (match_dup 1) 0))]
+ [(set (match_dup 2) (match_dup 3))]
"
-{ operands[2] = gen_lowpart (DImode, operands[0]); }")
+{
+ int endian = (WORDS_BIG_ENDIAN == 0);
+ long l[2];
+ REAL_VALUE_TYPE rv;
+
+ REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
+ REAL_VALUE_TO_TARGET_DOUBLE (rv, l);
+
+ operands[2] = gen_lowpart (DImode, operands[0]);
+ /* HIGHPART is lower memory address when WORDS_BIG_ENDIAN. */
+ operands[3] = immed_double_const (l[1 - endian], l[endian], DImode);
+}")
;; Don't have reload use general registers to load a constant. First,
;; it might not work if the output operand has is the equivalent of
{
switch (which_alternative)
{
+ default:
+ abort();
case 0:
/* We normally copy the low-numbered register first. However, if
the first register operand 0 is the same as the second register of
{
switch (which_alternative)
{
+ default:
+ abort();
case 0:
/* We normally copy the low-numbered register first. However, if
the first register operand 0 is the same as the second register of
if (GET_CODE (operands[0]) != REG)
operands[1] = force_reg (DImode, operands[1]);
- if (TARGET_64BIT
- && (GET_CODE (operands[1]) == CONST_DOUBLE
- || GET_CODE (operands[1]) == CONST_INT))
- {
- HOST_WIDE_INT low;
- HOST_WIDE_INT high;
-
- if (GET_CODE (operands[1]) == CONST_DOUBLE)
- {
- low = CONST_DOUBLE_LOW (operands[1]);
- high = CONST_DOUBLE_HIGH (operands[1]);
- }
- else
+ /* Convert a move of a CONST_DOUBLE into a CONST_INT
+ only if sign-extended lower-half for 32-bit host. */
+ if (GET_CODE (operands[1]) == CONST_DOUBLE
#if HOST_BITS_PER_WIDE_INT == 32
- {
- low = INTVAL (operands[1]);
- high = (low < 0) ? ~0 : 0;
- }
-#else
- {
- low = INTVAL (operands[1]) & 0xffffffff;
- high = (HOST_WIDE_INT) INTVAL (operands[1]) >> 32;
- }
+ && ((CONST_DOUBLE_HIGH (operands[1]) == 0
+ && (CONST_DOUBLE_LOW (operands[1]) & 0x80000000) == 0)
+ || (CONST_DOUBLE_HIGH (operands[1]) == 0xffffffff
+ && (CONST_DOUBLE_LOW (operands[1]) & 0x80000000) != 0))
#endif
+ )
+ operands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
- if (high)
- {
- emit_move_insn (operands[0], GEN_INT (high));
- emit_insn (gen_ashldi3 (operands[0], operands[0], GEN_INT(32)));
- if (low)
- {
- HOST_WIDE_INT low_low = low & 0xffff;
- HOST_WIDE_INT low_high = low & (~ (HOST_WIDE_INT) 0xffff);
- if (low_high)
- emit_insn (gen_iordi3 (operands[0], operands[0],
- GEN_INT (low_high)));
- if (low_low)
- emit_insn (gen_iordi3 (operands[0], operands[0],
- GEN_INT (low_low)));
- }
- DONE;
- }
- }
+ if (TARGET_64BIT
+ && CONSTANT_P (operands[1])
+#if HOST_BITS_PER_WIDE_INT == 32
+ && GET_CODE (operands[1]) != CONST_INT
+#endif
+ && ! easy_fp_constant (operands[1], DImode)
+ && ! LEGITIMATE_CONSTANT_POOL_ADDRESS_P (operands[1]))
+ {
+ /* Emit a USE operation so that the constant isn't deleted if
+ expensive optimizations are turned on because nobody
+ references it. This should only be done for operands that
+ contain SYMBOL_REFs with CONSTANT_POOL_ADDRESS_P set.
+ This should not be done for operands that contain LABEL_REFs.
+ For now, we just handle the obvious case. */
+ if (GET_CODE (operands[1]) != LABEL_REF)
+ emit_insn (gen_rtx (USE, VOIDmode, operands[1]));
- /* Stores between FPR and any non-FPR registers must go through a
- temporary stack slot. */
+ /* If we are to limit the number of things we put in the TOC and
+ this is a symbol plus a constant we can add in one insn,
+ just put the symbol in the TOC and add the constant. Don't do
+ this if reload is in progress. */
+ if (GET_CODE (operands[1]) == CONST
+ && TARGET_NO_SUM_IN_TOC && ! reload_in_progress
+ && GET_CODE (XEXP (operands[1], 0)) == PLUS
+ && add_operand (XEXP (XEXP (operands[1], 0), 1), DImode)
+ && (GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == LABEL_REF
+ || GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == SYMBOL_REF)
+ && ! side_effects_p (operands[0]))
+ {
+ rtx sym = force_const_mem (DImode, XEXP (XEXP (operands[1], 0), 0));
+ rtx other = XEXP (XEXP (operands[1], 0), 1);
- if (GET_CODE (operands[0]) == REG && GET_CODE (operands[1]) == REG
- && ((FP_REGNO_P (REGNO (operands[0]))
- && ! FP_REGNO_P (REGNO (operands[1])))
- || (FP_REGNO_P (REGNO (operands[1]))
- && ! FP_REGNO_P (REGNO (operands[0])))))
- {
- rtx stack_slot = assign_stack_temp (DImode, 8, 0);
+ emit_insn (gen_adddi3 (operands[0], force_reg (DImode, sym), other));
+ DONE;
+ }
- emit_move_insn (stack_slot, operands[1]);
- emit_move_insn (operands[0], stack_slot);
- DONE;
+ operands[1] = force_const_mem (DImode, operands[1]);
+ if (! memory_address_p (DImode, XEXP (operands[1], 0))
+ && ! reload_in_progress)
+ operands[1] = change_address (operands[1], DImode,
+ XEXP (operands[1], 0));
}
}")
(define_insn "*movdi_32"
[(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m,f,f,m,r,r,r,r,r")
(match_operand:DI 1 "input_operand" "r,m,r,f,m,f,IJK,n,G,H,F"))]
- "TARGET_32BIT
+ "! TARGET_POWERPC64
&& (gpc_reg_operand (operands[0], DImode)
|| gpc_reg_operand (operands[1], DImode))"
"*
{
switch (which_alternative)
{
+ default:
+ abort();
case 0:
/* We normally copy the low-numbered register first. However, if
the first register operand 0 is the same as the second register of
(define_split
[(set (match_operand:DI 0 "gpc_reg_operand" "")
(match_operand:DI 1 "const_int_operand" ""))]
- "TARGET_32BIT && reload_completed"
+ "! TARGET_POWERPC64 && reload_completed"
[(set (match_dup 2) (match_dup 4))
(set (match_dup 3) (match_dup 1))]
"
(define_split
[(set (match_operand:DI 0 "gpc_reg_operand" "")
(match_operand:DI 1 "const_double_operand" ""))]
- "TARGET_32BIT && reload_completed"
+ "! TARGET_POWERPC64 && reload_completed"
[(set (match_dup 2) (match_dup 4))
(set (match_dup 3) (match_dup 5))]
"
(define_insn "*movdi_64"
[(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m,r,r,r,r,f,f,m,r,*h,*h")
(match_operand:DI 1 "input_operand" "r,m,r,I,J,nF,R,f,m,f,*h,r,0"))]
- "TARGET_64BIT
+ "TARGET_POWERPC64
&& (gpc_reg_operand (operands[0], DImode)
|| gpc_reg_operand (operands[1], DImode))"
"@
[(set_attr "type" "*,load,store,*,*,*,*,fp,fpload,fpstore,*,mtjmpr,*")
(set_attr "length" "4,4,4,4,4,20,4,4,4,4,4,4,4")])
-;; Split a load of a large constant into the appropriate five-instruction
-;; sequence. The expansion in movdi tries to perform the minimum number of
-;; steps, but here we have to handle anything in a constant number of insns.
+(define_insn ""
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (match_operand:DI 1 "const_double_operand" "F"))]
+ "TARGET_POWERPC64 && GET_CODE (operands[1]) == CONST_DOUBLE
+ && num_insns_constant (operands[1], DImode) == 1"
+ "*
+{
+ return ((unsigned HOST_WIDE_INT)
+ (CONST_DOUBLE_LOW (operands[1]) + 0x8000) < 0x10000)
+ ? \"li %0,%1\" : \"lis %0,%v1\";
+}")
+
+(define_split
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (match_operand:DI 1 "const_int_operand" ""))]
+ "HOST_BITS_PER_WIDE_INT == 32 && TARGET_POWERPC64
+ && num_insns_constant (operands[1], DImode) > 1"
+ [(set (match_dup 0)
+ (match_dup 2))
+ (set (match_dup 0)
+ (ior:DI (match_dup 0)
+ (match_dup 3)))]
+ "
+{
+ operands[2] = GEN_INT (INTVAL (operands[1]) & 0xffff0000);
+ operands[3] = GEN_INT (INTVAL (operands[1]) & 0xffff);
+}")
(define_split
[(set (match_operand:DI 0 "gpc_reg_operand" "")
(match_operand:DI 1 "const_double_operand" ""))]
- "TARGET_64BIT && num_insns_constant (operands[1], DImode) > 1"
+ "HOST_BITS_PER_WIDE_INT == 32 && TARGET_POWERPC64
+ && GET_CODE (operands[1]) == CONST_DOUBLE
+ && ((CONST_DOUBLE_HIGH (operands[1]) == 0
+ && (CONST_DOUBLE_LOW (operands[1]) & 0x80000000) == 0)
+ || (CONST_DOUBLE_HIGH (operands[1]) == 0xffffffff
+ && (CONST_DOUBLE_LOW (operands[1]) & 0x80000000) != 0))"
[(set (match_dup 0)
(match_dup 2))
(set (match_dup 0)
(ior:DI (match_dup 0)
- (match_dup 3)))
+ (match_dup 3)))]
+ "
+{
+ operands[2] = GEN_INT (CONST_DOUBLE_LOW (operands[1]) & 0xffff0000);
+ operands[3] = GEN_INT (CONST_DOUBLE_LOW (operands[1]) & 0xffff);
+}")
+
+(define_split
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (match_operand:DI 1 "const_double_operand" ""))]
+ "HOST_BITS_PER_WIDE_INT == 32 && TARGET_POWERPC64
+ && GET_CODE (operands[1]) == CONST_DOUBLE
+ && CONST_DOUBLE_HIGH (operands[1]) == 0
+ && (CONST_DOUBLE_LOW (operands[1]) & 0x80000000) != 0"
+ [(set (match_dup 0)
+ (match_dup 2))
+ (set (match_dup 0)
+ (zero_extend:DI (subreg:SI (match_dup 0) 0)))]
+ "
+{ operands[2] = GEN_INT (CONST_DOUBLE_LOW (operands[1])); }")
+
+(define_split
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (match_operand:DI 1 "const_double_operand" ""))]
+ "HOST_BITS_PER_WIDE_INT == 32 && TARGET_POWERPC64
+ && GET_CODE (operands[1]) == CONST_DOUBLE
+ && CONST_DOUBLE_LOW (operands[1]) == 0"
+ [(set (match_dup 0)
+ (match_dup 2))
(set (match_dup 0)
(ashift:DI (match_dup 0)
- (const_int 32)))
+ (const_int 32)))]
+ "
+{ operands[2] = GEN_INT (CONST_DOUBLE_HIGH (operands[1])); }")
+
+;; Generate all one-bits and clear left or right.
+;; Use (and:DI (rotate:DI ...)) to avoid anddi3 unnecessary clobber.
+(define_split
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (match_operand:DI 1 "mask64_operand" ""))]
+ "TARGET_POWERPC64 && num_insns_constant (operands[1], DImode) > 1"
+ [(set (match_dup 0) (const_int -1))
(set (match_dup 0)
- (ior:DI (match_dup 0)
- (match_dup 4)))
+ (and:DI (rotate:DI (match_dup 0)
+ (const_int 0))
+ (match_dup 1)))]
+ "")
+
+;; Split a load of a large constant into the appropriate five-instruction
+;; sequence. Handle anything in a constant number of insns.
+;; When non-easy constants can go in the TOC, this should use
+;; easy_fp_constant predicate.
+(define_split
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (match_operand:DI 1 "const_double_operand" ""))]
+ "TARGET_POWERPC64 && num_insns_constant (operands[1], DImode) > 1"
+ [(set (match_dup 0)
+ (match_dup 2))
+ (set (match_dup 0)
+ (ashift:DI (match_dup 0)
+ (const_int 32)))
(set (match_dup 0)
(ior:DI (match_dup 0)
- (match_dup 5)))]
+ (match_dup 3)))]
"
{
HOST_WIDE_INT low;
}
#endif
- if ((high + 0x8000) < 0x10000
- && ((low & 0xffff) == 0 || (low & (~ (HOST_WIDE_INT) 0xffff)) == 0))
- FAIL;
-
- operands[2] = GEN_INT (high & (~ (HOST_WIDE_INT) 0xffff));
- operands[3] = GEN_INT (high & 0xffff);
- operands[4] = GEN_INT (low & (~ (HOST_WIDE_INT) 0xffff));
- operands[5] = GEN_INT (low & 0xffff);
+ operands[2] = GEN_INT (high);
+ operands[3] = GEN_INT (low);
}")
(define_insn ""
;; while the 2nd alternative would not. We put memory cases first so they
;; are preferred. Otherwise, we'd try to reload the output instead of
;; giving the SCRATCH mq.
-(define_insn ""
+(define_insn "*movti_power"
[(set (match_operand:TI 0 "reg_or_mem_operand" "=Q,m,????r,????r,????r")
(match_operand:TI 1 "reg_or_mem_operand" "r,r,r,Q,m"))
(clobber (match_scratch:SI 2 "=q,q#X,X,X,X"))]
[(set_attr "type" "store,store,*,load,load")
(set_attr "length" "*,16,16,*,16")])
-(define_insn ""
+(define_insn "*movti_string"
[(set (match_operand:TI 0 "reg_or_mem_operand" "=m,????r,????r")
(match_operand:TI 1 "reg_or_mem_operand" "r,r,m"))
(clobber (match_scratch:SI 2 "=X,X,X"))]
[(set_attr "type" "store,*,load")
(set_attr "length" "16,16,16")])
-(define_insn ""
+(define_insn "*movti_ppc64"
[(set (match_operand:TI 0 "nonimmediate_operand" "=r,r,m")
(match_operand:TI 1 "input_operand" "r,m,r"))]
"TARGET_POWERPC64 && (gpc_reg_operand (operands[0], TImode)
{
switch (which_alternative)
{
+ default:
+ abort();
case 0:
/* We normally copy the low-numbered register first. However, if
the first register operand 0 is the same as the second register of
;; We move the back-chain and decrement the stack pointer.
(define_expand "allocate_stack"
- [(set (match_operand:SI 0 "register_operand" "=r")
- (minus:SI (reg:SI 1) (match_operand:SI 1 "reg_or_short_operand" "")))
- (set (reg:SI 1)
- (minus:SI (reg:SI 1) (match_dup 1)))]
+ [(set (match_operand 0 "register_operand" "=r")
+ (minus (reg 1) (match_operand 1 "reg_or_short_operand" "")))
+ (set (reg 1)
+ (minus (reg 1) (match_dup 1)))]
""
"
{ rtx chain = gen_reg_rtx (Pmode);
if (DEFAULT_ABI == ABI_NT
&& (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) > 4096))
{
- rtx tmp = gen_reg_rtx (SImode);
+ rtx tmp = gen_reg_rtx (Pmode);
emit_library_call_value (gen_rtx (SYMBOL_REF, Pmode, \"__allocate_stack\"),
- tmp, 0, SImode, 1, operands[1], Pmode);
+ tmp, 0, Pmode, 1, operands[1], Pmode);
emit_insn (gen_set_sp (tmp));
emit_move_insn (operands[0], tmp);
DONE;
{
emit_insn ((* ((TARGET_32BIT) ? gen_addsi3 : gen_adddi3))
(stack_pointer_rtx, stack_pointer_rtx, neg_op0));
- emit_move_insn (gen_rtx (MEM, (TARGET_32BIT) ? SImode : DImode,
- stack_pointer_rtx),
- chain);
+ emit_move_insn (gen_rtx (MEM, Pmode, stack_pointer_rtx), chain);
}
emit_move_insn (operands[0], virtual_stack_dynamic_rtx);
"")
(define_expand "restore_stack_block"
- [(set (match_dup 2) (mem:SI (match_operand:SI 0 "register_operand" "")))
- (set (match_dup 0) (match_operand:SI 1 "register_operand" ""))
- (set (mem:SI (match_dup 0)) (match_dup 2))]
+ [(set (match_dup 2) (mem (match_operand 0 "register_operand" "")))
+ (set (match_dup 0) (match_operand 1 "register_operand" ""))
+ (set (mem (match_dup 0)) (match_dup 2))]
""
"
-{ operands[2] = gen_reg_rtx (SImode); }")
+{ operands[2] = gen_reg_rtx (Pmode); }")
(define_expand "save_stack_nonlocal"
- [(match_operand:DI 0 "memory_operand" "")
- (match_operand:SI 1 "register_operand" "")]
+ [(match_operand 0 "memory_operand" "")
+ (match_operand 1 "register_operand" "")]
""
"
{
- rtx temp = gen_reg_rtx (SImode);
+ rtx temp = gen_reg_rtx (Pmode);
/* Copy the backchain to the first word, sp to the second. */
- emit_move_insn (temp, gen_rtx (MEM, SImode, operands[1]));
- emit_move_insn (operand_subword (operands[0], 0, 0, DImode), temp);
- emit_move_insn (operand_subword (operands[0], 1, 0, DImode), operands[1]);
+ emit_move_insn (temp, gen_rtx (MEM, Pmode, operands[1]));
+ emit_move_insn (operand_subword (operands[0], 0, 0, (TARGET_32BIT ? DImode : TImode)),
+ temp);
+ emit_move_insn (operand_subword (operands[0], 1, 0, (TARGET_32BIT ? DImode : TImode)),
+ operands[1]);
DONE;
}")
(define_expand "restore_stack_nonlocal"
- [(match_operand:SI 0 "register_operand" "")
- (match_operand:DI 1 "memory_operand" "")]
+ [(match_operand 0 "register_operand" "")
+ (match_operand 1 "memory_operand" "")]
""
"
{
- rtx temp = gen_reg_rtx (SImode);
+ rtx temp = gen_reg_rtx (Pmode);
/* Restore the backchain from the first word, sp from the second. */
- emit_move_insn (temp, operand_subword (operands[1], 0, 0, DImode));
- emit_move_insn (operands[0], operand_subword (operands[1], 1, 0, DImode));
- emit_move_insn (gen_rtx (MEM, SImode, operands[0]), temp);
+ emit_move_insn (temp,
+ operand_subword (operands[1], 0, 0, (TARGET_32BIT ? DImode : TImode)));
+ emit_move_insn (operands[0],
+ operand_subword (operands[1], 1, 0, (TARGET_32BIT ? DImode : TImode)));
+ emit_move_insn (gen_rtx (MEM, Pmode, operands[0]), temp);
DONE;
}")
;; We do not break this into separate insns, so that the scheduler will not try
;; to move the load of the new TOC before any loads from the TOC.
-(define_insn "call_indirect_aix"
+(define_insn "call_indirect_aix32"
[(call (mem:SI (match_operand:SI 0 "register_operand" "b"))
(match_operand 1 "const_int_operand" "n"))
(use (match_operand 2 "const_int_operand" "n"))
[(set_attr "type" "load")
(set_attr "length" "28")])
-(define_insn "call_value_indirect_aix"
+(define_insn "call_indirect_aix64"
+ [(call (mem:SI (match_operand:DI 0 "register_operand" "b"))
+ (match_operand 1 "const_int_operand" "n"))
+ (use (match_operand 2 "const_int_operand" "n"))
+ (use (match_operand 3 "offsettable_addr_operand" "p"))
+ (use (match_operand 4 "register_operand" "r"))
+ (clobber (match_operand 5 "register_operand" "=r"))
+ (clobber (match_scratch:SI 6 "=&r"))
+ (clobber (match_scratch:SI 7 "=l"))]
+ "TARGET_64BIT && DEFAULT_ABI == ABI_AIX
+ && (INTVAL (operands[2]) == CALL_NORMAL || (INTVAL (operands[2]) & CALL_LONG) != 0)"
+ "stw %4,%a3\;ld %6,0(%0)\;ld %4,8(%0)\;mt%7 %6\;ld %5,16(%0)\;blrl\;ld %4,%a3"
+ [(set_attr "type" "load")
+ (set_attr "length" "28")])
+
+(define_insn "call_value_indirect_aix32"
[(set (match_operand 0 "register_operand" "fg")
(call (mem:SI (match_operand:SI 1 "register_operand" "b"))
(match_operand 2 "const_int_operand" "n")))
(clobber (match_scratch:SI 8 "=l"))]
"DEFAULT_ABI == ABI_AIX
&& (INTVAL (operands[3]) == CALL_NORMAL || (INTVAL (operands[3]) & CALL_LONG) != 0)"
- "{st|stw} %5,%a4\;{l|lwz} %7,0(%1)\;{l|lwz} %5,4(%1);\;mt%8 %7\;{l|lwz} %6,8(%1)\;{brl|blrl}\;{l|lwz} %5,%a4"
+ "{st|stw} %5,%a4\;{l|lwz} %7,0(%1)\;{l|lwz} %5,4(%1)\;mt%8 %7\;{l|lwz} %6,8(%1)\;{brl|blrl}\;{l|lwz} %5,%a4"
+ [(set_attr "type" "load")
+ (set_attr "length" "28")])
+
+(define_insn "call_value_indirect_aix64"
+ [(set (match_operand 0 "register_operand" "fg")
+ (call (mem:SI (match_operand:DI 1 "register_operand" "b"))
+ (match_operand 2 "const_int_operand" "n")))
+ (use (match_operand 3 "const_int_operand" "n"))
+ (use (match_operand 4 "offsettable_addr_operand" "p"))
+ (use (match_operand 5 "register_operand" "r"))
+ (clobber (match_operand 6 "register_operand" "=r"))
+ (clobber (match_scratch:SI 7 "=&r"))
+ (clobber (match_scratch:SI 8 "=l"))]
+ "TARGET_64BIT && DEFAULT_ABI == ABI_AIX
+ && (INTVAL (operands[3]) == CALL_NORMAL || (INTVAL (operands[3]) & CALL_LONG) != 0)"
+ "stw %5,%a4\;ld %7,0(%1)\;ld %5,8(%1)\;mt%8 %7\;ld %6,16(%1)\;blrl\;ld %5,%a4"
[(set_attr "type" "load")
(set_attr "length" "28")])
;; Now the definitions for the call and call_value insns
(define_expand "call"
- [(parallel [(call (mem:SI (match_operand:SI 0 "address_operand" ""))
+ [(parallel [(call (mem:SI (match_operand 0 "address_operand" ""))
(match_operand 1 "" ""))
(use (match_operand 2 "" ""))
(clobber (scratch:SI))])]
{
/* AIX function pointers are really pointers to a three word area */
rtx static_chain = gen_rtx (REG, Pmode, STATIC_CHAIN_REGNUM);
- emit_call_insn (gen_call_indirect_aix (force_reg (Pmode, operands[0]),
- operands[1], operands[2],
- toc_addr, toc_reg, static_chain));
+ emit_call_insn (TARGET_32BIT
+ ? gen_call_indirect_aix32 (force_reg (Pmode, operands[0]),
+ operands[1], operands[2],
+ toc_addr, toc_reg, static_chain)
+ : gen_call_indirect_aix64 (force_reg (Pmode, operands[0]),
+ operands[1], operands[2],
+ toc_addr, toc_reg, static_chain));
}
else if (DEFAULT_ABI == ABI_NT)
{
(define_expand "call_value"
[(parallel [(set (match_operand 0 "" "")
- (call (mem:SI (match_operand:SI 1 "address_operand" ""))
+ (call (mem:SI (match_operand 1 "address_operand" ""))
(match_operand 2 "" "")))
(use (match_operand 3 "" ""))
(clobber (scratch:SI))])]
{
/* AIX function pointers are really pointers to a three word area */
rtx static_chain = gen_rtx (REG, Pmode, STATIC_CHAIN_REGNUM);
- emit_call_insn (gen_call_value_indirect_aix (operands[0],
- force_reg (Pmode, operands[1]),
- operands[2], operands[3],
- toc_addr, toc_reg, static_chain));
+ emit_call_insn (TARGET_32BIT
+ ? gen_call_value_indirect_aix32 (operands[0],
+ force_reg (Pmode, operands[1]),
+ operands[2], operands[3],
+ toc_addr, toc_reg, static_chain)
+ : gen_call_value_indirect_aix64 (operands[0],
+ force_reg (Pmode, operands[1]),
+ operands[2], operands[3],
+ toc_addr, toc_reg, static_chain));
}
else if (DEFAULT_ABI == ABI_NT)
{
;; variable argument function. It is > 0 if FP registers were passed
;; and < 0 if they were not.
-(define_insn ""
+(define_insn "*call_local32"
[(call (mem:SI (match_operand:SI 0 "current_file_function_operand" "s,s"))
(match_operand 1 "" "g,g"))
(use (match_operand:SI 2 "immediate_operand" "O,n"))
[(set_attr "type" "branch")
(set_attr "length" "4,8")])
+(define_insn "*call_local64"
+ [(call (mem:SI (match_operand:DI 0 "current_file_function_operand" "s,s"))
+ (match_operand 1 "" "g,g"))
+ (use (match_operand:SI 2 "immediate_operand" "O,n"))
+ (clobber (match_scratch:SI 3 "=l,l"))]
+ "TARGET_64BIT && (INTVAL (operands[2]) & CALL_LONG) == 0"
+ "*
+{
+ if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS)
+ output_asm_insn (\"crxor 6,6,6\", operands);
+
+ else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
+ output_asm_insn (\"creqv 6,6,6\", operands);
+
+ return (DEFAULT_ABI == ABI_V4 && flag_pic) ? \"bl %z0@local\" : \"bl %z0\";
+}"
+ [(set_attr "type" "branch")
+ (set_attr "length" "4,8")])
+
+(define_insn "*ret_call_local32"
+ [(set (match_operand 0 "" "=fg,fg")
+ (call (mem:SI (match_operand:SI 1 "current_file_function_operand" "s,s"))
+ (match_operand 2 "" "g,g")))
+ (use (match_operand:SI 3 "immediate_operand" "O,n"))
+ (clobber (match_scratch:SI 4 "=l,l"))]
+ "(INTVAL (operands[3]) & CALL_LONG) == 0"
+ "*
+{
+ if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS)
+ output_asm_insn (\"crxor 6,6,6\", operands);
+
+ else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
+ output_asm_insn (\"creqv 6,6,6\", operands);
+
+ return (DEFAULT_ABI == ABI_V4 && flag_pic) ? \"bl %z1@local\" : \"bl %z1\";
+}"
+ [(set_attr "type" "branch")
+ (set_attr "length" "4,8")])
+
+
+(define_insn "*ret_call_local64"
+ [(set (match_operand 0 "" "=fg,fg")
+ (call (mem:SI (match_operand:DI 1 "current_file_function_operand" "s,s"))
+ (match_operand 2 "" "g,g")))
+ (use (match_operand:SI 3 "immediate_operand" "O,n"))
+ (clobber (match_scratch:SI 4 "=l,l"))]
+ "TARGET_64BIT && (INTVAL (operands[3]) & CALL_LONG) == 0"
+ "*
+{
+ if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS)
+ output_asm_insn (\"crxor 6,6,6\", operands);
+
+ else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
+ output_asm_insn (\"creqv 6,6,6\", operands);
+
+ return (DEFAULT_ABI == ABI_V4 && flag_pic) ? \"bl %z1@local\" : \"bl %z1\";
+}"
+ [(set_attr "type" "branch")
+ (set_attr "length" "4,8")])
+
;; Call to function which may be in another module. Restore the TOC
;; pointer (r2) after the call unless this is System V.
;; Operand2 is non-zero if we are using the V.4 calling sequence and
;; variable argument function. It is > 0 if FP registers were passed
;; and < 0 if they were not.
-(define_insn ""
+(define_insn "*call_nonlocal_aix32"
[(call (mem:SI (match_operand:SI 0 "call_operand" "s,s"))
(match_operand 1 "" "fg,fg"))
(use (match_operand:SI 2 "immediate_operand" "O,n"))
[(set_attr "type" "branch")
(set_attr "length" "8,12")])
-(define_insn ""
+(define_insn "*call_nonlocal_aix64"
+ [(call (mem:SI (match_operand:DI 0 "call_operand" "s,s"))
+ (match_operand 1 "" "fg,fg"))
+ (use (match_operand:SI 2 "immediate_operand" "O,n"))
+ (clobber (match_scratch:SI 3 "=l,l"))]
+ "TARGET_64BIT && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_NT)
+ && (INTVAL (operands[2]) & CALL_LONG) == 0"
+ "*
+{
+ /* Indirect calls should go through call_indirect */
+ if (GET_CODE (operands[0]) == REG)
+ abort ();
+
+ if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS)
+ output_asm_insn (\"crxor 6,6,6\", operands);
+
+ else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
+ output_asm_insn (\"creqv 6,6,6\", operands);
+
+ return (TARGET_WINDOWS_NT) ? \"bl %z0\;.znop %z0\" : \"bl %z0\;%.\";
+}"
+ [(set_attr "type" "branch")
+ (set_attr "length" "8,12")])
+
+(define_insn "*call_nonlocal_sysv"
[(call (mem:SI (match_operand:SI 0 "call_operand" "s,s"))
(match_operand 1 "" "fg,fg"))
(use (match_operand:SI 2 "immediate_operand" "O,n"))
[(set_attr "type" "branch")
(set_attr "length" "4,8")])
-(define_insn ""
+(define_insn "*ret_call_nonlocal_aix32"
[(set (match_operand 0 "" "=fg,fg")
- (call (mem:SI (match_operand:SI 1 "current_file_function_operand" "s,s"))
- (match_operand 2 "" "g,g")))
+ (call (mem:SI (match_operand:SI 1 "call_operand" "s,s"))
+ (match_operand 2 "" "fg,fg")))
(use (match_operand:SI 3 "immediate_operand" "O,n"))
(clobber (match_scratch:SI 4 "=l,l"))]
- "(INTVAL (operands[3]) & CALL_LONG) == 0"
+ "(DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_NT)
+ && (INTVAL (operands[3]) & CALL_LONG) == 0"
"*
{
+ /* This should be handled by call_value_indirect */
+ if (GET_CODE (operands[1]) == REG)
+ abort ();
+
if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS)
output_asm_insn (\"crxor 6,6,6\", operands);
else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
output_asm_insn (\"creqv 6,6,6\", operands);
- return (DEFAULT_ABI == ABI_V4 && flag_pic) ? \"bl %z1@local\" : \"bl %z1\";
+ return (TARGET_WINDOWS_NT) ? \"bl %z1\;.znop %z1\" : \"bl %z1\;%.\";
}"
[(set_attr "type" "branch")
- (set_attr "length" "4,8")])
+ (set_attr "length" "8,12")])
-(define_insn ""
+(define_insn "*ret_call_nonlocal_aix64"
[(set (match_operand 0 "" "=fg,fg")
- (call (mem:SI (match_operand:SI 1 "call_operand" "s,s"))
+ (call (mem:SI (match_operand:DI 1 "call_operand" "s,s"))
(match_operand 2 "" "fg,fg")))
(use (match_operand:SI 3 "immediate_operand" "O,n"))
(clobber (match_scratch:SI 4 "=l,l"))]
- "(DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_NT)
+ "TARGET_64BIT && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_NT)
&& (INTVAL (operands[3]) & CALL_LONG) == 0"
"*
{
[(set_attr "type" "branch")
(set_attr "length" "8,12")])
-(define_insn ""
+(define_insn "*ret_call_nonlocal_sysv"
[(set (match_operand 0 "" "=fg,fg")
(call (mem:SI (match_operand:SI 1 "call_operand" "s,s"))
(match_operand 2 "" "fg,fg")))
{sfi|subfic} %0,%1,%2\;{sfi|subfic} %3,%0,0\;{ae|adde} %0,%3,%0"
[(set_attr "length" "12,8,12,12,12")])
+(define_insn ""
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r,r,r")
+ (eq:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r,r,r,r")
+ (match_operand:DI 2 "reg_or_cint_operand" "r,O,K,J,I")))
+ (clobber (match_scratch:DI 3 "=r,&r,r,r,r"))]
+ "TARGET_POWERPC64"
+ "@
+ xor %0,%1,%2\;subfic %3,%0,0\;adde %0,%3,%0
+ subfic %3,%1,0\;adde %0,%3,%1
+ xori %0,%1,%b2\;subfic %3,%0,0\;adde %0,%3,%0
+ xoris %0,%1,%u2\;subfic %3,%0,0\;adde %0,%3,%0
+ subfic %0,%1,%2\;subfic %3,%0,0\;adde %0,%3,%0"
+ [(set_attr "length" "12,8,12,12,12")])
+
(define_insn ""
[(set (match_operand:CC 4 "cc_reg_operand" "=x,x,x,x,x")
(compare:CC
[(set_attr "type" "compare")
(set_attr "length" "12,8,12,12,12")])
+(define_insn ""
+ [(set (match_operand:CC 4 "cc_reg_operand" "=x,x,x,x,x")
+ (compare:CC
+ (eq:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r,r,r,r")
+ (match_operand:DI 2 "reg_or_cint_operand" "r,O,K,J,I"))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r,r,r")
+ (eq:DI (match_dup 1) (match_dup 2)))
+ (clobber (match_scratch:DI 3 "=r,&r,r,r,r"))]
+ "TARGET_POWERPC64"
+ "@
+ xor %0,%1,%2\;subfic %3,%0,0\;adde. %0,%3,%0
+ subfic %3,%1,0\;adde. %0,%3,%1
+ xori %0,%1,%b2\;subfic %3,%0,0\;adde. %0,%3,%0
+ xoris %0,%1,%u2\;subfic %3,%0,0\;adde. %0,%3,%0
+ subfic %0,%1,%2\;subfic %3,%0,0\;adde. %0,%3,%0"
+ [(set_attr "type" "compare")
+ (set_attr "length" "12,8,12,12,12")])
+
;; We have insns of the form shown by the first define_insn below. If
;; there is something inside the comparison operation, we must split it.
(define_split
"{ai|addic} %2,%1,-1\;{sfe|subfe} %0,%2,%1"
[(set_attr "length" "8")])
+(define_insn ""
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (lshiftrt:DI (neg:DI (abs:DI (match_operand:DI 1 "gpc_reg_operand" "r")))
+ (const_int 63)))
+ (clobber (match_scratch:DI 2 "=&r"))]
+ "TARGET_POWERPC64"
+ "addic %2,%1,-1\;subfe %0,%2,%1"
+ [(set_attr "length" "8")])
+
;; This is what (plus (ne X (const_int 0)) Y) looks like.
(define_insn ""
[(set (match_operand:SI 0 "gpc_reg_operand" "=r")
"{ai|addic} %3,%1,-1\;{aze|addze} %0,%2"
[(set_attr "length" "8")])
+(define_insn ""
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (plus:DI (lshiftrt:DI
+ (neg:DI (abs:DI (match_operand:DI 1 "gpc_reg_operand" "r")))
+ (const_int 63))
+ (match_operand:DI 2 "gpc_reg_operand" "r")))
+ (clobber (match_scratch:DI 3 "=&r"))]
+ "TARGET_POWERPC64"
+ "addic %3,%1,-1\;addze %0,%2"
+ [(set_attr "length" "8")])
+
(define_insn ""
[(set (match_operand:CC 0 "cc_reg_operand" "=x")
(compare:CC
[(set_attr "type" "compare")
(set_attr "length" "8")])
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x")
+ (compare:CC
+ (plus:DI (lshiftrt:DI
+ (neg:DI (abs:DI (match_operand:DI 1 "gpc_reg_operand" "r")))
+ (const_int 63))
+ (match_operand:DI 2 "gpc_reg_operand" "r"))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 "=&r"))]
+ "TARGET_POWERPC64"
+ "addic %3,%1,-1\;addze. %3,%2"
+ [(set_attr "type" "compare")
+ (set_attr "length" "8")])
+
(define_insn ""
[(set (match_operand:CC 4 "cc_reg_operand" "=x")
(compare:CC
[(set_attr "type" "compare")
(set_attr "length" "8")])
+(define_insn ""
+ [(set (match_operand:CC 4 "cc_reg_operand" "=x")
+ (compare:CC
+ (plus:DI (lshiftrt:DI
+ (neg:DI (abs:DI (match_operand:DI 1 "gpc_reg_operand" "r")))
+ (const_int 63))
+ (match_operand:DI 2 "gpc_reg_operand" "r"))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (plus:DI (lshiftrt:DI (neg:DI (abs:DI (match_dup 1))) (const_int 63))
+ (match_dup 2)))
+ (clobber (match_scratch:DI 3 "=&r"))]
+ "TARGET_POWERPC64"
+ "addic %3,%1,-1\;addze. %0,%2"
+ [(set_attr "type" "compare")
+ (set_attr "length" "8")])
+
(define_insn ""
[(set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
(le:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")