Commit 3933e0e1 by Michael Meissner

Add -mno-toc; Support block moves if -mno-string.

From-SVN: r9763
parent 15c8ec1c
...@@ -202,6 +202,10 @@ rs6000_override_options () ...@@ -202,6 +202,10 @@ rs6000_override_options ()
warning ("-mstring is not supported on little endian systems"); warning ("-mstring is not supported on little endian systems");
} }
} }
#ifdef SUBTARGET_OVERRIDE_OPTIONS
SUBTARGET_OVERRIDE_OPTIONS;
#endif
} }
/* Create a CONST_DOUBLE like immed_double_const, except reverse the /* Create a CONST_DOUBLE like immed_double_const, except reverse the
...@@ -641,127 +645,204 @@ input_operand (op, mode) ...@@ -641,127 +645,204 @@ input_operand (op, mode)
operands[2] is the length operands[2] is the length
operands[3] is the alignment */ operands[3] is the alignment */
#define MAX_MOVE_REG 4
int int
expand_block_move (operands) expand_block_move (operands)
rtx operands[]; rtx operands[];
{ {
rtx bytes_rtx = operands[2]; rtx bytes_rtx = operands[2];
int constp = (GET_CODE (bytes_rtx) == CONST_INT);
int bytes = (constp ? INTVAL (bytes_rtx) : 0);
rtx align_rtx = operands[3]; rtx align_rtx = operands[3];
int constp = (GET_CODE (bytes_rtx) == CONST_INT);
int align = XINT (align_rtx, 0); int align = XINT (align_rtx, 0);
int bytes;
int offset;
int num_reg;
int i;
rtx src_reg; rtx src_reg;
rtx dest_reg; rtx dest_reg;
rtx src_addr;
rtx dest_addr;
rtx tmp_reg; rtx tmp_reg;
rtx stores[MAX_MOVE_REG];
int move_bytes; int move_bytes;
/* If this is not a fixed size move, just call memcpy */
if (!constp)
return 0;
/* Anything to move? */ /* Anything to move? */
if (constp && bytes <= 0) bytes = INTVAL (bytes_rtx);
if (bytes <= 0)
return 1; return 1;
/* If we don't want to use multiple string instructions, quit now and /* Don't support real large moves. If string instructions are not used,
generate the normal code. */ then don't generate more than 8 loads. */
if (!TARGET_STRING) if (TARGET_STRING)
return 0; {
if (bytes > 64)
/* We don't support variable sized moves at this time or real large moves */ return 0;
if (!constp || bytes > 64) }
else if (!STRICT_ALIGNMENT)
{
if (bytes > 4*8)
return 0;
}
else if (bytes > 8*align)
return 0; return 0;
/* Move the address into scratch registers. */ /* Move the address into scratch registers. */
dest_reg = copy_addr_to_reg (XEXP (operands[0], 0)); dest_reg = copy_addr_to_reg (XEXP (operands[0], 0));
src_reg = copy_addr_to_reg (XEXP (operands[1], 0)); src_reg = copy_addr_to_reg (XEXP (operands[1], 0));
for ( ; bytes > 0; bytes -= move_bytes) if (TARGET_STRING) /* string instructions are available */
{ {
if (bytes > 24 /* move up to 32 bytes at a time */ for ( ; bytes > 0; bytes -= move_bytes)
&& !fixed_regs[5]
&& !fixed_regs[6]
&& !fixed_regs[7]
&& !fixed_regs[8]
&& !fixed_regs[9]
&& !fixed_regs[10]
&& !fixed_regs[11]
&& !fixed_regs[12])
{
move_bytes = (bytes > 32) ? 32 : bytes;
emit_insn (gen_movstrsi_8reg (dest_reg,
src_reg,
GEN_INT ((move_bytes == 32) ? 0 : move_bytes),
align_rtx,
GEN_INT ((bytes > move_bytes) ? move_bytes : 0)));
}
else if (bytes > 16 /* move up to 24 bytes at a time */
&& !fixed_regs[7]
&& !fixed_regs[8]
&& !fixed_regs[9]
&& !fixed_regs[10]
&& !fixed_regs[11]
&& !fixed_regs[12])
{ {
move_bytes = (bytes > 24) ? 24 : bytes; if (bytes > 24 /* move up to 32 bytes at a time */
emit_insn (gen_movstrsi_6reg (dest_reg, && !fixed_regs[5]
src_reg, && !fixed_regs[6]
GEN_INT (move_bytes), && !fixed_regs[7]
align_rtx, && !fixed_regs[8]
GEN_INT ((bytes > move_bytes) ? move_bytes : 0))); && !fixed_regs[9]
&& !fixed_regs[10]
&& !fixed_regs[11]
&& !fixed_regs[12])
{
move_bytes = (bytes > 32) ? 32 : bytes;
emit_insn (gen_movstrsi_8reg (dest_reg,
src_reg,
GEN_INT ((move_bytes == 32) ? 0 : move_bytes),
align_rtx,
GEN_INT ((bytes > move_bytes) ? move_bytes : 0)));
}
else if (bytes > 16 /* move up to 24 bytes at a time */
&& !fixed_regs[7]
&& !fixed_regs[8]
&& !fixed_regs[9]
&& !fixed_regs[10]
&& !fixed_regs[11]
&& !fixed_regs[12])
{
move_bytes = (bytes > 24) ? 24 : bytes;
emit_insn (gen_movstrsi_6reg (dest_reg,
src_reg,
GEN_INT (move_bytes),
align_rtx,
GEN_INT ((bytes > move_bytes) ? move_bytes : 0)));
}
else if (bytes > 8 /* move up to 16 bytes at a time */
&& !fixed_regs[9]
&& !fixed_regs[10]
&& !fixed_regs[11]
&& !fixed_regs[12])
{
move_bytes = (bytes > 16) ? 16 : bytes;
emit_insn (gen_movstrsi_4reg (dest_reg,
src_reg,
GEN_INT (move_bytes),
align_rtx,
GEN_INT ((bytes > move_bytes) ? move_bytes : 0)));
}
else if (bytes > 4 && !TARGET_64BIT)
{ /* move up to 8 bytes at a time */
move_bytes = (bytes > 8) ? 8 : bytes;
emit_insn (gen_movstrsi_2reg (dest_reg,
src_reg,
GEN_INT (move_bytes),
align_rtx,
GEN_INT ((bytes > move_bytes) ? move_bytes : 0)));
}
else if (bytes >= 4 && (align >= 4 || !STRICT_ALIGNMENT))
{ /* move 4 bytes */
move_bytes = 4;
tmp_reg = gen_reg_rtx (SImode);
emit_move_insn (tmp_reg, gen_rtx (MEM, SImode, src_reg));
emit_move_insn (gen_rtx (MEM, SImode, dest_reg), tmp_reg);
if (bytes > move_bytes)
{
emit_insn (gen_addsi3 (src_reg, src_reg, GEN_INT (move_bytes)));
emit_insn (gen_addsi3 (dest_reg, dest_reg, GEN_INT (move_bytes)));
}
}
else if (bytes == 2 && (align >= 2 || !STRICT_ALIGNMENT))
{ /* move 2 bytes */
move_bytes = 2;
tmp_reg = gen_reg_rtx (HImode);
emit_move_insn (tmp_reg, gen_rtx (MEM, HImode, src_reg));
emit_move_insn (gen_rtx (MEM, HImode, dest_reg), tmp_reg);
}
else if (bytes == 1) /* move 1 byte */
{
move_bytes = 1;
tmp_reg = gen_reg_rtx (QImode);
emit_move_insn (tmp_reg, gen_rtx (MEM, QImode, src_reg));
emit_move_insn (gen_rtx (MEM, QImode, dest_reg), tmp_reg);
}
else
{ /* move up to 4 bytes at a time */
move_bytes = (bytes > 4) ? 4 : bytes;
emit_insn (gen_movstrsi_1reg (dest_reg,
src_reg,
GEN_INT (move_bytes),
align_rtx,
GEN_INT ((bytes > move_bytes) ? move_bytes : 0)));
}
} }
else if (bytes > 8 /* move up to 16 bytes at a time */ }
&& !fixed_regs[9]
&& !fixed_regs[10] else /* string instructions not available */
&& !fixed_regs[11] {
&& !fixed_regs[12]) num_reg = offset = 0;
for ( ; bytes > 0; (bytes -= move_bytes), (offset += move_bytes))
{ {
move_bytes = (bytes > 16) ? 16 : bytes; /* Calculate the correct offset for src/dest */
emit_insn (gen_movstrsi_4reg (dest_reg, if (offset == 0)
src_reg,
GEN_INT (move_bytes),
align_rtx,
GEN_INT ((bytes > move_bytes) ? move_bytes : 0)));
}
else if (bytes > 4 && !TARGET_64BIT)
{ /* move up to 8 bytes at a time */
move_bytes = (bytes > 8) ? 8 : bytes;
emit_insn (gen_movstrsi_2reg (dest_reg,
src_reg,
GEN_INT (move_bytes),
align_rtx,
GEN_INT ((bytes > move_bytes) ? move_bytes : 0)));
}
else if (bytes >= 4 && (align >= 4 || !STRICT_ALIGNMENT))
{ /* move 4 bytes */
move_bytes = 4;
tmp_reg = gen_reg_rtx (SImode);
emit_move_insn (tmp_reg, gen_rtx (MEM, SImode, src_reg));
emit_move_insn (gen_rtx (MEM, SImode, dest_reg), tmp_reg);
if (bytes > move_bytes)
{ {
emit_insn (gen_addsi3 (src_reg, src_reg, GEN_INT (move_bytes))); src_addr = src_reg;
emit_insn (gen_addsi3 (dest_reg, dest_reg, GEN_INT (move_bytes))); dest_addr = dest_reg;
}
else
{
src_addr = gen_rtx (PLUS, Pmode, src_reg, GEN_INT (offset));
dest_addr = gen_rtx (PLUS, Pmode, dest_reg, GEN_INT (offset));
}
/* Generate the appropriate load and store, saving the stores for later */
if (bytes >= 4 && (align >= 4 || !STRICT_ALIGNMENT))
{
move_bytes = 4;
tmp_reg = gen_reg_rtx (SImode);
emit_insn (gen_movsi (tmp_reg, gen_rtx (MEM, SImode, src_addr)));
stores[ num_reg++ ] = gen_movsi (gen_rtx (MEM, SImode, dest_addr), tmp_reg);
}
else if (bytes >= 2 && (align >= 2 || !STRICT_ALIGNMENT))
{
move_bytes = 2;
tmp_reg = gen_reg_rtx (HImode);
emit_insn (gen_movhi (tmp_reg, gen_rtx (MEM, HImode, src_addr)));
stores[ num_reg++ ] = gen_movhi (gen_rtx (MEM, HImode, dest_addr), tmp_reg);
}
else
{
move_bytes = 1;
tmp_reg = gen_reg_rtx (QImode);
emit_insn (gen_movqi (tmp_reg, gen_rtx (MEM, QImode, src_addr)));
stores[ num_reg++ ] = gen_movqi (gen_rtx (MEM, QImode, dest_addr), tmp_reg);
}
if (num_reg >= MAX_MOVE_REG)
{
for (i = 0; i < num_reg; i++)
emit_insn (stores[i]);
num_reg = 0;
} }
} }
else if (bytes == 2 && (align >= 2 || !STRICT_ALIGNMENT))
{ /* move 2 bytes */ if (num_reg > 0)
move_bytes = 2;
tmp_reg = gen_reg_rtx (HImode);
emit_move_insn (tmp_reg, gen_rtx (MEM, HImode, src_reg));
emit_move_insn (gen_rtx (MEM, HImode, dest_reg), tmp_reg);
}
else if (bytes == 1) /* move 1 byte */
{ {
move_bytes = 1; for (i = 0; i < num_reg; i++)
tmp_reg = gen_reg_rtx (QImode); emit_insn (stores[i]);
emit_move_insn (tmp_reg, gen_rtx (MEM, QImode, src_reg));
emit_move_insn (gen_rtx (MEM, QImode, dest_reg), tmp_reg);
}
else
{ /* move up to 4 bytes at a time */
move_bytes = (bytes > 4) ? 4 : bytes;
emit_insn (gen_movstrsi_1reg (dest_reg,
src_reg,
GEN_INT (move_bytes),
align_rtx,
GEN_INT ((bytes > move_bytes) ? move_bytes : 0)));
} }
} }
...@@ -1936,6 +2017,16 @@ output_prolog (file, size) ...@@ -1936,6 +2017,16 @@ output_prolog (file, size)
asm_fprintf (file, "\t{cax|add} 30,0,30\n"); asm_fprintf (file, "\t{cax|add} 30,0,30\n");
rs6000_pic_labelno++; rs6000_pic_labelno++;
} }
else if (TARGET_NO_TOC)
{
ASM_GENERATE_INTERNAL_LABEL (buf, "LCTOC", 1);
asm_fprintf (file, "\t{cau|addis} 30,0,");
assemble_name (file, buf);
asm_fprintf (file, "@ha\n");
asm_fprintf (file, "\t{cal|addi} 30,30,");
assemble_name (file, buf);
asm_fprintf (file, "@l\n");
}
else else
#endif /* USING_SVR4_H */ #endif /* USING_SVR4_H */
{ {
......
...@@ -279,16 +279,7 @@ extern char *rs6000_cpu_string; ...@@ -279,16 +279,7 @@ extern char *rs6000_cpu_string;
On the RS/6000 this is used to define the target cpu type. */ On the RS/6000 this is used to define the target cpu type. */
#define OVERRIDE_OPTIONS \ #define OVERRIDE_OPTIONS rs6000_override_options ()
do { \
rs6000_override_options (); \
SUBTARGET_OVERRIDE_OPTIONS; \
} while (0)
/* For OS-dependent options */
#ifndef SUBTARGET_OVERRIDE_OPTIONS
#define SUBTARGET_OVERRIDE_OPTIONS
#endif
/* Show we can debug even without a frame pointer. */ /* Show we can debug even without a frame pointer. */
#define CAN_DEBUG_WITHOUT_FP #define CAN_DEBUG_WITHOUT_FP
......
...@@ -26,16 +26,19 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ ...@@ -26,16 +26,19 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#define MASK_RELOCATABLE 0x10000000 /* GOT pointers are PC relative */ #define MASK_RELOCATABLE 0x10000000 /* GOT pointers are PC relative */
#define MASK_NO_TRACEBACK 0x08000000 /* eliminate traceback words */ #define MASK_NO_TRACEBACK 0x08000000 /* eliminate traceback words */
#define MASK_LITTLE_ENDIAN 0x04000000 /* target is little endian */ #define MASK_LITTLE_ENDIAN 0x04000000 /* target is little endian */
#define MASK_NO_TOC 0x02000000 /* do not use TOC for loading addresses */
#define TARGET_NO_BITFIELD_TYPE (target_flags & MASK_NO_BITFIELD_TYPE) #define TARGET_NO_BITFIELD_TYPE (target_flags & MASK_NO_BITFIELD_TYPE)
#define TARGET_STRICT_ALIGN (target_flags & MASK_STRICT_ALIGN) #define TARGET_STRICT_ALIGN (target_flags & MASK_STRICT_ALIGN)
#define TARGET_RELOCATABLE (target_flags & MASK_RELOCATABLE) #define TARGET_RELOCATABLE (target_flags & MASK_RELOCATABLE)
#define TARGET_NO_TRACEBACK (target_flags & MASK_NO_TRACEBACK) #define TARGET_NO_TRACEBACK (target_flags & MASK_NO_TRACEBACK)
#define TARGET_LITTLE_ENDIAN (target_flags & MASK_LITTLE_ENDIAN) #define TARGET_LITTLE_ENDIAN (target_flags & MASK_LITTLE_ENDIAN)
#define TARGET_NO_TOC (target_flags & MASK_NO_TOC)
#define TARGET_BITFIELD_TYPE (! TARGET_NO_BITFIELD_TYPE) #define TARGET_BITFIELD_TYPE (! TARGET_NO_BITFIELD_TYPE)
#define TARGET_TRACEBACK (! TARGET_NO_TRACEBACK) #define TARGET_TRACEBACK (! TARGET_NO_TRACEBACK)
#define TARGET_BIG_ENDIAN (! TARGET_LITTLE_ENDIAN) #define TARGET_BIG_ENDIAN (! TARGET_LITTLE_ENDIAN)
#define TARGET_TOC (! TARGET_NO_TOC)
#undef SUBTARGET_SWITCHES #undef SUBTARGET_SWITCHES
#define SUBTARGET_SWITCHES \ #define SUBTARGET_SWITCHES \
...@@ -50,7 +53,39 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ ...@@ -50,7 +53,39 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
{ "little-endian", MASK_LITTLE_ENDIAN }, \ { "little-endian", MASK_LITTLE_ENDIAN }, \
{ "little", MASK_LITTLE_ENDIAN }, \ { "little", MASK_LITTLE_ENDIAN }, \
{ "big-endian", -MASK_LITTLE_ENDIAN }, \ { "big-endian", -MASK_LITTLE_ENDIAN }, \
{ "big", -MASK_LITTLE_ENDIAN }, { "big", -MASK_LITTLE_ENDIAN }, \
{ "no-toc", MASK_NO_TOC | MASK_MINIMAL_TOC }, \
{ "toc", -MASK_NO_TOC },
/* Sometimes certain combinations of command options do not make sense
on a particular target machine. You can define a macro
`OVERRIDE_OPTIONS' to take account of this. This macro, if
defined, is executed once just after all the command options have
been parsed.
The macro SUBTARGET_OVERRIDE_OPTIONS is provided for subtargets, to
get control. */
#define SUBTARGET_OVERRIDE_OPTIONS \
do { \
if (TARGET_RELOCATABLE && TARGET_NO_TOC) \
{ \
target_flags &= ~ MASK_NO_TOC; \
error ("-mrelocatable and -mno-toc are incompatible."); \
} \
\
if (TARGET_RELOCATABLE && !TARGET_MINIMAL_TOC) \
{ \
target_flags |= MASK_MINIMAL_TOC; \
error ("-mrelocatable and -mno-minimal-toc are incompatible."); \
} \
\
if (TARGET_NO_TOC && !TARGET_MINIMAL_TOC) \
{ \
target_flags |= MASK_MINIMAL_TOC; \
error ("-mno-toc and -mno-minimal-toc are incompatible."); \
} \
} while (0)
#include "rs6000/powerpc.h" #include "rs6000/powerpc.h"
...@@ -152,12 +187,12 @@ toc_section () \ ...@@ -152,12 +187,12 @@ toc_section () \
{ \ { \
if (! toc_initialized) \ if (! toc_initialized) \
{ \ { \
if (!TARGET_RELOCATABLE) \ if (!TARGET_RELOCATABLE && !TARGET_NO_TOC) \
fprintf (asm_out_file, "%s\n", TOC_SECTION_ASM_OP); \ fprintf (asm_out_file, "%s\n", TOC_SECTION_ASM_OP); \
\ \
if (TARGET_MINIMAL_TOC) \ if (TARGET_MINIMAL_TOC) \
{ \ { \
if (!TARGET_RELOCATABLE) \ if (!TARGET_RELOCATABLE && !TARGET_NO_TOC) \
{ \ { \
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LCTOC", 0); \ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LCTOC", 0); \
fprintf (asm_out_file, "\t.tc "); \ fprintf (asm_out_file, "\t.tc "); \
......
...@@ -16,9 +16,11 @@ fp-bit.c: $(srcdir)/config/fp-bit.c ...@@ -16,9 +16,11 @@ fp-bit.c: $(srcdir)/config/fp-bit.c
# Build libgcc.a with different options. # Build libgcc.a with different options.
MULTILIB_OPTIONS = msoft-float \ MULTILIB_OPTIONS = msoft-float \
mno-toc \
mlittle/mbig mlittle/mbig
MULTILIB_DIRNAMES = soft-float \ MULTILIB_DIRNAMES = soft-float \
no-toc \
little-endian big-endian little-endian big-endian
MULTILIB_MATCHES = mlittle=mlittle-endian \ MULTILIB_MATCHES = mlittle=mlittle-endian \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment