rtx dlo, dhi;
int deleted_move_count = 0;
split_double_mode (mode, &dst, 1, &dlo, &dhi);
+ /* Constraints ensure that if both lo and hi are MEMs, then
+ dst has early-clobber and thus addresses of MEMs don't use
+ dlo/dhi registers. Otherwise if at least one of li and hi are MEMs,
+ dlo/dhi are registers. */
+ if (MEM_P (lo)
+ && rtx_equal_p (dlo, hi)
+ && reg_overlap_mentioned_p (dhi, lo))
+ {
+ /* If dlo is same as hi and lo's address uses dhi register,
+ code below would first emit_move_insn (dhi, hi)
+ and then emit_move_insn (dlo, lo). But the former
+ would invalidate lo's address. Load into dhi first,
+ then swap. */
+ emit_move_insn (dhi, lo);
+ lo = dhi;
+ }
+ else if (MEM_P (hi)
+ && !MEM_P (lo)
+ && !rtx_equal_p (dlo, lo)
+ && reg_overlap_mentioned_p (dlo, hi))
+ {
+ /* In this case, code below would first emit_move_insn (dlo, lo)
+ and then emit_move_insn (dhi, hi). But the former would
+ invalidate hi's address. Load into dhi first. */
+ emit_move_insn (dhi, hi);
+ hi = dhi;
+ }
if (!rtx_equal_p (dlo, hi))
{
if (!rtx_equal_p (dlo, lo))
;; Split DST = (HI<<32)|LO early to minimize register usage.
(define_code_iterator any_or_plus [plus ior xor])
(define_insn_and_split "*concat<mode><dwi>3_1"
- [(set (match_operand:<DWI> 0 "nonimmediate_operand" "=ro")
+ [(set (match_operand:<DWI> 0 "nonimmediate_operand" "=ro,r")
(any_or_plus:<DWI>
- (ashift:<DWI> (match_operand:<DWI> 1 "register_operand" "r")
+ (ashift:<DWI> (match_operand:<DWI> 1 "register_operand" "r,r")
(match_operand:<DWI> 2 "const_int_operand"))
- (zero_extend:<DWI> (match_operand:DWIH 3 "register_operand" "r"))))]
+ (zero_extend:<DWI>
+ (match_operand:DWIH 3 "nonimmediate_operand" "r,m"))))]
"INTVAL (operands[2]) == <MODE_SIZE> * BITS_PER_UNIT"
"#"
"&& reload_completed"
})
(define_insn_and_split "*concat<mode><dwi>3_2"
- [(set (match_operand:<DWI> 0 "nonimmediate_operand" "=ro")
+ [(set (match_operand:<DWI> 0 "nonimmediate_operand" "=ro,r")
(any_or_plus:<DWI>
- (zero_extend:<DWI> (match_operand:DWIH 1 "register_operand" "r"))
- (ashift:<DWI> (match_operand:<DWI> 2 "register_operand" "r")
+ (zero_extend:<DWI>
+ (match_operand:DWIH 1 "nonimmediate_operand" "r,m"))
+ (ashift:<DWI> (match_operand:<DWI> 2 "register_operand" "r,r")
(match_operand:<DWI> 3 "const_int_operand"))))]
"INTVAL (operands[3]) == <MODE_SIZE> * BITS_PER_UNIT"
"#"
})
(define_insn_and_split "*concat<mode><dwi>3_3"
- [(set (match_operand:<DWI> 0 "nonimmediate_operand" "=ro")
+ [(set (match_operand:<DWI> 0 "nonimmediate_operand" "=ro,r,r,&r")
(any_or_plus:<DWI>
(ashift:<DWI>
- (zero_extend:<DWI> (match_operand:DWIH 1 "register_operand" "r"))
+ (zero_extend:<DWI>
+ (match_operand:DWIH 1 "nonimmediate_operand" "r,m,r,m"))
(match_operand:<DWI> 2 "const_int_operand"))
- (zero_extend:<DWI> (match_operand:DWIH 3 "register_operand" "r"))))]
+ (zero_extend:<DWI>
+ (match_operand:DWIH 3 "nonimmediate_operand" "r,r,m,m"))))]
"INTVAL (operands[2]) == <MODE_SIZE> * BITS_PER_UNIT"
"#"
"&& reload_completed"
})
(define_insn_and_split "*concat<mode><dwi>3_4"
- [(set (match_operand:<DWI> 0 "nonimmediate_operand" "=ro")
+ [(set (match_operand:<DWI> 0 "nonimmediate_operand" "=ro,r,r,&r")
(any_or_plus:<DWI>
- (zero_extend:<DWI> (match_operand:DWIH 1 "register_operand" "r"))
+ (zero_extend:<DWI>
+ (match_operand:DWIH 1 "nonimmediate_operand" "r,m,r,m"))
(ashift:<DWI>
- (zero_extend:<DWI> (match_operand:DWIH 2 "register_operand" "r"))
+ (zero_extend:<DWI>
+ (match_operand:DWIH 2 "nonimmediate_operand" "r,r,m,m"))
(match_operand:<DWI> 3 "const_int_operand"))))]
"INTVAL (operands[3]) == <MODE_SIZE> * BITS_PER_UNIT"
"#"
--- /dev/null
+/* PR target/107627 */
+/* { dg-do compile { target int128 } } */
+/* { dg-options "-O2 -masm=att" } */
+/* { dg-final { scan-assembler-not "\torq\t" } } */
+
+static inline unsigned __int128
+foo (unsigned long long x, unsigned long long y)
+{
+ return ((unsigned __int128) x << 64) | y;
+}
+
+static inline unsigned long long
+bar (unsigned long long x, unsigned long long y, unsigned z)
+{
+ return foo (x, y) >> (z % 64);
+}
+
+void
+baz (unsigned long long *x, const unsigned long long *y, unsigned z)
+{
+ x[0] = bar (y[0], y[1], z);
+}
--- /dev/null
+/* PR target/107627 */
+/* { dg-do compile { target ia32 } } */
+/* { dg-options "-O2 -masm=att" } */
+/* { dg-final { scan-assembler-not "\torl\t" } } */
+
+static inline unsigned long long
+qux (unsigned int x, unsigned int y)
+{
+ return ((unsigned long long) x << 32) | y;
+}
+
+static inline unsigned int
+corge (unsigned int x, unsigned int y, unsigned z)
+{
+ return qux (x, y) >> (z % 32);
+}
+
+void
+garply (unsigned int *x, const unsigned int *y, unsigned z)
+{
+ x[0] = corge (y[0], y[1], z);
+}