diff options
author | Michael Meissner <meissner@gcc.gnu.org> | 1995-05-22 18:57:01 +0000 |
---|---|---|
committer | Michael Meissner <meissner@gcc.gnu.org> | 1995-05-22 18:57:01 +0000 |
commit | 3933e0e1e533707b2a0cdf3d03b73f4444ecfac2 (patch) | |
tree | cfbb2fb4d8512c46f9bddae8c49cc89ffc71c6d4 | |
parent | 15c8ec1ccde96eb39e9cced074149b8828ef5a49 (diff) | |
download | gcc-3933e0e1e533707b2a0cdf3d03b73f4444ecfac2.zip gcc-3933e0e1e533707b2a0cdf3d03b73f4444ecfac2.tar.gz gcc-3933e0e1e533707b2a0cdf3d03b73f4444ecfac2.tar.bz2 |
Add -mno-toc; Support block moves if -mno-string.
From-SVN: r9763
-rw-r--r-- | gcc/config/rs6000/rs6000.c | 275 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.h | 11 | ||||
-rw-r--r-- | gcc/config/rs6000/sysv4.h | 41 | ||||
-rw-r--r-- | gcc/config/rs6000/t-ppcgas | 2 |
4 files changed, 224 insertions, 105 deletions
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index c24631e..b3d0746 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -202,6 +202,10 @@ rs6000_override_options () 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 @@ -641,127 +645,204 @@ input_operand (op, mode) operands[2] is the length operands[3] is the alignment */ +#define MAX_MOVE_REG 4 + int expand_block_move (operands) rtx operands[]; { 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]; + int constp = (GET_CODE (bytes_rtx) == CONST_INT); int align = XINT (align_rtx, 0); + int bytes; + int offset; + int num_reg; + int i; rtx src_reg; rtx dest_reg; + rtx src_addr; + rtx dest_addr; rtx tmp_reg; + rtx stores[MAX_MOVE_REG]; int move_bytes; + /* If this is not a fixed size move, just call memcpy */ + if (!constp) + return 0; + /* Anything to move? */ - if (constp && bytes <= 0) + bytes = INTVAL (bytes_rtx); + if (bytes <= 0) return 1; - /* If we don't want to use multiple string instructions, quit now and - generate the normal code. */ - if (!TARGET_STRING) - return 0; - - /* We don't support variable sized moves at this time or real large moves */ - if (!constp || bytes > 64) + /* Don't support real large moves. If string instructions are not used, + then don't generate more than 8 loads. */ + if (TARGET_STRING) + { + if (bytes > 64) + return 0; + } + else if (!STRICT_ALIGNMENT) + { + if (bytes > 4*8) + return 0; + } + else if (bytes > 8*align) return 0; /* Move the address into scratch registers. */ dest_reg = copy_addr_to_reg (XEXP (operands[0], 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 */ - && !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]) + for ( ; bytes > 0; bytes -= move_bytes) { - 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))); + if (bytes > 24 /* move up to 32 bytes at a time */ + && !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; + 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] - && !fixed_regs[11] - && !fixed_regs[12]) + } + + else /* string instructions not available */ + { + num_reg = offset = 0; + for ( ; bytes > 0; (bytes -= move_bytes), (offset += move_bytes)) { - 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) + /* Calculate the correct offset for src/dest */ + if (offset == 0) { - emit_insn (gen_addsi3 (src_reg, src_reg, GEN_INT (move_bytes))); - emit_insn (gen_addsi3 (dest_reg, dest_reg, GEN_INT (move_bytes))); + src_addr = src_reg; + 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 */ - 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 */ + + if (num_reg > 0) { - 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))); + for (i = 0; i < num_reg; i++) + emit_insn (stores[i]); } } @@ -1936,6 +2017,16 @@ output_prolog (file, size) asm_fprintf (file, "\t{cax|add} 30,0,30\n"); 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 #endif /* USING_SVR4_H */ { diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index 4c5103a..353b4a4 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -279,16 +279,7 @@ extern char *rs6000_cpu_string; On the RS/6000 this is used to define the target cpu type. */ -#define OVERRIDE_OPTIONS \ -do { \ - rs6000_override_options (); \ - SUBTARGET_OVERRIDE_OPTIONS; \ -} while (0) - -/* For OS-dependent options */ -#ifndef SUBTARGET_OVERRIDE_OPTIONS -#define SUBTARGET_OVERRIDE_OPTIONS -#endif +#define OVERRIDE_OPTIONS rs6000_override_options () /* Show we can debug even without a frame pointer. */ #define CAN_DEBUG_WITHOUT_FP diff --git a/gcc/config/rs6000/sysv4.h b/gcc/config/rs6000/sysv4.h index 4ad6016..0da08d5 100644 --- a/gcc/config/rs6000/sysv4.h +++ b/gcc/config/rs6000/sysv4.h @@ -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_NO_TRACEBACK 0x08000000 /* eliminate traceback words */ #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_STRICT_ALIGN (target_flags & MASK_STRICT_ALIGN) #define TARGET_RELOCATABLE (target_flags & MASK_RELOCATABLE) #define TARGET_NO_TRACEBACK (target_flags & MASK_NO_TRACEBACK) #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_TRACEBACK (! TARGET_NO_TRACEBACK) #define TARGET_BIG_ENDIAN (! TARGET_LITTLE_ENDIAN) +#define TARGET_TOC (! TARGET_NO_TOC) #undef SUBTARGET_SWITCHES #define SUBTARGET_SWITCHES \ @@ -50,7 +53,39 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ { "little-endian", MASK_LITTLE_ENDIAN }, \ { "little", 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" @@ -152,12 +187,12 @@ toc_section () \ { \ if (! toc_initialized) \ { \ - if (!TARGET_RELOCATABLE) \ + if (!TARGET_RELOCATABLE && !TARGET_NO_TOC) \ fprintf (asm_out_file, "%s\n", TOC_SECTION_ASM_OP); \ \ if (TARGET_MINIMAL_TOC) \ { \ - if (!TARGET_RELOCATABLE) \ + if (!TARGET_RELOCATABLE && !TARGET_NO_TOC) \ { \ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LCTOC", 0); \ fprintf (asm_out_file, "\t.tc "); \ diff --git a/gcc/config/rs6000/t-ppcgas b/gcc/config/rs6000/t-ppcgas index 6b0840a..aa87b5e 100644 --- a/gcc/config/rs6000/t-ppcgas +++ b/gcc/config/rs6000/t-ppcgas @@ -16,9 +16,11 @@ fp-bit.c: $(srcdir)/config/fp-bit.c # Build libgcc.a with different options. MULTILIB_OPTIONS = msoft-float \ + mno-toc \ mlittle/mbig MULTILIB_DIRNAMES = soft-float \ + no-toc \ little-endian big-endian MULTILIB_MATCHES = mlittle=mlittle-endian \ |