else
return false;
})
+
+(define_predicate "lowpart_subreg_operator"
+ (and (match_code "subreg")
+ (match_test "subreg_lowpart_offset (mode, GET_MODE (SUBREG_REG (op)))
+ == SUBREG_BYTE (op)")))
(define_code_iterator any_fix [fix unsigned_fix])
(define_code_iterator any_float [float unsigned_float])
+; Shift right.
+(define_code_iterator any_shiftrt [ashiftrt lshiftrt])
+
(define_code_attr u [(sign_extend "")
(zero_extend "u")
(fix "")
;; {%1:SF=unspec[r122:DI>>0x20#0] 86;clobber scratch;}
;; split it before reload with "and mask" to avoid generating shift right
;; 32 bit then shift left 32 bit.
-(define_insn_and_split "movsf_from_si2"
+(define_insn_and_split "movsf_from_si2_<code>"
[(set (match_operand:SF 0 "gpc_reg_operand" "=wa")
(unspec:SF
- [(subreg:SI
- (ashiftrt:DI
+ [(match_operator:SI 3 "lowpart_subreg_operator"
+ [(any_shiftrt:DI
(match_operand:DI 1 "input_operand" "r")
- (const_int 32))
- 0)]
+ (const_int 32))])]
UNSPEC_SF_FROM_SI))
(clobber (match_scratch:DI 2 "=r"))]
"TARGET_NO_SF_SUBREG"
--- /dev/null
+/* { dg-do run } */
+/* { dg-require-effective-target hard_float } */
+/* { dg-options "-O2 -save-temps" } */
+
+/* Under lp64, parameter 'v' is in DI regs, then bitcast sub DI to SF. */
+/* { dg-final { scan-assembler-times {\mxscvspdpn\M} 1 { target { lp64 && has_arch_pwr8 } } } } */
+/* { dg-final { scan-assembler-times {\mmtvsrd\M} 1 { target { lp64 && has_arch_pwr8 } } } } */
+/* { dg-final { scan-assembler-times {\mrldicr\M} 1 { target { lp64 && has_arch_pwr8 } } } } */
+
+struct di_sf_sf
+{
+ float f1; float f2; long long l;
+};
+
+float __attribute__ ((noipa))
+sf_from_high32bit_di (struct di_sf_sf v)
+{
+#ifdef __LITTLE_ENDIAN__
+ return v.f2;
+#else
+ return v.f1;
+#endif
+}
+
+int main()
+{
+ struct di_sf_sf v;
+ v.f1 = v.f2 = 0.0f;
+#ifdef __LITTLE_ENDIAN__
+ v.f2 = 2.0f;
+#else
+ v.f1 = 2.0f;
+#endif
+ if (sf_from_high32bit_di (v) != 2.0f)
+ __builtin_abort ();
+ return 0;
+}