aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Bergner <bergner@linux.ibm.com>2021-07-14 18:23:31 -0500
committerPeter Bergner <bergner@linux.ibm.com>2021-07-14 18:23:31 -0500
commit7d914777fc6c6151f430d798fc97bae927a430f7 (patch)
tree498ea7095c07db3dc40fd45236b75f057bbc7db1
parentbebd8e9da838c51a7f911985083d5a2b2498a23a (diff)
downloadgcc-7d914777fc6c6151f430d798fc97bae927a430f7.zip
gcc-7d914777fc6c6151f430d798fc97bae927a430f7.tar.gz
gcc-7d914777fc6c6151f430d798fc97bae927a430f7.tar.bz2
rs6000: Move rs6000_split_multireg_move to later in file
An upcoming change to rs6000_split_multireg_move requires it to be moved later in the file to fix a declaration issue. 2021-07-14 Peter Bergner <bergner@linux.ibm.com> gcc/ * config/rs6000/rs6000.c (rs6000_split_multireg_move): Move to later in the file.
-rw-r--r--gcc/config/rs6000/rs6000.c751
1 files changed, 375 insertions, 376 deletions
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index de11de5..1d27bb8 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -16690,382 +16690,6 @@ rs6000_expand_atomic_op (enum rtx_code code, rtx mem, rtx val,
emit_move_insn (orig_after, after);
}
-/* Emit instructions to move SRC to DST. Called by splitters for
- multi-register moves. It will emit at most one instruction for
- each register that is accessed; that is, it won't emit li/lis pairs
- (or equivalent for 64-bit code). One of SRC or DST must be a hard
- register. */
-
-void
-rs6000_split_multireg_move (rtx dst, rtx src)
-{
- /* The register number of the first register being moved. */
- int reg;
- /* The mode that is to be moved. */
- machine_mode mode;
- /* The mode that the move is being done in, and its size. */
- machine_mode reg_mode;
- int reg_mode_size;
- /* The number of registers that will be moved. */
- int nregs;
-
- reg = REG_P (dst) ? REGNO (dst) : REGNO (src);
- mode = GET_MODE (dst);
- nregs = hard_regno_nregs (reg, mode);
-
- /* If we have a vector quad register for MMA, and this is a load or store,
- see if we can use vector paired load/stores. */
- if (mode == XOmode && TARGET_MMA
- && (MEM_P (dst) || MEM_P (src)))
- {
- reg_mode = OOmode;
- nregs /= 2;
- }
- /* If we have a vector pair/quad mode, split it into two/four separate
- vectors. */
- else if (mode == OOmode || mode == XOmode)
- reg_mode = V1TImode;
- else if (FP_REGNO_P (reg))
- reg_mode = DECIMAL_FLOAT_MODE_P (mode) ? DDmode :
- (TARGET_HARD_FLOAT ? DFmode : SFmode);
- else if (ALTIVEC_REGNO_P (reg))
- reg_mode = V16QImode;
- else
- reg_mode = word_mode;
- reg_mode_size = GET_MODE_SIZE (reg_mode);
-
- gcc_assert (reg_mode_size * nregs == GET_MODE_SIZE (mode));
-
- /* TDmode residing in FP registers is special, since the ISA requires that
- the lower-numbered word of a register pair is always the most significant
- word, even in little-endian mode. This does not match the usual subreg
- semantics, so we cannnot use simplify_gen_subreg in those cases. Access
- the appropriate constituent registers "by hand" in little-endian mode.
-
- Note we do not need to check for destructive overlap here since TDmode
- can only reside in even/odd register pairs. */
- if (FP_REGNO_P (reg) && DECIMAL_FLOAT_MODE_P (mode) && !BYTES_BIG_ENDIAN)
- {
- rtx p_src, p_dst;
- int i;
-
- for (i = 0; i < nregs; i++)
- {
- if (REG_P (src) && FP_REGNO_P (REGNO (src)))
- p_src = gen_rtx_REG (reg_mode, REGNO (src) + nregs - 1 - i);
- else
- p_src = simplify_gen_subreg (reg_mode, src, mode,
- i * reg_mode_size);
-
- if (REG_P (dst) && FP_REGNO_P (REGNO (dst)))
- p_dst = gen_rtx_REG (reg_mode, REGNO (dst) + nregs - 1 - i);
- else
- p_dst = simplify_gen_subreg (reg_mode, dst, mode,
- i * reg_mode_size);
-
- emit_insn (gen_rtx_SET (p_dst, p_src));
- }
-
- return;
- }
-
- /* The __vector_pair and __vector_quad modes are multi-register
- modes, so if we have to load or store the registers, we have to be
- careful to properly swap them if we're in little endian mode
- below. This means the last register gets the first memory
- location. We also need to be careful of using the right register
- numbers if we are splitting XO to OO. */
- if (mode == OOmode || mode == XOmode)
- {
- nregs = hard_regno_nregs (reg, mode);
- int reg_mode_nregs = hard_regno_nregs (reg, reg_mode);
- if (MEM_P (dst))
- {
- unsigned offset = 0;
- unsigned size = GET_MODE_SIZE (reg_mode);
-
- /* If we are reading an accumulator register, we have to
- deprime it before we can access it. */
- if (TARGET_MMA
- && GET_MODE (src) == XOmode && FP_REGNO_P (REGNO (src)))
- emit_insn (gen_mma_xxmfacc (src, src));
-
- for (int i = 0; i < nregs; i += reg_mode_nregs)
- {
- unsigned subreg =
- (WORDS_BIG_ENDIAN) ? i : (nregs - reg_mode_nregs - i);
- rtx dst2 = adjust_address (dst, reg_mode, offset);
- rtx src2 = gen_rtx_REG (reg_mode, reg + subreg);
- offset += size;
- emit_insn (gen_rtx_SET (dst2, src2));
- }
-
- return;
- }
-
- if (MEM_P (src))
- {
- unsigned offset = 0;
- unsigned size = GET_MODE_SIZE (reg_mode);
-
- for (int i = 0; i < nregs; i += reg_mode_nregs)
- {
- unsigned subreg =
- (WORDS_BIG_ENDIAN) ? i : (nregs - reg_mode_nregs - i);
- rtx dst2 = gen_rtx_REG (reg_mode, reg + subreg);
- rtx src2 = adjust_address (src, reg_mode, offset);
- offset += size;
- emit_insn (gen_rtx_SET (dst2, src2));
- }
-
- /* If we are writing an accumulator register, we have to
- prime it after we've written it. */
- if (TARGET_MMA
- && GET_MODE (dst) == XOmode && FP_REGNO_P (REGNO (dst)))
- emit_insn (gen_mma_xxmtacc (dst, dst));
-
- return;
- }
-
- if (GET_CODE (src) == UNSPEC)
- {
- gcc_assert (XINT (src, 1) == UNSPEC_MMA_ASSEMBLE);
- gcc_assert (REG_P (dst));
- if (GET_MODE (src) == XOmode)
- gcc_assert (FP_REGNO_P (REGNO (dst)));
- if (GET_MODE (src) == OOmode)
- gcc_assert (VSX_REGNO_P (REGNO (dst)));
-
- reg_mode = GET_MODE (XVECEXP (src, 0, 0));
- int nvecs = XVECLEN (src, 0);
- for (int i = 0; i < nvecs; i++)
- {
- int index = WORDS_BIG_ENDIAN ? i : nvecs - 1 - i;
- rtx dst_i = gen_rtx_REG (reg_mode, reg + index);
- emit_insn (gen_rtx_SET (dst_i, XVECEXP (src, 0, i)));
- }
-
- /* We are writing an accumulator register, so we have to
- prime it after we've written it. */
- if (GET_MODE (src) == XOmode)
- emit_insn (gen_mma_xxmtacc (dst, dst));
-
- return;
- }
-
- /* Register -> register moves can use common code. */
- }
-
- if (REG_P (src) && REG_P (dst) && (REGNO (src) < REGNO (dst)))
- {
- /* If we are reading an accumulator register, we have to
- deprime it before we can access it. */
- if (TARGET_MMA
- && GET_MODE (src) == XOmode && FP_REGNO_P (REGNO (src)))
- emit_insn (gen_mma_xxmfacc (src, src));
-
- /* Move register range backwards, if we might have destructive
- overlap. */
- int i;
- /* XO/OO are opaque so cannot use subregs. */
- if (mode == OOmode || mode == XOmode )
- {
- for (i = nregs - 1; i >= 0; i--)
- {
- rtx dst_i = gen_rtx_REG (reg_mode, REGNO (dst) + i);
- rtx src_i = gen_rtx_REG (reg_mode, REGNO (src) + i);
- emit_insn (gen_rtx_SET (dst_i, src_i));
- }
- }
- else
- {
- for (i = nregs - 1; i >= 0; i--)
- emit_insn (gen_rtx_SET (simplify_gen_subreg (reg_mode, dst, mode,
- i * reg_mode_size),
- simplify_gen_subreg (reg_mode, src, mode,
- i * reg_mode_size)));
- }
-
- /* If we are writing an accumulator register, we have to
- prime it after we've written it. */
- if (TARGET_MMA
- && GET_MODE (dst) == XOmode && FP_REGNO_P (REGNO (dst)))
- emit_insn (gen_mma_xxmtacc (dst, dst));
- }
- else
- {
- int i;
- int j = -1;
- bool used_update = false;
- rtx restore_basereg = NULL_RTX;
-
- if (MEM_P (src) && INT_REGNO_P (reg))
- {
- rtx breg;
-
- if (GET_CODE (XEXP (src, 0)) == PRE_INC
- || GET_CODE (XEXP (src, 0)) == PRE_DEC)
- {
- rtx delta_rtx;
- breg = XEXP (XEXP (src, 0), 0);
- delta_rtx = (GET_CODE (XEXP (src, 0)) == PRE_INC
- ? GEN_INT (GET_MODE_SIZE (GET_MODE (src)))
- : GEN_INT (-GET_MODE_SIZE (GET_MODE (src))));
- emit_insn (gen_add3_insn (breg, breg, delta_rtx));
- src = replace_equiv_address (src, breg);
- }
- else if (! rs6000_offsettable_memref_p (src, reg_mode, true))
- {
- if (GET_CODE (XEXP (src, 0)) == PRE_MODIFY)
- {
- rtx basereg = XEXP (XEXP (src, 0), 0);
- if (TARGET_UPDATE)
- {
- rtx ndst = simplify_gen_subreg (reg_mode, dst, mode, 0);
- emit_insn (gen_rtx_SET (ndst,
- gen_rtx_MEM (reg_mode,
- XEXP (src, 0))));
- used_update = true;
- }
- else
- emit_insn (gen_rtx_SET (basereg,
- XEXP (XEXP (src, 0), 1)));
- src = replace_equiv_address (src, basereg);
- }
- else
- {
- rtx basereg = gen_rtx_REG (Pmode, reg);
- emit_insn (gen_rtx_SET (basereg, XEXP (src, 0)));
- src = replace_equiv_address (src, basereg);
- }
- }
-
- breg = XEXP (src, 0);
- if (GET_CODE (breg) == PLUS || GET_CODE (breg) == LO_SUM)
- breg = XEXP (breg, 0);
-
- /* If the base register we are using to address memory is
- also a destination reg, then change that register last. */
- if (REG_P (breg)
- && REGNO (breg) >= REGNO (dst)
- && REGNO (breg) < REGNO (dst) + nregs)
- j = REGNO (breg) - REGNO (dst);
- }
- else if (MEM_P (dst) && INT_REGNO_P (reg))
- {
- rtx breg;
-
- if (GET_CODE (XEXP (dst, 0)) == PRE_INC
- || GET_CODE (XEXP (dst, 0)) == PRE_DEC)
- {
- rtx delta_rtx;
- breg = XEXP (XEXP (dst, 0), 0);
- delta_rtx = (GET_CODE (XEXP (dst, 0)) == PRE_INC
- ? GEN_INT (GET_MODE_SIZE (GET_MODE (dst)))
- : GEN_INT (-GET_MODE_SIZE (GET_MODE (dst))));
-
- /* We have to update the breg before doing the store.
- Use store with update, if available. */
-
- if (TARGET_UPDATE)
- {
- rtx nsrc = simplify_gen_subreg (reg_mode, src, mode, 0);
- emit_insn (TARGET_32BIT
- ? (TARGET_POWERPC64
- ? gen_movdi_si_update (breg, breg, delta_rtx, nsrc)
- : gen_movsi_si_update (breg, breg, delta_rtx, nsrc))
- : gen_movdi_di_update (breg, breg, delta_rtx, nsrc));
- used_update = true;
- }
- else
- emit_insn (gen_add3_insn (breg, breg, delta_rtx));
- dst = replace_equiv_address (dst, breg);
- }
- else if (!rs6000_offsettable_memref_p (dst, reg_mode, true)
- && GET_CODE (XEXP (dst, 0)) != LO_SUM)
- {
- if (GET_CODE (XEXP (dst, 0)) == PRE_MODIFY)
- {
- rtx basereg = XEXP (XEXP (dst, 0), 0);
- if (TARGET_UPDATE)
- {
- rtx nsrc = simplify_gen_subreg (reg_mode, src, mode, 0);
- emit_insn (gen_rtx_SET (gen_rtx_MEM (reg_mode,
- XEXP (dst, 0)),
- nsrc));
- used_update = true;
- }
- else
- emit_insn (gen_rtx_SET (basereg,
- XEXP (XEXP (dst, 0), 1)));
- dst = replace_equiv_address (dst, basereg);
- }
- else
- {
- rtx basereg = XEXP (XEXP (dst, 0), 0);
- rtx offsetreg = XEXP (XEXP (dst, 0), 1);
- gcc_assert (GET_CODE (XEXP (dst, 0)) == PLUS
- && REG_P (basereg)
- && REG_P (offsetreg)
- && REGNO (basereg) != REGNO (offsetreg));
- if (REGNO (basereg) == 0)
- {
- rtx tmp = offsetreg;
- offsetreg = basereg;
- basereg = tmp;
- }
- emit_insn (gen_add3_insn (basereg, basereg, offsetreg));
- restore_basereg = gen_sub3_insn (basereg, basereg, offsetreg);
- dst = replace_equiv_address (dst, basereg);
- }
- }
- else if (GET_CODE (XEXP (dst, 0)) != LO_SUM)
- gcc_assert (rs6000_offsettable_memref_p (dst, reg_mode, true));
- }
-
- /* If we are reading an accumulator register, we have to
- deprime it before we can access it. */
- if (TARGET_MMA && REG_P (src)
- && GET_MODE (src) == XOmode && FP_REGNO_P (REGNO (src)))
- emit_insn (gen_mma_xxmfacc (src, src));
-
- for (i = 0; i < nregs; i++)
- {
- /* Calculate index to next subword. */
- ++j;
- if (j == nregs)
- j = 0;
-
- /* If compiler already emitted move of first word by
- store with update, no need to do anything. */
- if (j == 0 && used_update)
- continue;
-
- /* XO/OO are opaque so cannot use subregs. */
- if (mode == OOmode || mode == XOmode )
- {
- rtx dst_i = gen_rtx_REG (reg_mode, REGNO (dst) + j);
- rtx src_i = gen_rtx_REG (reg_mode, REGNO (src) + j);
- emit_insn (gen_rtx_SET (dst_i, src_i));
- }
- else
- emit_insn (gen_rtx_SET (simplify_gen_subreg (reg_mode, dst, mode,
- j * reg_mode_size),
- simplify_gen_subreg (reg_mode, src, mode,
- j * reg_mode_size)));
- }
-
- /* If we are writing an accumulator register, we have to
- prime it after we've written it. */
- if (TARGET_MMA && REG_P (dst)
- && GET_MODE (dst) == XOmode && FP_REGNO_P (REGNO (dst)))
- emit_insn (gen_mma_xxmtacc (dst, dst));
-
- if (restore_basereg != NULL_RTX)
- emit_insn (restore_basereg);
- }
-}
-
static GTY(()) alias_set_type TOC_alias_set = -1;
alias_set_type
@@ -26982,6 +26606,381 @@ rs6000_split_logical (rtx operands[3],
return;
}
+/* Emit instructions to move SRC to DST. Called by splitters for
+ multi-register moves. It will emit at most one instruction for
+ each register that is accessed; that is, it won't emit li/lis pairs
+ (or equivalent for 64-bit code). One of SRC or DST must be a hard
+ register. */
+
+void
+rs6000_split_multireg_move (rtx dst, rtx src)
+{
+ /* The register number of the first register being moved. */
+ int reg;
+ /* The mode that is to be moved. */
+ machine_mode mode;
+ /* The mode that the move is being done in, and its size. */
+ machine_mode reg_mode;
+ int reg_mode_size;
+ /* The number of registers that will be moved. */
+ int nregs;
+
+ reg = REG_P (dst) ? REGNO (dst) : REGNO (src);
+ mode = GET_MODE (dst);
+ nregs = hard_regno_nregs (reg, mode);
+
+ /* If we have a vector quad register for MMA, and this is a load or store,
+ see if we can use vector paired load/stores. */
+ if (mode == XOmode && TARGET_MMA
+ && (MEM_P (dst) || MEM_P (src)))
+ {
+ reg_mode = OOmode;
+ nregs /= 2;
+ }
+ /* If we have a vector pair/quad mode, split it into two/four separate
+ vectors. */
+ else if (mode == OOmode || mode == XOmode)
+ reg_mode = V1TImode;
+ else if (FP_REGNO_P (reg))
+ reg_mode = DECIMAL_FLOAT_MODE_P (mode) ? DDmode :
+ (TARGET_HARD_FLOAT ? DFmode : SFmode);
+ else if (ALTIVEC_REGNO_P (reg))
+ reg_mode = V16QImode;
+ else
+ reg_mode = word_mode;
+ reg_mode_size = GET_MODE_SIZE (reg_mode);
+
+ gcc_assert (reg_mode_size * nregs == GET_MODE_SIZE (mode));
+
+ /* TDmode residing in FP registers is special, since the ISA requires that
+ the lower-numbered word of a register pair is always the most significant
+ word, even in little-endian mode. This does not match the usual subreg
+ semantics, so we cannnot use simplify_gen_subreg in those cases. Access
+ the appropriate constituent registers "by hand" in little-endian mode.
+
+ Note we do not need to check for destructive overlap here since TDmode
+ can only reside in even/odd register pairs. */
+ if (FP_REGNO_P (reg) && DECIMAL_FLOAT_MODE_P (mode) && !BYTES_BIG_ENDIAN)
+ {
+ rtx p_src, p_dst;
+ int i;
+
+ for (i = 0; i < nregs; i++)
+ {
+ if (REG_P (src) && FP_REGNO_P (REGNO (src)))
+ p_src = gen_rtx_REG (reg_mode, REGNO (src) + nregs - 1 - i);
+ else
+ p_src = simplify_gen_subreg (reg_mode, src, mode,
+ i * reg_mode_size);
+
+ if (REG_P (dst) && FP_REGNO_P (REGNO (dst)))
+ p_dst = gen_rtx_REG (reg_mode, REGNO (dst) + nregs - 1 - i);
+ else
+ p_dst = simplify_gen_subreg (reg_mode, dst, mode,
+ i * reg_mode_size);
+
+ emit_insn (gen_rtx_SET (p_dst, p_src));
+ }
+
+ return;
+ }
+
+ /* The __vector_pair and __vector_quad modes are multi-register
+ modes, so if we have to load or store the registers, we have to be
+ careful to properly swap them if we're in little endian mode
+ below. This means the last register gets the first memory
+ location. We also need to be careful of using the right register
+ numbers if we are splitting XO to OO. */
+ if (mode == OOmode || mode == XOmode)
+ {
+ nregs = hard_regno_nregs (reg, mode);
+ int reg_mode_nregs = hard_regno_nregs (reg, reg_mode);
+ if (MEM_P (dst))
+ {
+ unsigned offset = 0;
+ unsigned size = GET_MODE_SIZE (reg_mode);
+
+ /* If we are reading an accumulator register, we have to
+ deprime it before we can access it. */
+ if (TARGET_MMA
+ && GET_MODE (src) == XOmode && FP_REGNO_P (REGNO (src)))
+ emit_insn (gen_mma_xxmfacc (src, src));
+
+ for (int i = 0; i < nregs; i += reg_mode_nregs)
+ {
+ unsigned subreg =
+ (WORDS_BIG_ENDIAN) ? i : (nregs - reg_mode_nregs - i);
+ rtx dst2 = adjust_address (dst, reg_mode, offset);
+ rtx src2 = gen_rtx_REG (reg_mode, reg + subreg);
+ offset += size;
+ emit_insn (gen_rtx_SET (dst2, src2));
+ }
+
+ return;
+ }
+
+ if (MEM_P (src))
+ {
+ unsigned offset = 0;
+ unsigned size = GET_MODE_SIZE (reg_mode);
+
+ for (int i = 0; i < nregs; i += reg_mode_nregs)
+ {
+ unsigned subreg =
+ (WORDS_BIG_ENDIAN) ? i : (nregs - reg_mode_nregs - i);
+ rtx dst2 = gen_rtx_REG (reg_mode, reg + subreg);
+ rtx src2 = adjust_address (src, reg_mode, offset);
+ offset += size;
+ emit_insn (gen_rtx_SET (dst2, src2));
+ }
+
+ /* If we are writing an accumulator register, we have to
+ prime it after we've written it. */
+ if (TARGET_MMA
+ && GET_MODE (dst) == XOmode && FP_REGNO_P (REGNO (dst)))
+ emit_insn (gen_mma_xxmtacc (dst, dst));
+
+ return;
+ }
+
+ if (GET_CODE (src) == UNSPEC)
+ {
+ gcc_assert (XINT (src, 1) == UNSPEC_MMA_ASSEMBLE);
+ gcc_assert (REG_P (dst));
+ if (GET_MODE (src) == XOmode)
+ gcc_assert (FP_REGNO_P (REGNO (dst)));
+ if (GET_MODE (src) == OOmode)
+ gcc_assert (VSX_REGNO_P (REGNO (dst)));
+
+ reg_mode = GET_MODE (XVECEXP (src, 0, 0));
+ int nvecs = XVECLEN (src, 0);
+ for (int i = 0; i < nvecs; i++)
+ {
+ int index = WORDS_BIG_ENDIAN ? i : nvecs - 1 - i;
+ rtx dst_i = gen_rtx_REG (reg_mode, reg + index);
+ emit_insn (gen_rtx_SET (dst_i, XVECEXP (src, 0, i)));
+ }
+
+ /* We are writing an accumulator register, so we have to
+ prime it after we've written it. */
+ if (GET_MODE (src) == XOmode)
+ emit_insn (gen_mma_xxmtacc (dst, dst));
+
+ return;
+ }
+
+ /* Register -> register moves can use common code. */
+ }
+
+ if (REG_P (src) && REG_P (dst) && (REGNO (src) < REGNO (dst)))
+ {
+ /* If we are reading an accumulator register, we have to
+ deprime it before we can access it. */
+ if (TARGET_MMA
+ && GET_MODE (src) == XOmode && FP_REGNO_P (REGNO (src)))
+ emit_insn (gen_mma_xxmfacc (src, src));
+
+ /* Move register range backwards, if we might have destructive
+ overlap. */
+ int i;
+ /* XO/OO are opaque so cannot use subregs. */
+ if (mode == OOmode || mode == XOmode )
+ {
+ for (i = nregs - 1; i >= 0; i--)
+ {
+ rtx dst_i = gen_rtx_REG (reg_mode, REGNO (dst) + i);
+ rtx src_i = gen_rtx_REG (reg_mode, REGNO (src) + i);
+ emit_insn (gen_rtx_SET (dst_i, src_i));
+ }
+ }
+ else
+ {
+ for (i = nregs - 1; i >= 0; i--)
+ emit_insn (gen_rtx_SET (simplify_gen_subreg (reg_mode, dst, mode,
+ i * reg_mode_size),
+ simplify_gen_subreg (reg_mode, src, mode,
+ i * reg_mode_size)));
+ }
+
+ /* If we are writing an accumulator register, we have to
+ prime it after we've written it. */
+ if (TARGET_MMA
+ && GET_MODE (dst) == XOmode && FP_REGNO_P (REGNO (dst)))
+ emit_insn (gen_mma_xxmtacc (dst, dst));
+ }
+ else
+ {
+ int i;
+ int j = -1;
+ bool used_update = false;
+ rtx restore_basereg = NULL_RTX;
+
+ if (MEM_P (src) && INT_REGNO_P (reg))
+ {
+ rtx breg;
+
+ if (GET_CODE (XEXP (src, 0)) == PRE_INC
+ || GET_CODE (XEXP (src, 0)) == PRE_DEC)
+ {
+ rtx delta_rtx;
+ breg = XEXP (XEXP (src, 0), 0);
+ delta_rtx = (GET_CODE (XEXP (src, 0)) == PRE_INC
+ ? GEN_INT (GET_MODE_SIZE (GET_MODE (src)))
+ : GEN_INT (-GET_MODE_SIZE (GET_MODE (src))));
+ emit_insn (gen_add3_insn (breg, breg, delta_rtx));
+ src = replace_equiv_address (src, breg);
+ }
+ else if (! rs6000_offsettable_memref_p (src, reg_mode, true))
+ {
+ if (GET_CODE (XEXP (src, 0)) == PRE_MODIFY)
+ {
+ rtx basereg = XEXP (XEXP (src, 0), 0);
+ if (TARGET_UPDATE)
+ {
+ rtx ndst = simplify_gen_subreg (reg_mode, dst, mode, 0);
+ emit_insn (gen_rtx_SET (ndst,
+ gen_rtx_MEM (reg_mode,
+ XEXP (src, 0))));
+ used_update = true;
+ }
+ else
+ emit_insn (gen_rtx_SET (basereg,
+ XEXP (XEXP (src, 0), 1)));
+ src = replace_equiv_address (src, basereg);
+ }
+ else
+ {
+ rtx basereg = gen_rtx_REG (Pmode, reg);
+ emit_insn (gen_rtx_SET (basereg, XEXP (src, 0)));
+ src = replace_equiv_address (src, basereg);
+ }
+ }
+
+ breg = XEXP (src, 0);
+ if (GET_CODE (breg) == PLUS || GET_CODE (breg) == LO_SUM)
+ breg = XEXP (breg, 0);
+
+ /* If the base register we are using to address memory is
+ also a destination reg, then change that register last. */
+ if (REG_P (breg)
+ && REGNO (breg) >= REGNO (dst)
+ && REGNO (breg) < REGNO (dst) + nregs)
+ j = REGNO (breg) - REGNO (dst);
+ }
+ else if (MEM_P (dst) && INT_REGNO_P (reg))
+ {
+ rtx breg;
+
+ if (GET_CODE (XEXP (dst, 0)) == PRE_INC
+ || GET_CODE (XEXP (dst, 0)) == PRE_DEC)
+ {
+ rtx delta_rtx;
+ breg = XEXP (XEXP (dst, 0), 0);
+ delta_rtx = (GET_CODE (XEXP (dst, 0)) == PRE_INC
+ ? GEN_INT (GET_MODE_SIZE (GET_MODE (dst)))
+ : GEN_INT (-GET_MODE_SIZE (GET_MODE (dst))));
+
+ /* We have to update the breg before doing the store.
+ Use store with update, if available. */
+
+ if (TARGET_UPDATE)
+ {
+ rtx nsrc = simplify_gen_subreg (reg_mode, src, mode, 0);
+ emit_insn (TARGET_32BIT
+ ? (TARGET_POWERPC64
+ ? gen_movdi_si_update (breg, breg, delta_rtx, nsrc)
+ : gen_movsi_si_update (breg, breg, delta_rtx, nsrc))
+ : gen_movdi_di_update (breg, breg, delta_rtx, nsrc));
+ used_update = true;
+ }
+ else
+ emit_insn (gen_add3_insn (breg, breg, delta_rtx));
+ dst = replace_equiv_address (dst, breg);
+ }
+ else if (!rs6000_offsettable_memref_p (dst, reg_mode, true)
+ && GET_CODE (XEXP (dst, 0)) != LO_SUM)
+ {
+ if (GET_CODE (XEXP (dst, 0)) == PRE_MODIFY)
+ {
+ rtx basereg = XEXP (XEXP (dst, 0), 0);
+ if (TARGET_UPDATE)
+ {
+ rtx nsrc = simplify_gen_subreg (reg_mode, src, mode, 0);
+ emit_insn (gen_rtx_SET (gen_rtx_MEM (reg_mode,
+ XEXP (dst, 0)),
+ nsrc));
+ used_update = true;
+ }
+ else
+ emit_insn (gen_rtx_SET (basereg,
+ XEXP (XEXP (dst, 0), 1)));
+ dst = replace_equiv_address (dst, basereg);
+ }
+ else
+ {
+ rtx basereg = XEXP (XEXP (dst, 0), 0);
+ rtx offsetreg = XEXP (XEXP (dst, 0), 1);
+ gcc_assert (GET_CODE (XEXP (dst, 0)) == PLUS
+ && REG_P (basereg)
+ && REG_P (offsetreg)
+ && REGNO (basereg) != REGNO (offsetreg));
+ if (REGNO (basereg) == 0)
+ {
+ rtx tmp = offsetreg;
+ offsetreg = basereg;
+ basereg = tmp;
+ }
+ emit_insn (gen_add3_insn (basereg, basereg, offsetreg));
+ restore_basereg = gen_sub3_insn (basereg, basereg, offsetreg);
+ dst = replace_equiv_address (dst, basereg);
+ }
+ }
+ else if (GET_CODE (XEXP (dst, 0)) != LO_SUM)
+ gcc_assert (rs6000_offsettable_memref_p (dst, reg_mode, true));
+ }
+
+ /* If we are reading an accumulator register, we have to
+ deprime it before we can access it. */
+ if (TARGET_MMA && REG_P (src)
+ && GET_MODE (src) == XOmode && FP_REGNO_P (REGNO (src)))
+ emit_insn (gen_mma_xxmfacc (src, src));
+
+ for (i = 0; i < nregs; i++)
+ {
+ /* Calculate index to next subword. */
+ ++j;
+ if (j == nregs)
+ j = 0;
+
+ /* If compiler already emitted move of first word by
+ store with update, no need to do anything. */
+ if (j == 0 && used_update)
+ continue;
+
+ /* XO/OO are opaque so cannot use subregs. */
+ if (mode == OOmode || mode == XOmode )
+ {
+ rtx dst_i = gen_rtx_REG (reg_mode, REGNO (dst) + j);
+ rtx src_i = gen_rtx_REG (reg_mode, REGNO (src) + j);
+ emit_insn (gen_rtx_SET (dst_i, src_i));
+ }
+ else
+ emit_insn (gen_rtx_SET (simplify_gen_subreg (reg_mode, dst, mode,
+ j * reg_mode_size),
+ simplify_gen_subreg (reg_mode, src, mode,
+ j * reg_mode_size)));
+ }
+
+ /* If we are writing an accumulator register, we have to
+ prime it after we've written it. */
+ if (TARGET_MMA && REG_P (dst)
+ && GET_MODE (dst) == XOmode && FP_REGNO_P (REGNO (dst)))
+ emit_insn (gen_mma_xxmtacc (dst, dst));
+
+ if (restore_basereg != NULL_RTX)
+ emit_insn (restore_basereg);
+ }
+}
/* Return true if the peephole2 can combine a load involving a combination of
an addis instruction and a load with an offset that can be fused together on