(define_predicate "addv_const_operand"
(and (match_code "const_int")
(match_test "INTVAL (op) >= -32768 && INTVAL (op) <= 32767")))
+
+; Match (subreg (reg ...)) operands.
+; Used for movstrict destination operands
+; When replacing pseudos with hard regs reload strips away the
+; subregs. Accept also plain registers then to prevent the insn from
+; becoming unrecognizable.
+(define_predicate "subreg_register_operand"
+ (ior (and (match_code "subreg")
+ (match_test "register_operand (SUBREG_REG (op), GET_MODE (SUBREG_REG (op)))"))
+ (and (match_code "reg")
+ (match_test "reload_completed || reload_in_progress")
+ (match_test "register_operand (op, GET_MODE (op))"))))
return cfun_gpr_save_slot(RETURN_REGNUM) == SAVE_SLOT_STACK;
}
+/* Generate a SUBREG for the MODE lowpart of EXPR.
+
+ In contrast to gen_lowpart it will always return a SUBREG
+ expression. This is useful to generate STRICT_LOW_PART
+ expressions. */
+rtx
+s390_gen_lowpart_subreg (machine_mode mode, rtx expr)
+{
+ rtx lowpart = gen_lowpart (mode, expr);
+
+ /* There might be no SUBREG in case it could be applied to the hard
+ REG rtx or it could be folded with a paradoxical subreg. Bring
+ it back. */
+ if (!SUBREG_P (lowpart))
+ {
+ machine_mode reg_mode = TARGET_ZARCH ? DImode : SImode;
+ gcc_assert (REG_P (lowpart));
+ lowpart = gen_lowpart_SUBREG (mode,
+ gen_rtx_REG (reg_mode,
+ REGNO (lowpart)));
+ }
+
+ return lowpart;
+}
+
/* Return nonzero if it's OK to use fused multiply-add for MODE. */
bool
s390_fma_allowed_p (machine_mode mode)
/* Emit a strict_low_part pattern if possible. */
if (smode_bsize == bitsize && bitpos == mode_bsize - smode_bsize)
{
- rtx low_dest = gen_lowpart (smode, dest);
+ rtx low_dest = s390_gen_lowpart_subreg (smode, dest);
rtx low_src = gen_lowpart (smode, src);
switch (smode)
"TARGET_ZARCH"
"#"
"&& reload_completed"
- [(set (match_dup 2) (match_dup 3))
+ [(set (match_dup 2) (match_dup 4))
(set (match_dup 0) (ashift:DI (match_dup 0) (const_int 32)))
- (set (strict_low_part (match_dup 2)) (match_dup 4))]
+ (set (strict_low_part (match_dup 3)) (match_dup 5))]
"operands[2] = gen_lowpart (SImode, operands[0]);
- s390_split_access_reg (operands[1], &operands[4], &operands[3]);")
+ operands[3] = s390_gen_lowpart_subreg (SImode, operands[0]);
+ s390_split_access_reg (operands[1], &operands[5], &operands[4]);")
; Splitters for storing TLS pointer to %a0:DI.
[(set (match_dup 0) (match_dup 2))]
"operands[2] = get_pool_constant (operands[1]);")
+
;
-; movstrictqi instruction pattern(s).
+; movstrict instruction pattern(s).
;
(define_insn "movstrictqi"
- [(set (strict_low_part (match_operand:QI 0 "register_operand" "+d,d"))
- (match_operand:QI 1 "memory_operand" "R,T"))]
+ [(set (strict_low_part (match_operand:QI 0 "subreg_register_operand" "+d,d"))
+ (match_operand:QI 1 "memory_operand" "R,T"))]
""
"@
ic\t%0,%1
(set_attr "cpu_facility" "*,longdisp")
(set_attr "z10prop" "z10_super_E1,z10_super_E1")])
-;
-; movstricthi instruction pattern(s).
-;
-
(define_insn "movstricthi"
- [(set (strict_low_part (match_operand:HI 0 "register_operand" "+d,d"))
- (match_operand:HI 1 "memory_operand" "Q,S"))
+ [(set (strict_low_part (match_operand:HI 0 "subreg_register_operand" "+d,d"))
+ (match_operand:HI 1 "memory_operand" "Q,S"))
(clobber (reg:CC CC_REGNUM))]
""
"@
(set_attr "cpu_facility" "*,longdisp")
(set_attr "z10prop" "z10_super_E1,z10_super_E1")])
-;
-; movstrictsi instruction pattern(s).
-;
-
(define_insn "movstrictsi"
- [(set (strict_low_part (match_operand:SI 0 "register_operand" "+d,d,d,d"))
- (match_operand:SI 1 "general_operand" "d,R,T,t"))]
+ [(set (strict_low_part (match_operand:SI 0 "subreg_register_operand" "+d,d,d,d"))
+ (match_operand:SI 1 "general_operand" "d,R,T,t"))]
"TARGET_ZARCH"
"@
lr\t%0,%1
(parallel
[(set (strict_low_part (match_dup 2)) (match_dup 1))
(clobber (reg:CC CC_REGNUM))])]
- "operands[2] = gen_lowpart (HImode, operands[0]);")
+ "operands[2] = s390_gen_lowpart_subreg (HImode, operands[0]);")
(define_insn_and_split "*zero_extendqisi2_31"
[(set (match_operand:SI 0 "register_operand" "=&d")
"&& reload_completed"
[(set (match_dup 0) (const_int 0))
(set (strict_low_part (match_dup 2)) (match_dup 1))]
- "operands[2] = gen_lowpart (QImode, operands[0]);")
+ "operands[2] = s390_gen_lowpart_subreg (QImode, operands[0]);")
;
; zero_extendqihi2 instruction pattern(s).
"&& reload_completed"
[(set (match_dup 0) (const_int 0))
(set (strict_low_part (match_dup 2)) (match_dup 1))]
- "operands[2] = gen_lowpart (QImode, operands[0]);")
+ "operands[2] = s390_gen_lowpart_subreg (QImode, operands[0]);")
;
; fixuns_trunc(dd|td|sf|df|tf)(si|di)2 expander