/* 256-bit integer mode is needed for STACK_SAVEAREA_MODE. */
INT_MODE (OI, 32);
-/* Define TFmode to work around reload problem PR 20927. */
+/* 128-bit float stored in a VR on z14+ or a FPR pair on older machines. */
FLOAT_MODE (TF, 16, ieee_quad_format);
+/* 128-bit float stored in a FPR pair. */
+FLOAT_MODE (FPRX2, 16, ieee_quad_format);
+
/* Add any extra modes needed to represent the condition code. */
/*
extern int s390_class_max_nregs (enum reg_class, machine_mode);
extern bool s390_function_arg_vector (machine_mode, const_tree);
extern bool s390_return_addr_from_memory(void);
+extern bool s390_fma_allowed_p (machine_mode);
#if S390_USE_TARGET_ATTRIBUTE
extern tree s390_valid_target_attribute_tree (tree args,
struct gcc_options *opts,
return cfun_gpr_save_slot(RETURN_REGNUM) == SAVE_SLOT_STACK;
}
+/* Return nonzero if it's OK to use fused multiply-add for MODE. */
+bool
+s390_fma_allowed_p (machine_mode mode)
+{
+ if (TARGET_VXE && mode == TFmode)
+ return flag_vx_long_double_fma;
+
+ return true;
+}
+
/* Indicate which ABI has been used for passing vector args.
0 - no vector type arguments have been passed where the ABI is relevant
1 - the old ABI has been used
machine_mode mode = s390_select_ccmode (code, op0, op1);
rtx cc;
+ /* Force OP1 into register in order to satisfy VXE TFmode patterns. */
+ if (TARGET_VXE && GET_MODE (op1) == TFmode)
+ op1 = force_reg (TFmode, op1);
+
if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_CC)
{
/* Do not output a redundant compare instruction if a
extern rtx
s390_build_signbit_mask (machine_mode mode)
{
+ if (mode == TFmode && TARGET_VXE)
+ {
+ wide_int mask_val = wi::set_bit_in_zero (127, 128);
+ rtx mask = immed_wide_int_const (mask_val, TImode);
+ return gen_lowpart (TFmode, mask);
+ }
+
/* Generate the integral element mask value. */
machine_mode inner_mode = GET_MODE_INNER (mode);
int inner_bitsize = GET_MODE_BITSIZE (inner_mode);
CONST_VECTOR: Generate a bitmask for vgbm instruction.
'x': print integer X as if it's an unsigned halfword.
'v': print register number as vector register (v1 instead of f1).
+ 'V': print the second word of a TFmode operand as vector register.
*/
void
case REG:
/* Print FP regs as fx instead of vx when they are accessed
through non-vector mode. */
- if (code == 'v'
+ if ((code == 'v' || code == 'V')
|| VECTOR_NOFP_REG_P (x)
|| (FP_REG_P (x) && VECTOR_MODE_P (GET_MODE (x)))
|| (VECTOR_REG_P (x)
&& (GET_MODE_SIZE (GET_MODE (x)) /
s390_class_max_nregs (FP_REGS, GET_MODE (x))) > 8))
- fprintf (file, "%%v%s", reg_names[REGNO (x)] + 2);
+ fprintf (file, "%%v%s", reg_names[REGNO (x) + (code == 'V')] + 2);
else
fprintf (file, "%s", reg_names[REGNO (x)]);
break;
static machine_mode constant_modes[] =
{
- TFmode, TImode, TDmode,
+ TFmode, FPRX2mode, TImode, TDmode,
V16QImode, V8HImode, V4SImode, V2DImode, V1TImode,
V4SFmode, V2DFmode, V1TFmode,
DFmode, DImode, DDmode,
full VRs. */
if (TARGET_VX
&& SCALAR_FLOAT_MODE_P (mode)
- && GET_MODE_SIZE (mode) >= 16)
+ && GET_MODE_SIZE (mode) >= 16
+ && !(TARGET_VXE && mode == TFmode))
reg_pair_required_p = true;
/* Even if complex types would fit into a single FPR/VR we force
return (GET_MODE_SIZE (mode) + reg_size - 1) / reg_size;
}
+/* Return nonzero if mode M describes a 128-bit float in a floating point
+ register pair. */
+
+static bool
+s390_is_fpr128 (machine_mode m)
+{
+ return m == FPRX2mode || (!TARGET_VXE && m == TFmode);
+}
+
+/* Return nonzero if mode M describes a 128-bit float in a vector
+ register. */
+
+static bool
+s390_is_vr128 (machine_mode m)
+{
+ return m == V1TFmode || (TARGET_VXE && m == TFmode);
+}
+
/* Implement TARGET_CAN_CHANGE_MODE_CLASS. */
static bool
machine_mode small_mode;
machine_mode big_mode;
- /* V1TF and TF have different representations in vector
- registers. */
+ /* 128-bit values have different representations in floating point and
+ vector registers. */
if (reg_classes_intersect_p (VEC_REGS, rclass)
- && ((from_mode == V1TFmode && to_mode == TFmode)
- || (from_mode == TFmode && to_mode == V1TFmode)))
+ && ((s390_is_fpr128 (from_mode) && s390_is_vr128 (to_mode))
+ || (s390_is_vr128 (from_mode) && s390_is_fpr128 (to_mode))))
return false;
if (GET_MODE_SIZE (from_mode) == GET_MODE_SIZE (to_mode))
#define TARGET_INDIRECT_BRANCH_TABLE s390_indirect_branch_table
+#ifdef GENERATOR_FILE
+/* gencondmd.c is built before insn-flags.h. */
+#define HAVE_TF(icode) true
+#else
+#define HAVE_TF(icode) (HAVE_##icode##_fpr || HAVE_##icode##_vr)
+#endif
+
+/* Dispatcher for movtf. */
+#define EXPAND_MOVTF(icode) \
+ do \
+ { \
+ if (TARGET_VXE) \
+ emit_insn (gen_##icode##_vr (operands[0], operands[1])); \
+ else \
+ emit_insn (gen_##icode##_fpr (operands[0], operands[1])); \
+ DONE; \
+ } \
+ while (false)
+
+/* Like EXPAND_MOVTF, but also legitimizes operands. */
+#define EXPAND_TF(icode, nops) \
+ do \
+ { \
+ const size_t __nops = (nops); \
+ expand_operand ops[__nops]; \
+ create_output_operand (&ops[0], operands[0], GET_MODE (operands[0])); \
+ for (size_t i = 1; i < __nops; i++) \
+ create_input_operand (&ops[i], operands[i], GET_MODE (operands[i])); \
+ if (TARGET_VXE) \
+ expand_insn (CODE_FOR_##icode##_vr, __nops, ops); \
+ else \
+ expand_insn (CODE_FOR_##icode##_fpr, __nops, ops); \
+ DONE; \
+ } \
+ while (false)
#endif /* S390_H */
(PFPO_OP_TYPE_SF 0x5)
(PFPO_OP_TYPE_DF 0x6)
(PFPO_OP_TYPE_TF 0x7)
+ (PFPO_OP_TYPE_FPRX2 0x7)
(PFPO_OP_TYPE_SD 0x8)
(PFPO_OP_TYPE_DD 0x9)
(PFPO_OP_TYPE_TD 0xa)
;; Iterators
-(define_mode_iterator ALL [TI DI SI HI QI TF DF SF TD DD SD V1QI V2QI V4QI V8QI V16QI V1HI V2HI V4HI V8HI V1SI V2SI V4SI V1DI V2DI V1SF V2SF V4SF V1TI V1DF V2DF V1TF])
+(define_mode_iterator ALL [TI DI SI HI QI TF FPRX2 DF SF TD DD SD V1QI V2QI
+ V4QI V8QI V16QI V1HI V2HI V4HI V8HI V1SI V2SI V4SI
+ V1DI V2DI V1SF V2SF V4SF V1TI V1DF V2DF V1TF])
;; These mode iterators allow floating point patterns to be generated from the
;; same template.
-(define_mode_iterator FP_ALL [TF DF SF (TD "TARGET_HARD_DFP") (DD "TARGET_HARD_DFP")
+(define_mode_iterator FP_ALL [(TF "!TARGET_VXE") (FPRX2 "TARGET_VXE") DF SF
+ (TD "TARGET_HARD_DFP") (DD "TARGET_HARD_DFP")
(SD "TARGET_HARD_DFP")])
-(define_mode_iterator FP [TF DF SF (TD "TARGET_HARD_DFP") (DD "TARGET_HARD_DFP")])
-(define_mode_iterator BFP [TF DF SF])
+(define_mode_iterator FP [(TF "!TARGET_VXE") (FPRX2 "TARGET_VXE") DF SF
+ (TD "TARGET_HARD_DFP") (DD "TARGET_HARD_DFP")])
+;; Like FP, but without a condition on TF. Useful for expanders that must be
+;; the same for FP and VR variants of TF.
+(define_mode_iterator FP_ANYTF [TF (FPRX2 "TARGET_VXE") DF SF
+ (TD "TARGET_HARD_DFP")
+ (DD "TARGET_HARD_DFP")])
+(define_mode_iterator BFP [(TF "!TARGET_VXE") (FPRX2 "TARGET_VXE") DF SF])
(define_mode_iterator DFP [TD DD])
(define_mode_iterator DFP_ALL [TD DD SD])
(define_mode_iterator DSF [DF SF])
(define_mode_iterator SD_SF [SF SD])
(define_mode_iterator DD_DF [DF DD])
-(define_mode_iterator TD_TF [TF TD])
+(define_mode_iterator TD_TF [(TF "!TARGET_VXE") (FPRX2 "TARGET_VXE") TD])
; 32 bit int<->fp conversion instructions are available since VXE2 (z15).
(define_mode_iterator VX_CONV_BFP [DF (SF "TARGET_VXE2")])
;; In FP templates, a string like "lt<de>br" will expand to "ltxbr" in
;; TF/TDmode, "ltdbr" in DF/DDmode, and "ltebr" in SF/SDmode.
-(define_mode_attr xde [(TF "x") (DF "d") (SF "e") (TD "x") (DD "d") (SD "e") (V4SF "e") (V2DF "d")])
+(define_mode_attr xde [(TF "x") (FPRX2 "x") (DF "d") (SF "e") (TD "x")
+ (DD "d") (SD "e") (V4SF "e") (V2DF "d")])
;; In FP templates, a <dee> in "m<dee><bt>r" will expand to "mx<bt>r" in
;; TF/TDmode, "md<bt>r" in DF/DDmode, "mee<bt>r" in SFmode and "me<bt>r in
;; These mode attributes are supposed to be used in the `enabled' insn
;; attribute to disable certain alternatives for certain modes.
-(define_mode_attr nBFP [(TF "0") (DF "0") (SF "0") (TD "*") (DD "*") (DD "*")])
-(define_mode_attr nDFP [(TF "*") (DF "*") (SF "*") (TD "0") (DD "0") (DD "0")])
-(define_mode_attr DSF [(TF "0") (DF "*") (SF "*") (TD "0") (DD "0") (SD "0")])
-(define_mode_attr DFDI [(TF "0") (DF "*") (SF "0")
+(define_mode_attr nBFP [(TF "0") (FPRX2 "0") (DF "0") (SF "0") (TD "*")
+ (DD "*") (DD "*")])
+(define_mode_attr nDFP [(TF "*") (FPRX2 "*") (DF "*") (SF "*") (TD "0")
+ (DD "0") (DD "0")])
+(define_mode_attr DSF [(TF "0") (FPRX2 "0") (DF "*") (SF "*") (TD "0")
+ (DD "0") (SD "0")])
+(define_mode_attr DFDI [(TF "0") (FPRX2 "0") (DF "*") (SF "0")
(TD "0") (DD "0") (DD "0")
(TI "0") (DI "*") (SI "0")])
-(define_mode_attr SFSI [(TF "0") (DF "0") (SF "*")
+(define_mode_attr SFSI [(TF "0") (FPRX2 "0") (DF "0") (SF "*")
(TD "0") (DD "0") (DD "0")
(TI "0") (DI "0") (SI "*")])
-(define_mode_attr DF [(TF "0") (DF "*") (SF "0")
+(define_mode_attr DF [(TF "0") (FPRX2 "0") (DF "*") (SF "0")
(TD "0") (DD "0") (DD "0")
(TI "0") (DI "0") (SI "0")])
-(define_mode_attr SF [(TF "0") (DF "0") (SF "*")
+(define_mode_attr SF [(TF "0") (FPRX2 "0") (DF "0") (SF "*")
(TD "0") (DD "0") (DD "0")
(TI "0") (DI "0") (SI "0")])
;; sign bit instructions only handle single source and target fp registers
;; these instructions can only be used for TFmode values if the source and
;; target operand uses the same fp register.
-(define_mode_attr fT0 [(TF "0") (DF "f") (SF "f")])
+(define_mode_attr fT0 [(TF "0") (FPRX2 "0") (DF "f") (SF "f")])
;; This attribute adds b for bfp instructions and t for dfp instructions and is used
;; within instruction mnemonics.
-(define_mode_attr bt [(TF "b") (DF "b") (SF "b") (TD "t") (DD "t") (SD "t")])
+(define_mode_attr bt [(TF "b") (FPRX2 "b") (DF "b") (SF "b") (TD "t") (DD "t")
+ (SD "t")])
;; This attribute is used within instruction mnemonics. It evaluates to d for dfp
;; modes and to an empty string for bfp modes.
-(define_mode_attr _d [(TF "") (DF "") (SF "") (TD "d") (DD "d") (SD "d")])
+(define_mode_attr _d [(TF "") (FPRX2 "") (DF "") (SF "") (TD "d") (DD "d")
+ (SD "d")])
;; In GPR and P templates, a constraint like "<d0>" will expand to "d" in DImode
;; and "0" in SImode. This allows to combine instructions of which the 31bit
;; This attribute expands to DF for TFmode and to DD for TDmode . It is
;; used for Txmode splitters splitting a Txmode copy into 2 Dxmode copies.
-(define_mode_attr HALF_TMODE [(TF "DF") (TD "DD")])
+(define_mode_attr HALF_TMODE [(TF "DF") (FPRX2 "DF") (TD "DD")])
;; Maximum unsigned integer that fits in MODE.
(define_mode_attr max_uint [(HI "65535") (QI "255")])
;; Allow return and simple_return to be defined from a single template.
(define_code_iterator ANY_RETURN [return simple_return])
+;; Facilitate dispatching TFmode expanders on z14+.
+(define_mode_attr tf_fpr [(TF "_fpr") (FPRX2 "") (DF "") (SF "") (TD "")
+ (DD "") (SD "")])
+
+;; Mode names as seen in type mode_attr values.
+(define_mode_attr type [(TF "tf") (FPRX2 "tf") (DF "df") (SF "sf") (TD "td")
+ (DD "dd") (SD "sd")])
; Condition code modes generated by vector fp comparisons. These will
"TARGET_HARD_FLOAT"
"lt<xde><bt>r\t%0,%0"
[(set_attr "op_type" "RRE")
- (set_attr "type" "fsimp<mode>")])
+ (set_attr "type" "fsimp<type>")])
(define_insn "*cmp<mode>_ccs_0_fastmath"
[(set (reg CC_REGNUM)
&& !flag_signaling_nans"
"lt<xde><bt>r\t%0,%0"
[(set_attr "op_type" "RRE")
- (set_attr "type" "fsimp<mode>")])
+ (set_attr "type" "fsimp<type>")])
; VX: TFmode in FPR pairs: use cxbr instead of wfcxb
; cxtr, cdtr, cxbr, cdbr, cebr, cdb, ceb, wfcsb, wfcdb
(set_attr "cpu_facility" "*,*,vx,vxe")
(set_attr "enabled" "*,<DSF>,<DF>,<SF>")])
+; VX: TFmode in VR: use wfcxb
+(define_insn "*cmptf_ccs"
+ [(set (reg CC_REGNUM)
+ (compare (match_operand:TF 0 "register_operand" "v")
+ (match_operand:TF 1 "register_operand" "v")))]
+ "s390_match_ccmode(insn, CCSmode) && TARGET_VXE"
+ "wfcxb\t%0,%1"
+ [(set_attr "op_type" "VRR")
+ (set_attr "cpu_facility" "vxe")])
+
+; VX: TFmode in FPR pairs: use kxbr instead of wfkxb
+; kxtr, kdtr, kxbr, kdbr, kebr, kdb, keb, wfksb, wfkdb
(define_insn "*cmp<mode>_ccsfps"
[(set (reg CC_REGNUM)
(compare (match_operand:FP 0 "register_operand" "f,f,v,v")
(set_attr "cpu_facility" "*,*,vx,vxe")
(set_attr "enabled" "*,<DSF>,<DF>,<SF>")])
+; VX: TFmode in VR: use wfkxb
+(define_insn "*cmptf_ccsfps"
+ [(set (reg CC_REGNUM)
+ (compare (match_operand:TF 0 "register_operand" "v")
+ (match_operand:TF 1 "register_operand" "v")))]
+ "s390_match_ccmode (insn, CCSFPSmode) && TARGET_VXE"
+ "wfkxb\t%0,%1"
+ [(set_attr "op_type" "VRR")
+ (set_attr "cpu_facility" "vxe")])
+
; Compare and Branch instructions
; cij, cgij, crj, cgrj, cfi, cgfi, cr, cgr
; mov(tf|td) instruction pattern(s).
;
-(define_expand "mov<mode>"
+(define_expand "mov<mode><tf_fpr>"
[(set (match_operand:TD_TF 0 "nonimmediate_operand" "")
(match_operand:TD_TF 1 "general_operand" ""))]
""
; Test data class.
;
-(define_expand "signbit<mode>2"
+(define_expand "signbit<mode>2<tf_fpr>"
[(set (reg:CCZ CC_REGNUM)
(unspec:CCZ [(match_operand:FP_ALL 1 "register_operand" "f")
(match_dup 2)]
operands[2] = GEN_INT (S390_TDC_SIGNBIT_SET);
})
-(define_expand "isinf<mode>2"
+(define_expand "isinf<mode>2<tf_fpr>"
[(set (reg:CCZ CC_REGNUM)
(unspec:CCZ [(match_operand:FP_ALL 1 "register_operand" "f")
(match_dup 2)]
"TARGET_HARD_FLOAT"
"t<_d>c<xde><bt>\t%0,%1"
[(set_attr "op_type" "RXE")
- (set_attr "type" "fsimp<mode>")])
+ (set_attr "type" "fsimp<type>")])
; This is the only entry point for fixuns_trunc. It multiplexes the
; expansion to either the *_emu expanders below for pre z196 machines
; or emits the default pattern otherwise.
-(define_expand "fixuns_trunc<FP:mode><GPR:mode>2"
+(define_expand "fixuns_trunc<FP:mode><GPR:mode>2<FP:tf_fpr>"
[(parallel
[(set (match_operand:GPR 0 "register_operand" "")
(unsigned_fix:GPR (match_operand:FP 1 "register_operand" "")))
; fix_trunctf(si|di)2 instruction pattern(s).
;
-(define_expand "fix_trunctf<mode>2"
+(define_expand "fix_trunctf<mode>2_fpr"
[(parallel [(set (match_operand:GPR 0 "register_operand" "")
(fix:GPR (match_operand:TF 1 "register_operand" "")))
(unspec:GPR [(const_int BFP_RND_TOWARD_0)] UNSPEC_ROUND)
(clobber (reg:CC CC_REGNUM))])]
- "TARGET_HARD_FLOAT"
+ "TARGET_HARD_FLOAT && !TARGET_VXE"
"")
;
; cxgbr, cdgbr, cegbr, cxgtr, cdgtr
-(define_insn "floatdi<mode>2"
+(define_insn "floatdi<mode>2<tf_fpr>"
[(set (match_operand:FP 0 "register_operand" "=f,v")
(float:FP (match_operand:DI 1 "register_operand" "d,v")))]
"TARGET_ZARCH && TARGET_HARD_FLOAT"
c<xde>g<bt>r\t%0,%1
wcdgb\t%v0,%v1,0,0"
[(set_attr "op_type" "RRE,VRR")
- (set_attr "type" "itof<mode>" )
+ (set_attr "type" "itof<type>" )
(set_attr "cpu_facility" "*,vx")
(set_attr "enabled" "*,<DFDI>")])
; cxfbr, cdfbr, cefbr, wcefb
-(define_insn "floatsi<mode>2"
+(define_insn "floatsi<mode>2<tf_fpr>"
[(set (match_operand:BFP 0 "register_operand" "=f,v")
(float:BFP (match_operand:SI 1 "register_operand" "d,v")))]
"TARGET_HARD_FLOAT"
c<xde>fbr\t%0,%1
wcefb\t%v0,%v1,0,0"
[(set_attr "op_type" "RRE,VRR")
- (set_attr "type" "itof<mode>" )
+ (set_attr "type" "itof<type>" )
(set_attr "cpu_facility" "*,vxe2")
(set_attr "enabled" "*,<SFSI>")])
"TARGET_Z196 && TARGET_HARD_FLOAT"
"c<xde>ftr\t%0,0,%1,0"
[(set_attr "op_type" "RRE")
- (set_attr "type" "itof<mode>" )])
+ (set_attr "type" "itof<type>")])
;
; floatuns(si|di)(tf|df|sf|td|dd)2 instruction pattern(s).
&& (!TARGET_VX || <FP:MODE>mode != DFmode || <GPR:MODE>mode != DImode)"
"c<FP:xde>l<GPR:gf><FP:bt>r\t%0,0,%1,0"
[(set_attr "op_type" "RRE")
- (set_attr "type" "itof<FP:mode>")])
+ (set_attr "type" "itof<FP:type>")])
-(define_expand "floatuns<GPR:mode><FP:mode>2"
+(define_expand "floatuns<GPR:mode><FP:mode>2<tf_fpr>"
[(set (match_operand:FP 0 "register_operand" "")
(unsigned_float:FP (match_operand:GPR 1 "register_operand" "")))]
"TARGET_Z196 && TARGET_HARD_FLOAT")
;
; ldxbr, lexbr
-(define_insn "trunctf<mode>2"
+(define_insn "trunctf<mode>2_fpr"
[(set (match_operand:DSF 0 "register_operand" "=f")
(float_truncate:DSF (match_operand:TF 1 "register_operand" "f")))
(clobber (match_scratch:TF 2 "=f"))]
l<BFP:xde><DSF:xde>br\t%0,%1
l<BFP:xde><DSF:xde>b\t%0,%1"
[(set_attr "op_type" "RRE,RXE")
- (set_attr "type" "fsimp<BFP:mode>, fload<BFP:mode>")])
+ (set_attr "type" "fsimp<BFP:type>, fload<BFP:type>")])
-(define_expand "extend<DSF:mode><BFP:mode>2"
+(define_expand "extend<DSF:mode><BFP:mode>2<BFP:tf_fpr>"
[(set (match_operand:BFP 0 "register_operand" "")
(float_extend:BFP (match_operand:DSF 1 "nonimmediate_operand" "")))]
"TARGET_HARD_FLOAT
; For all of them the inexact exceptions are suppressed.
; fiebra, fidbra, fixbra
-(define_insn "<FPINT:fpint_name><BFP:mode>2"
+(define_insn "<FPINT:fpint_name><BFP:mode>2<BFP:tf_fpr>"
[(set (match_operand:BFP 0 "register_operand" "=f")
(unspec:BFP [(match_operand:BFP 1 "register_operand" "f")]
FPINT))]
"TARGET_Z196"
"fi<BFP:xde>bra\t%0,<FPINT:fpint_roundingmode>,%1,4"
[(set_attr "op_type" "RRF")
- (set_attr "type" "fsimp<BFP:mode>")])
+ (set_attr "type" "fsimp<BFP:type>")])
; rint is supposed to raise an inexact exception so we can use the
; older instructions.
; fiebr, fidbr, fixbr
-(define_insn "rint<BFP:mode>2"
+(define_insn "rint<BFP:mode>2<BFP:tf_fpr>"
[(set (match_operand:BFP 0 "register_operand" "=f")
(unspec:BFP [(match_operand:BFP 1 "register_operand" "f")]
UNSPEC_FPINT_RINT))]
""
"fi<BFP:xde>br\t%0,0,%1"
[(set_attr "op_type" "RRF")
- (set_attr "type" "fsimp<BFP:mode>")])
+ (set_attr "type" "fsimp<BFP:type>")])
; Decimal Floating Point - load fp integer
"TARGET_HARD_DFP"
"fi<DFP:xde>tr\t%0,<FPINT:fpint_roundingmode>,%1,4"
[(set_attr "op_type" "RRF")
- (set_attr "type" "fsimp<DFP:mode>")])
+ (set_attr "type" "fsimp<DFP:type>")])
; fidtr, fixtr
(define_insn "rint<DFP:mode>2"
"TARGET_HARD_DFP"
"fi<DFP:xde>tr\t%0,0,%1,0"
[(set_attr "op_type" "RRF")
- (set_attr "type" "fsimp<DFP:mode>")])
+ (set_attr "type" "fsimp<DFP:type>")])
;
; Binary <-> Decimal floating point trunc patterns
"TARGET_HARD_DFP"
"pfpo")
-(define_expand "trunc<BFP:mode><DFP_ALL:mode>2"
+(define_expand "trunc<BFP:mode><DFP_ALL:mode>2<BFP:tf_fpr>"
[(set (reg:BFP FPR4_REGNUM) (match_operand:BFP 1 "nonimmediate_operand" ""))
(set (reg:SI GPR0_REGNUM) (match_dup 2))
(parallel
operands[2] = GEN_INT (flags);
})
-(define_expand "trunc<DFP_ALL:mode><BFP:mode>2"
+(define_expand "trunc<DFP_ALL:mode><BFP:mode>2<BFP:tf_fpr>"
[(set (reg:DFP_ALL FPR4_REGNUM)
(match_operand:DFP_ALL 1 "nonimmediate_operand" ""))
(set (reg:SI GPR0_REGNUM) (match_dup 2))
"TARGET_HARD_DFP"
"pfpo")
-(define_expand "extend<BFP:mode><DFP_ALL:mode>2"
+(define_expand "extend<BFP:mode><DFP_ALL:mode>2<BFP:tf_fpr>"
[(set (reg:BFP FPR4_REGNUM) (match_operand:BFP 1 "nonimmediate_operand" ""))
(set (reg:SI GPR0_REGNUM) (match_dup 2))
(parallel
operands[2] = GEN_INT (flags);
})
-(define_expand "extend<DFP_ALL:mode><BFP:mode>2"
+(define_expand "extend<DFP_ALL:mode><BFP:mode>2<BFP:tf_fpr>"
[(set (reg:DFP_ALL FPR4_REGNUM)
(match_operand:DFP_ALL 1 "nonimmediate_operand" ""))
(set (reg:SI GPR0_REGNUM) (match_dup 2))
; axbr, adbr, aebr, axb, adb, aeb, adtr, axtr
; FIXME: wfadb does not clobber cc
-(define_insn "add<mode>3"
+(define_insn "add<mode>3<tf_fpr>"
[(set (match_operand:FP 0 "register_operand" "=f,f,f,v,v")
(plus:FP (match_operand:FP 1 "nonimmediate_operand" "%f,0,0,v,v")
(match_operand:FP 2 "general_operand" "f,f,R,v,v")))
wfadb\t%v0,%v1,%v2
wfasb\t%v0,%v1,%v2"
[(set_attr "op_type" "RRF,RRE,RXE,VRR,VRR")
- (set_attr "type" "fsimp<mode>")
+ (set_attr "type" "fsimp<type>")
(set_attr "cpu_facility" "*,*,*,vx,vxe")
(set_attr "enabled" "<nBFP>,<nDFP>,<DSF>,<DF>,<SF>")])
a<xde>br\t%0,%2
a<xde>b\t%0,%2"
[(set_attr "op_type" "RRF,RRE,RXE")
- (set_attr "type" "fsimp<mode>")
+ (set_attr "type" "fsimp<type>")
(set_attr "enabled" "<nBFP>,<nDFP>,<DSF>")])
; axbr, adbr, aebr, axb, adb, aeb, adtr, axtr
a<xde>br\t%0,%2
a<xde>b\t%0,%2"
[(set_attr "op_type" "RRF,RRE,RXE")
- (set_attr "type" "fsimp<mode>")
+ (set_attr "type" "fsimp<type>")
(set_attr "enabled" "<nBFP>,<nDFP>,<DSF>")])
;
; FIXME: (clobber (match_scratch:CC 3 "=c,c,c,X,X")) does not work - why?
; sxbr, sdbr, sebr, sdb, seb, sxtr, sdtr
-(define_insn "sub<mode>3"
+(define_insn "sub<mode>3<tf_fpr>"
[(set (match_operand:FP 0 "register_operand" "=f,f,f,v,v")
(minus:FP (match_operand:FP 1 "register_operand" "f,0,0,v,v")
(match_operand:FP 2 "general_operand" "f,f,R,v,v")))
wfsdb\t%v0,%v1,%v2
wfssb\t%v0,%v1,%v2"
[(set_attr "op_type" "RRF,RRE,RXE,VRR,VRR")
- (set_attr "type" "fsimp<mode>")
+ (set_attr "type" "fsimp<type>")
(set_attr "cpu_facility" "*,*,*,vx,vxe")
(set_attr "enabled" "<nBFP>,<nDFP>,<DSF>,<DF>,<SF>")])
s<xde>br\t%0,%2
s<xde>b\t%0,%2"
[(set_attr "op_type" "RRF,RRE,RXE")
- (set_attr "type" "fsimp<mode>")
+ (set_attr "type" "fsimp<type>")
(set_attr "enabled" "<nBFP>,<nDFP>,<DSF>")])
; sxbr, sdbr, sebr, sdb, seb, sxtr, sdtr
s<xde>br\t%0,%2
s<xde>b\t%0,%2"
[(set_attr "op_type" "RRF,RRE,RXE")
- (set_attr "type" "fsimp<mode>")
+ (set_attr "type" "fsimp<type>")
(set_attr "enabled" "<nBFP>,<nDFP>,<DSF>")])
;
; mxbr, mdbr, meebr, mxb, mxb, meeb, mdtr, mxtr
-(define_insn "mul<mode>3"
+(define_insn "mul<mode>3<tf_fpr>"
[(set (match_operand:FP 0 "register_operand" "=f,f,f,v,v")
(mult:FP (match_operand:FP 1 "nonimmediate_operand" "%f,0,0,v,v")
(match_operand:FP 2 "general_operand" "f,f,R,v,v")))]
wfmdb\t%v0,%v1,%v2
wfmsb\t%v0,%v1,%v2"
[(set_attr "op_type" "RRF,RRE,RXE,VRR,VRR")
- (set_attr "type" "fmul<mode>")
+ (set_attr "type" "fmul<type>")
(set_attr "cpu_facility" "*,*,*,vx,vxe")
(set_attr "enabled" "<nBFP>,<nDFP>,<DSF>,<DF>,<SF>")])
(fma:DSF (match_operand:DSF 1 "nonimmediate_operand" "%f,f,v,v")
(match_operand:DSF 2 "nonimmediate_operand" "f,R,v,v")
(match_operand:DSF 3 "register_operand" "0,0,v,v")))]
- "TARGET_HARD_FLOAT"
+ "TARGET_HARD_FLOAT && s390_fma_allowed_p (<MODE>mode)"
"@
ma<xde>br\t%0,%1,%2
ma<xde>b\t%0,%1,%2
(fma:DSF (match_operand:DSF 1 "nonimmediate_operand" "%f,f,v,v")
(match_operand:DSF 2 "nonimmediate_operand" "f,R,v,v")
(neg:DSF (match_operand:DSF 3 "register_operand" "0,0,v,v"))))]
- "TARGET_HARD_FLOAT"
+ "TARGET_HARD_FLOAT && s390_fma_allowed_p (<MODE>mode)"
"@
ms<xde>br\t%0,%1,%2
ms<xde>b\t%0,%1,%2
;
; dxbr, ddbr, debr, dxb, ddb, deb, ddtr, dxtr
-(define_insn "div<mode>3"
+(define_insn "div<mode>3<tf_fpr>"
[(set (match_operand:FP 0 "register_operand" "=f,f,f,v,v")
(div:FP (match_operand:FP 1 "register_operand" "f,0,0,v,v")
(match_operand:FP 2 "general_operand" "f,f,R,v,v")))]
wfddb\t%v0,%v1,%v2
wfdsb\t%v0,%v1,%v2"
[(set_attr "op_type" "RRF,RRE,RXE,VRR,VRR")
- (set_attr "type" "fdiv<mode>")
+ (set_attr "type" "fdiv<type>")
(set_attr "cpu_facility" "*,*,*,vx,vxe")
(set_attr "enabled" "<nBFP>,<nDFP>,<DSF>,<DF>,<SF>")])
operands[6] = gen_label_rtx ();")
;
-; neg(df|sf)2 instruction pattern(s).
+; neg(tf|df|sf)2 instruction pattern(s).
;
-(define_expand "neg<mode>2"
+(define_expand "neg<mode>2<tf_fpr>"
[(parallel
[(set (match_operand:BFP 0 "register_operand")
(neg:BFP (match_operand:BFP 1 "register_operand")))
"s390_match_ccmode (insn, CCSmode) && TARGET_HARD_FLOAT"
"lc<xde>br\t%0,%1"
[(set_attr "op_type" "RRE")
- (set_attr "type" "fsimp<mode>")])
+ (set_attr "type" "fsimp<type>")])
; lcxbr, lcdbr, lcebr
(define_insn "*neg<mode>2_cconly"
"s390_match_ccmode (insn, CCSmode) && TARGET_HARD_FLOAT"
"lc<xde>br\t%0,%1"
[(set_attr "op_type" "RRE")
- (set_attr "type" "fsimp<mode>")])
+ (set_attr "type" "fsimp<type>")])
; lcdfr
(define_insn "*neg<mode>2_nocc"
"TARGET_DFP"
"lcdfr\t%0,%1"
[(set_attr "op_type" "RRE")
- (set_attr "type" "fsimp<mode>")])
+ (set_attr "type" "fsimp<type>")])
; lcxbr, lcdbr, lcebr
; FIXME: wflcdb does not clobber cc
wflcsb\t%0,%1"
[(set_attr "op_type" "RRE,VRR,VRR")
(set_attr "cpu_facility" "*,vx,vxe")
- (set_attr "type" "fsimp<mode>,*,*")
+ (set_attr "type" "fsimp<type>,*,*")
(set_attr "enabled" "*,<DF>,<SF>")])
(set_attr "z10prop" "z10_c")])
;
-; abs(df|sf)2 instruction pattern(s).
+; abs(tf|df|sf)2 instruction pattern(s).
;
-(define_expand "abs<mode>2"
+(define_expand "abs<mode>2<tf_fpr>"
[(parallel
[(set (match_operand:BFP 0 "register_operand" "=f")
(abs:BFP (match_operand:BFP 1 "register_operand" "f")))
"s390_match_ccmode (insn, CCSmode) && TARGET_HARD_FLOAT"
"lp<xde>br\t%0,%1"
[(set_attr "op_type" "RRE")
- (set_attr "type" "fsimp<mode>")])
+ (set_attr "type" "fsimp<type>")])
; lpxbr, lpdbr, lpebr
(define_insn "*abs<mode>2_cconly"
"s390_match_ccmode (insn, CCSmode) && TARGET_HARD_FLOAT"
"lp<xde>br\t%0,%1"
[(set_attr "op_type" "RRE")
- (set_attr "type" "fsimp<mode>")])
+ (set_attr "type" "fsimp<type>")])
; lpdfr
(define_insn "*abs<mode>2_nocc"
"TARGET_DFP"
"lpdfr\t%0,%1"
[(set_attr "op_type" "RRE")
- (set_attr "type" "fsimp<mode>")])
+ (set_attr "type" "fsimp<type>")])
; lpxbr, lpdbr, lpebr
; FIXME: wflpdb does not clobber cc
wflpdb\t%0,%1"
[(set_attr "op_type" "RRE,VRR")
(set_attr "cpu_facility" "*,vx")
- (set_attr "type" "fsimp<mode>,*")
+ (set_attr "type" "fsimp<type>,*")
(set_attr "enabled" "*,<DFDI>")])
"s390_match_ccmode (insn, CCSmode) && TARGET_HARD_FLOAT"
"ln<xde>br\t%0,%1"
[(set_attr "op_type" "RRE")
- (set_attr "type" "fsimp<mode>")])
+ (set_attr "type" "fsimp<type>")])
; lnxbr, lndbr, lnebr
(define_insn "*negabs<mode>2_cconly"
"s390_match_ccmode (insn, CCSmode) && TARGET_HARD_FLOAT"
"ln<xde>br\t%0,%1"
[(set_attr "op_type" "RRE")
- (set_attr "type" "fsimp<mode>")])
+ (set_attr "type" "fsimp<type>")])
; lndfr
(define_insn "*negabs<mode>2_nocc"
"TARGET_DFP"
"lndfr\t%0,%1"
[(set_attr "op_type" "RRE")
- (set_attr "type" "fsimp<mode>")])
+ (set_attr "type" "fsimp<type>")])
; lnxbr, lndbr, lnebr
; FIXME: wflndb does not clobber cc
wflndb\t%0,%1"
[(set_attr "op_type" "RRE,VRR")
(set_attr "cpu_facility" "*,vx")
- (set_attr "type" "fsimp<mode>,*")
+ (set_attr "type" "fsimp<type>,*")
(set_attr "enabled" "*,<DFDI>")])
;;
;
; sqxbr, sqdbr, sqebr, sqdb, sqeb
-(define_insn "sqrt<mode>2"
+(define_insn "sqrt<mode>2<tf_fpr>"
[(set (match_operand:BFP 0 "register_operand" "=f,f,v")
(sqrt:BFP (match_operand:BFP 1 "general_operand" "f,R,v")))]
"TARGET_HARD_FLOAT"
sq<xde>b\t%0,%1
wfsqdb\t%v0,%v1"
[(set_attr "op_type" "RRE,RXE,VRR")
- (set_attr "type" "fsqrt<mode>")
+ (set_attr "type" "fsqrt<type>")
(set_attr "cpu_facility" "*,*,vx")
(set_attr "enabled" "*,<DSF>,<DFDI>")])
(define_expand "cbranch<mode>4"
[(set (pc)
(if_then_else (match_operator 0 "comparison_operator"
- [(match_operand:FP 1 "register_operand" "")
- (match_operand:FP 2 "general_operand" "")])
+ [(match_operand:FP_ANYTF 1 "register_operand" "")
+ (match_operand:FP_ANYTF 2 "general_operand" "")])
(label_ref (match_operand 3 "" ""))
(pc)))]
"TARGET_HARD_FLOAT"
;;- Copy sign instructions
;;
-(define_insn "copysign<mode>3"
+(define_insn "copysign<mode>3<tf_fpr>"
[(set (match_operand:FP 0 "register_operand" "=f")
(unspec:FP [(match_operand:FP 1 "register_operand" "<fT0>")
(match_operand:FP 2 "register_operand" "f")]
"TARGET_Z196"
"cpsdr\t%0,%2,%1"
[(set_attr "op_type" "RRF")
- (set_attr "type" "fsimp<mode>")])
+ (set_attr "type" "fsimp<type>")])
;;
Target Report Var(flag_nop_mcount)
Generate mcount/__fentry__ calls as nops. To activate they need to be
patched in.
+
+mvx-long-double-fma
+Target Report Undocumented Var(flag_vx_long_double_fma)
+Emit fused multiply-add instructions for long doubles in vector registers
+(wfmaxb, wfmsxb, wfnmaxb, wfnmsxb). Reassociation pass does not handle
+fused multiply-adds, therefore code generated by the middle-end is prone to
+having long fused multiply-add chains. This is not pipeline-friendly,
+and the default behavior is to emit separate multiplication and addition
+instructions for long doubles in vector registers, because measurements show
+that this improves performance. This option allows overriding it for testing
+purposes.
V2SF V4SF V1DF V2DF V1TF V1TI TI])
; All modes directly supported by the hardware having full vector reg size
-; V_HW2 is duplicate of V_HW for having two iterators expanding
-; independently e.g. vcond
-(define_mode_iterator V_HW [V16QI V8HI V4SI V2DI (V1TI "TARGET_VXE") V2DF (V4SF "TARGET_VXE") (V1TF "TARGET_VXE")])
-(define_mode_iterator V_HW2 [V16QI V8HI V4SI V2DI V2DF (V4SF "TARGET_VXE") (V1TF "TARGET_VXE")])
+; V_HW2 is for having two iterators expanding independently e.g. vcond.
+; It's similar to V_HW, but not fully identical: V1TI is not included, because
+; there are no 128-bit compares.
+(define_mode_iterator V_HW [V16QI V8HI V4SI V2DI (V1TI "TARGET_VXE") V2DF
+ (V4SF "TARGET_VXE") (V1TF "TARGET_VXE")
+ (TF "TARGET_VXE")])
+(define_mode_iterator V_HW2 [V16QI V8HI V4SI V2DI V2DF (V4SF "TARGET_VXE")
+ (V1TF "TARGET_VXE") (TF "TARGET_VXE")])
(define_mode_iterator V_HW_64 [V2DI V2DF])
(define_mode_iterator VT_HW_HSDT [V8HI V4SI V4SF V2DI V2DF V1TI V1TF TI TF])
(define_mode_iterator VFT [(V1SF "TARGET_VXE") (V2SF "TARGET_VXE") (V4SF "TARGET_VXE")
V1DF V2DF
- (V1TF "TARGET_VXE")])
+ (V1TF "TARGET_VXE") (TF "TARGET_VXE")])
; FP vector modes directly supported by the HW. This does not include
; vector modes using only part of a vector register and should be used
; for instructions which might trigger IEEE exceptions.
-(define_mode_iterator VF_HW [(V4SF "TARGET_VXE") V2DF (V1TF "TARGET_VXE")])
+(define_mode_iterator VF_HW [(V4SF "TARGET_VXE") V2DF (V1TF "TARGET_VXE")
+ (TF "TARGET_VXE")])
(define_mode_iterator V_8 [V1QI])
(define_mode_iterator V_16 [V2QI V1HI])
(define_mode_iterator V_32 [V4QI V2HI V1SI V1SF])
(define_mode_iterator V_64 [V8QI V4HI V2SI V2SF V1DI V1DF])
-(define_mode_iterator V_128 [V16QI V8HI V4SI V4SF V2DI V2DF V1TI V1TF])
-
+(define_mode_iterator V_128 [V16QI V8HI V4SI V4SF V2DI V2DF V1TI V1TF
+ (TF "TARGET_VXE")])
(define_mode_iterator V_128_NOSINGLE [V16QI V8HI V4SI V4SF V2DI V2DF])
; 32 bit int<->fp vector conversion instructions are available since VXE2 (z15).
(V1DF "") (V2DF "")
(V1TF "") (TF "")])
+;; Facilitate dispatching TFmode expanders on z14+.
+(define_mode_attr tf_vr [(TF "_vr") (V4SF "") (V2DF "") (V1TF "") (V1SF "")
+ (V2SF "") (V1DF "") (V16QI "") (V8HI "") (V4SI "")
+ (V2DI "") (V1TI "")])
+
; The element type of the vector.
(define_mode_attr non_vec[(V1QI "QI") (V2QI "QI") (V4QI "QI") (V8QI "QI") (V16QI "QI")
(V1HI "HI") (V2HI "HI") (V4HI "HI") (V8HI "HI")
(V1TI "V1TI")
(V1SF "V1SI") (V2SF "V2SI") (V4SF "V4SI")
(V1DF "V1DI") (V2DF "V2DI")
- (V1TF "V1TI")])
+ (V1TF "V1TI") (TF "V1TI")])
(define_mode_attr vw [(SF "w") (V1SF "w") (V2SF "v") (V4SF "v")
(DF "w") (V1DF "w") (V2DF "v")
(TF "w") (V1TF "w")])
; for TImode (use double-int for the calculations)
; vgmb, vgmh, vgmf, vgmg, vrepib, vrepih, vrepif, vrepig
-(define_insn "mov<mode>"
+(define_insn "mov<mode><tf_vr>"
[(set (match_operand:V_128 0 "nonimmediate_operand" "=v,v,R, v, v, v, v, v,v,*d,*d,?o")
(match_operand:V_128 1 "general_operand" " v,R,v,j00,jm1,jyy,jxx,jKK,d, v,dT,*d"))]
""
[(set_attr "cpu_facility" "vx,vx,vx,vx,vx,vx,vx,vx,vx,vx,*,*")
(set_attr "op_type" "VRR,VRX,VRX,VRI,VRI,VRI,VRI,VRI,VRR,*,*,*")])
+(define_expand "movtf"
+ [(match_operand:TF 0 "nonimmediate_operand" "")
+ (match_operand:TF 1 "general_operand" "")]
+ ""
+ { EXPAND_MOVTF(movtf); })
+
; VR -> GPR, no instruction so split it into 64 element sets.
(define_split
[(set (match_operand:V_128 0 "register_operand" "")
; A TFmode operand resides in FPR register pairs while V1TF is in a
; single vector register.
-(define_insn "*vec_tf_to_v1tf"
+(define_insn "*vec_tf_to_v1tf_fpr"
[(set (match_operand:V1TF 0 "nonimmediate_operand" "=v,v,R,v,v")
(vec_duplicate:V1TF (match_operand:TF 1 "general_operand" "f,R,f,G,d")))]
- "TARGET_VX"
+ "TARGET_VX && !TARGET_VXE"
"@
vmrhg\t%v0,%1,%N1
vl\t%v0,%1%A1
vlvgp\t%v0,%1,%N1"
[(set_attr "op_type" "VRR,VRX,VRX,VRI,VRR")])
+; Both TFmode and V1TFmode operands reside in vector registers.
+(define_insn "*vec_tf_to_v1tf_vr"
+ [(set (match_operand:V1TF 0 "nonimmediate_operand" "=v,v,R,v,v")
+ (vec_duplicate:V1TF (match_operand:TF 1 "general_operand" "v,R,v,G,d")))]
+ "TARGET_VXE"
+ "@
+ vlr\t%v0,%1
+ vl\t%v0,%1%A1
+ vst\t%v1,%0%A0
+ vzero\t%v0
+ vlvgp\t%v0,%1,%N1"
+ [(set_attr "op_type" "VRR,VRX,VRX,VRI,VRR")])
+
+(define_insn "*fprx2_to_tf"
+ [(set (match_operand:TF 0 "nonimmediate_operand" "=v")
+ (subreg:TF (match_operand:FPRX2 1 "general_operand" "f") 0))]
+ "TARGET_VXE"
+ "vmrhg\t%v0,%1,%N1"
+ [(set_attr "op_type" "VRR")])
+
(define_insn "*vec_ti_to_v1ti"
[(set (match_operand:V1TI 0 "nonimmediate_operand" "=v,v,R, v, v,v")
(vec_duplicate:V1TI (match_operand:TI 1 "general_operand" "v,R,v,j00,jm1,d")))]
"vperm\t%v0,%v1,%v2,%v3"
[(set_attr "op_type" "VRR")])
+(define_insn "*mov_tf_to_fprx2_0"
+ [(set (subreg:DF (match_operand:FPRX2 0 "nonimmediate_operand" "=f") 0)
+ (subreg:DF (match_operand:TF 1 "general_operand" "v") 0))]
+ "TARGET_VXE"
+ ; M4 == 1 corresponds to %v0[0] = %v1[0]; %v0[1] = %v0[1];
+ "vpdi\t%v0,%v1,%v0,1"
+ [(set_attr "op_type" "VRR")])
+
+(define_insn "*mov_tf_to_fprx2_1"
+ [(set (subreg:DF (match_operand:FPRX2 0 "nonimmediate_operand" "=f") 8)
+ (subreg:DF (match_operand:TF 1 "general_operand" "v") 8))]
+ "TARGET_VXE"
+ ; M4 == 5 corresponds to %V0[0] = %v1[1]; %V0[1] = %V0[1];
+ "vpdi\t%V0,%v1,%V0,5"
+ [(set_attr "op_type" "VRR")])
; vec_perm_const for V2DI using vpdi?
;;
; vfasb, vfadb, wfasb, wfadb, wfaxb
-(define_insn "add<mode>3"
+(define_insn "add<mode>3<tf_vr>"
[(set (match_operand:VF_HW 0 "register_operand" "=v")
(plus:VF_HW (match_operand:VF_HW 1 "register_operand" "v")
(match_operand:VF_HW 2 "register_operand" "v")))]
"<vw>fa<sdx>b\t%v0,%v1,%v2"
[(set_attr "op_type" "VRR")])
+(define_expand "addtf3"
+ [(match_operand:TF 0 "register_operand" "")
+ (match_operand:TF 1 "nonimmediate_operand" "")
+ (match_operand:TF 2 "general_operand" "")]
+ "HAVE_TF (addtf3)"
+ { EXPAND_TF (addtf3, 3); })
+
; vfssb, vfsdb, wfssb, wfsdb, wfsxb
-(define_insn "sub<mode>3"
+(define_insn "sub<mode>3<tf_vr>"
[(set (match_operand:VF_HW 0 "register_operand" "=v")
(minus:VF_HW (match_operand:VF_HW 1 "register_operand" "v")
(match_operand:VF_HW 2 "register_operand" "v")))]
"<vw>fs<sdx>b\t%v0,%v1,%v2"
[(set_attr "op_type" "VRR")])
+(define_expand "subtf3"
+ [(match_operand:TF 0 "register_operand" "")
+ (match_operand:TF 1 "register_operand" "")
+ (match_operand:TF 2 "general_operand" "")]
+ "HAVE_TF (subtf3)"
+ { EXPAND_TF (subtf3, 3); })
+
; vfmsb, vfmdb, wfmsb, wfmdb, wfmxb
-(define_insn "mul<mode>3"
+(define_insn "mul<mode>3<tf_vr>"
[(set (match_operand:VF_HW 0 "register_operand" "=v")
(mult:VF_HW (match_operand:VF_HW 1 "register_operand" "v")
(match_operand:VF_HW 2 "register_operand" "v")))]
"<vw>fm<sdx>b\t%v0,%v1,%v2"
[(set_attr "op_type" "VRR")])
+(define_expand "multf3"
+ [(match_operand:TF 0 "register_operand" "")
+ (match_operand:TF 1 "nonimmediate_operand" "")
+ (match_operand:TF 2 "general_operand" "")]
+ "HAVE_TF (multf3)"
+ { EXPAND_TF (multf3, 3); })
+
; vfdsb, vfddb, wfdsb, wfddb, wfdxb
-(define_insn "div<mode>3"
+(define_insn "div<mode>3<tf_vr>"
[(set (match_operand:VF_HW 0 "register_operand" "=v")
(div:VF_HW (match_operand:VF_HW 1 "register_operand" "v")
(match_operand:VF_HW 2 "register_operand" "v")))]
"<vw>fd<sdx>b\t%v0,%v1,%v2"
[(set_attr "op_type" "VRR")])
+(define_expand "divtf3"
+ [(match_operand:TF 0 "register_operand" "")
+ (match_operand:TF 1 "register_operand" "")
+ (match_operand:TF 2 "general_operand" "")]
+ "HAVE_TF (divtf3)"
+ { EXPAND_TF (divtf3, 3); })
+
; vfsqsb, vfsqdb, wfsqsb, wfsqdb, wfsqxb
-(define_insn "sqrt<mode>2"
- [(set (match_operand:VF_HW 0 "register_operand" "=v")
+(define_insn "sqrt<mode>2<tf_vr>"
+ [(set (match_operand:VF_HW 0 "register_operand" "=v")
(sqrt:VF_HW (match_operand:VF_HW 1 "register_operand" "v")))]
"TARGET_VX"
"<vw>fsq<sdx>b\t%v0,%v1"
[(set_attr "op_type" "VRR")])
+(define_expand "sqrttf2"
+ [(match_operand:TF 0 "register_operand" "")
+ (match_operand:TF 1 "general_operand" "")]
+ "HAVE_TF (sqrttf2)"
+ { EXPAND_TF (sqrttf2, 2); })
+
; vfmasb, vfmadb, wfmasb, wfmadb, wfmaxb
(define_insn "fma<mode>4"
[(set (match_operand:VF_HW 0 "register_operand" "=v")
(fma:VF_HW (match_operand:VF_HW 1 "register_operand" "v")
(match_operand:VF_HW 2 "register_operand" "v")
(match_operand:VF_HW 3 "register_operand" "v")))]
- "TARGET_VX"
+ "TARGET_VX && s390_fma_allowed_p (<MODE>mode)"
"<vw>fma<sdx>b\t%v0,%v1,%v2,%v3"
[(set_attr "op_type" "VRR")])
(fma:VF_HW (match_operand:VF_HW 1 "register_operand" "v")
(match_operand:VF_HW 2 "register_operand" "v")
(neg:VF_HW (match_operand:VF_HW 3 "register_operand" "v"))))]
- "TARGET_VX"
+ "TARGET_VX && s390_fma_allowed_p (<MODE>mode)"
"<vw>fms<sdx>b\t%v0,%v1,%v2,%v3"
[(set_attr "op_type" "VRR")])
(fma:VF_HW (match_operand:VF_HW 1 "register_operand" "v")
(match_operand:VF_HW 2 "register_operand" "v")
(match_operand:VF_HW 3 "register_operand" "v"))))]
- "TARGET_VXE"
+ "TARGET_VXE && s390_fma_allowed_p (<MODE>mode)"
"<vw>fnma<sdx>b\t%v0,%v1,%v2,%v3"
[(set_attr "op_type" "VRR")])
(fma:VF_HW (match_operand:VF_HW 1 "register_operand" "v")
(match_operand:VF_HW 2 "register_operand" "v")
(neg:VF_HW (match_operand:VF_HW 3 "register_operand" "v")))))]
- "TARGET_VXE"
+ "TARGET_VXE && s390_fma_allowed_p (<MODE>mode)"
"<vw>fnms<sdx>b\t%v0,%v1,%v2,%v3"
[(set_attr "op_type" "VRR")])
; vflcsb, vflcdb, wflcsb, wflcdb, wflcxb
-(define_insn "neg<mode>2"
+(define_insn "neg<mode>2<tf_vr>"
[(set (match_operand:VFT 0 "register_operand" "=v")
(neg:VFT (match_operand:VFT 1 "register_operand" "v")))]
"TARGET_VX"
"<vw>flc<sdx>b\t%v0,%v1"
[(set_attr "op_type" "VRR")])
+(define_expand "negtf2"
+ [(match_operand:TF 0 "register_operand" "")
+ (match_operand:TF 1 "register_operand" "")]
+ "HAVE_TF (negtf2)"
+ { EXPAND_TF (negtf2, 2); })
+
; vflpsb, vflpdb, wflpsb, wflpdb, wflpxb
-(define_insn "abs<mode>2"
+(define_insn "abs<mode>2<tf_vr>"
[(set (match_operand:VFT 0 "register_operand" "=v")
(abs:VFT (match_operand:VFT 1 "register_operand" "v")))]
"TARGET_VX"
"<vw>flp<sdx>b\t%v0,%v1"
[(set_attr "op_type" "VRR")])
+(define_expand "abstf2"
+ [(match_operand:TF 0 "register_operand" "")
+ (match_operand:TF 1 "register_operand" "")]
+ "HAVE_TF (abstf2)"
+ { EXPAND_TF (abstf2, 2); })
+
; vflnsb, vflndb, wflnsb, wflndb, wflnxb
(define_insn "negabs<mode>2"
[(set (match_operand:VFT 0 "register_operand" "=v")
"vc<VX_VEC_CONV_BFP:xde><VX_VEC_CONV_INT:bhfgq>b\t%v0,%v1,0,0"
[(set_attr "op_type" "VRR")])
+; There is no instruction for loading a signed integer into an extended BFP
+; operand in a VR, therefore we need to load it into a FPR pair first.
+(define_expand "float<mode>tf2_vr"
+ [(set (match_dup 2)
+ (float:FPRX2 (match_operand:DSI 1 "register_operand" "")))
+ (set (match_operand:TF 0 "register_operand" "")
+ (subreg:TF (match_dup 2) 0))]
+ "TARGET_VXE"
+{
+ operands[2] = gen_reg_rtx (FPRX2mode);
+})
+
+(define_expand "float<mode>tf2"
+ [(match_operand:TF 0 "register_operand" "")
+ (match_operand:DSI 1 "register_operand" "")]
+ "HAVE_TF (float<mode>tf2)"
+ { EXPAND_TF (float<mode>tf2, 2); })
+
; unsigned integer to floating point
; op2: inexact exception not suppressed (IEEE 754 2008)
"vc<VX_VEC_CONV_BFP:xde>l<VX_VEC_CONV_INT:bhfgq>b\t%v0,%v1,0,0"
[(set_attr "op_type" "VRR")])
+; There is no instruction for loading an unsigned integer into an extended BFP
+; operand in a VR, therefore load it into a FPR pair first.
+(define_expand "floatuns<mode>tf2_vr"
+ [(set (match_dup 2)
+ (unsigned_float:FPRX2 (match_operand:GPR 1 "register_operand" "")))
+ (set (match_operand:TF 0 "register_operand" "")
+ (subreg:TF (match_dup 2) 0))]
+ "TARGET_VXE"
+{
+ operands[2] = gen_reg_rtx (FPRX2mode);
+})
+
+(define_expand "floatuns<mode>tf2"
+ [(match_operand:TF 0 "register_operand" "")
+ (match_operand:GPR 1 "register_operand" "")]
+ "HAVE_TF (floatuns<mode>tf2)"
+ { EXPAND_TF (floatuns<mode>tf2, 2); })
+
; floating point to signed integer
; op2: inexact exception not suppressed (IEEE 754 2008)
"vc<VX_VEC_CONV_INT:bhfgq><VX_VEC_CONV_BFP:xde>b\t%v0,%v1,0,5"
[(set_attr "op_type" "VRR")])
+; There is no instruction for rounding an extended BFP operand in a VR into
+; a signed integer, therefore copy it into a FPR pair first.
+(define_expand "fix_trunctf<mode>2_vr"
+ [(set (subreg:DF (match_dup 2) 0)
+ (subreg:DF (match_operand:TF 1 "register_operand" "") 0))
+ (set (subreg:DF (match_dup 2) 8) (subreg:DF (match_dup 1) 8))
+ (parallel [(set (match_operand:GPR 0 "register_operand" "")
+ (fix:GPR (match_dup 2)))
+ (unspec:GPR [(const_int BFP_RND_TOWARD_0)] UNSPEC_ROUND)
+ (clobber (reg:CC CC_REGNUM))])]
+ "TARGET_VXE"
+{
+ operands[2] = gen_reg_rtx (FPRX2mode);
+})
+
+(define_expand "fix_trunctf<mode>2"
+ [(match_operand:GPR 0 "register_operand" "")
+ (match_operand:TF 1 "register_operand" "")]
+ "HAVE_TF (fix_trunctf<mode>2)"
+ { EXPAND_TF (fix_trunctf<mode>2, 2); })
+
; floating point to unsigned integer
; op2: inexact exception not suppressed (IEEE 754 2008)
"vcl<VX_VEC_CONV_INT:bhfgq><VX_VEC_CONV_BFP:xde>b\t%v0,%v1,0,5"
[(set_attr "op_type" "VRR")])
+; There is no instruction for rounding an extended BFP operand in a VR into
+; an unsigned integer, therefore copy it into a FPR pair first.
+(define_expand "fixuns_trunctf<mode>2_vr"
+ [(set (subreg:DF (match_dup 2) 0)
+ (subreg:DF (match_operand:TF 1 "register_operand" "") 0))
+ (set (subreg:DF (match_dup 2) 8) (subreg:DF (match_dup 1) 8))
+ (parallel [(set (match_operand:GPR 0 "register_operand" "")
+ (unsigned_fix:GPR (match_dup 2)))
+ (unspec:GPR [(const_int BFP_RND_TOWARD_0)] UNSPEC_ROUND)
+ (clobber (reg:CC CC_REGNUM))])]
+ "TARGET_VXE"
+{
+ operands[2] = gen_reg_rtx (FPRX2mode);
+})
+
+(define_expand "fixuns_trunctf<mode>2"
+ [(match_operand:GPR 0 "register_operand" "")
+ (match_operand:TF 1 "register_operand" "")]
+ "HAVE_TF (fixuns_trunctf<mode>2)"
+ { EXPAND_TF (fixuns_trunctf<mode>2, 2); })
+
+; load fp integer
+
+; vfisb, wfisb, vfidb, wfidb, wfixb; suppress inexact exceptions
+(define_insn "<FPINT:fpint_name><VF_HW:mode>2<VF_HW:tf_vr>"
+ [(set (match_operand:VF_HW 0 "register_operand" "=v")
+ (unspec:VF_HW [(match_operand:VF_HW 1 "register_operand" "v")]
+ FPINT))]
+ "TARGET_VX"
+ "<vw>fi<VF_HW:sdx>b\t%v0,%v1,4,<FPINT:fpint_roundingmode>"
+ [(set_attr "op_type" "VRR")])
+
+(define_expand "<FPINT:fpint_name>tf2"
+ [(match_operand:TF 0 "register_operand" "")
+ (match_operand:TF 1 "register_operand" "")
+ ; recognize FPINT as an iterator
+ (unspec:TF [(match_dup 1)] FPINT)]
+ "HAVE_TF (<FPINT:fpint_name>tf2)"
+ { EXPAND_TF (<FPINT:fpint_name>tf2, 2); })
+
+; vfisb, wfisb, vfidb, wfidb, wfixb; raise inexact exceptions
+(define_insn "rint<mode>2<tf_vr>"
+ [(set (match_operand:VF_HW 0 "register_operand" "=v")
+ (unspec:VF_HW [(match_operand:VF_HW 1 "register_operand" "v")]
+ UNSPEC_FPINT_RINT))]
+ "TARGET_VX"
+ "<vw>fi<sdx>b\t%v0,%v1,0,0"
+ [(set_attr "op_type" "VRR")])
+
+(define_expand "rinttf2"
+ [(match_operand:TF 0 "register_operand" "")
+ (match_operand:TF 1 "register_operand" "")]
+ "HAVE_TF (rinttf2)"
+ { EXPAND_TF (rinttf2, 2); })
+
+; load rounded
+
+; wflrx
+(define_insn "*trunctfdf2_vr"
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (float_truncate:DF (match_operand:TF 1 "register_operand" "v")))
+ (unspec:DF [(match_operand 2 "const_int_operand" "")]
+ UNSPEC_ROUND)]
+ "TARGET_VXE"
+ "wflrx\t%v0,%v1,0,%2"
+ [(set_attr "op_type" "VRR")])
+
+(define_expand "trunctfdf2_vr"
+ [(parallel [
+ (set (match_operand:DF 0 "register_operand" "")
+ (float_truncate:DF (match_operand:TF 1 "register_operand" "")))
+ (unspec:DF [(const_int BFP_RND_CURRENT)] UNSPEC_ROUND)])]
+ "TARGET_VXE")
+
+(define_expand "trunctfdf2"
+ [(match_operand:DF 0 "register_operand" "")
+ (match_operand:TF 1 "register_operand" "")]
+ "HAVE_TF (trunctfdf2)"
+ { EXPAND_TF (trunctfdf2, 2); })
+
+; wflrx + (ledbr|wledb)
+(define_expand "trunctfsf2_vr"
+ [(parallel [
+ (set (match_dup 2)
+ (float_truncate:DF (match_operand:TF 1 "register_operand" "")))
+ (unspec:DF [(const_int BFP_RND_PREP_FOR_SHORT_PREC)] UNSPEC_ROUND)])
+ (set (match_operand:SF 0 "register_operand" "")
+ (float_truncate:SF (match_dup 2)))]
+ "TARGET_VXE"
+{
+ operands[2] = gen_reg_rtx(DFmode);
+})
+
+(define_expand "trunctfsf2"
+ [(match_operand:SF 0 "register_operand" "")
+ (match_operand:TF 1 "register_operand" "")]
+ "HAVE_TF (trunctfsf2)"
+ { EXPAND_TF (trunctfsf2, 2); })
+
+; load lengthened
+
+(define_insn "extenddftf2_vr"
+ [(set (match_operand:TF 0 "register_operand" "=v")
+ (float_extend:TF (match_operand:DF 1 "register_operand" "f")))]
+ "TARGET_VXE"
+ "wflld\t%v0,%v1"
+ [(set_attr "op_type" "VRR")])
+
+(define_expand "extenddftf2"
+ [(match_operand:TF 0 "register_operand" "")
+ (match_operand:DF 1 "nonimmediate_operand" "")]
+ "HAVE_TF (extenddftf2)"
+ { EXPAND_TF (extenddftf2, 2); })
+
+(define_expand "extendsftf2_vr"
+ [(set (match_dup 2)
+ (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "")))
+ (set (match_operand:TF 0 "register_operand" "")
+ (float_extend:TF (match_dup 2)))]
+ "TARGET_VXE"
+{
+ operands[2] = gen_reg_rtx(DFmode);
+})
+
+(define_expand "extendsftf2"
+ [(match_operand:TF 0 "register_operand" "")
+ (match_operand:SF 1 "nonimmediate_operand" "")]
+ "HAVE_TF (extendsftf2)"
+ { EXPAND_TF (extendsftf2, 2); })
+
+; test data class
+
+(define_expand "signbittf2_vr"
+ [(parallel
+ [(set (reg:CCRAW CC_REGNUM)
+ (unspec:CCRAW [(match_operand:TF 1 "register_operand" "")
+ (match_dup 2)]
+ UNSPEC_VEC_VFTCICC))
+ (clobber (scratch:V1TI))])
+ (set (match_operand:SI 0 "register_operand" "")
+ (const_int 0))
+ (set (match_dup 0)
+ (if_then_else:SI (eq (reg:CCRAW CC_REGNUM) (const_int 8))
+ (const_int 1)
+ (match_dup 0)))]
+ "TARGET_VXE"
+{
+ operands[2] = GEN_INT (S390_TDC_SIGNBIT_SET);
+})
+
+(define_expand "signbittf2"
+ [(match_operand:SI 0 "register_operand" "")
+ (match_operand:TF 1 "register_operand" "")]
+ "HAVE_TF (signbittf2)"
+ { EXPAND_TF (signbittf2, 2); })
+
+(define_expand "isinftf2_vr"
+ [(parallel
+ [(set (reg:CCRAW CC_REGNUM)
+ (unspec:CCRAW [(match_operand:TF 1 "register_operand" "")
+ (match_dup 2)]
+ UNSPEC_VEC_VFTCICC))
+ (clobber (scratch:V1TI))])
+ (set (match_operand:SI 0 "register_operand" "")
+ (const_int 0))
+ (set (match_dup 0)
+ (if_then_else:SI (eq (reg:CCRAW CC_REGNUM) (const_int 8))
+ (const_int 1)
+ (match_dup 0)))]
+ "TARGET_VXE"
+{
+ operands[2] = GEN_INT (S390_TDC_INFINITY);
+})
+
+(define_expand "isinftf2"
+ [(match_operand:SI 0 "register_operand" "")
+ (match_operand:TF 1 "register_operand" "")]
+ "HAVE_TF (isinftf2)"
+ { EXPAND_TF (isinftf2, 2); })
+
;
; Vector byte swap patterns
;
; These ignore the vector result and only want CC stored to an int
; pointer.
-; vftcisb, vftcidb
+; vftcisb, vftcidb, wftcixb
(define_insn "*vftci<mode>_cconly"
[(set (reg:CCRAW CC_REGNUM)
- (unspec:CCRAW [(match_operand:VECF_HW 1 "register_operand")
- (match_operand:HI 2 "const_int_operand")]
+ (unspec:CCRAW [(match_operand:VF_HW 1 "register_operand" "v")
+ (match_operand:HI 2 "const_int_operand" "J")]
UNSPEC_VEC_VFTCICC))
- (clobber (match_scratch:<tointvec> 0))]
+ (clobber (match_scratch:<tointvec> 0 "=v"))]
"TARGET_VX && CONST_OK_FOR_CONSTRAINT_P (INTVAL (operands[2]), 'J', \"J\")"
- "vftci<sdx>b\t%v0,%v1,%x2"
+ "<vw>ftci<sdx>b\t%v0,%v1,%x2"
[(set_attr "op_type" "VRR")])
(define_expand "vftci<mode>_intcconly"
[(parallel
[(set (reg:CCRAW CC_REGNUM)
- (unspec:CCRAW [(match_operand:VECF_HW 0 "register_operand")
- (match_operand:HI 1 "const_int_operand")]
+ (unspec:CCRAW [(match_operand:VF_HW 0 "register_operand")
+ (match_operand:HI 1 "const_int_operand")]
UNSPEC_VEC_VFTCICC))
(clobber (scratch:<tointvec>))])
(set (match_operand:SI 2 "register_operand" "")
; vec_fp_test_data_class wants the result vector and the CC stored to
; an int pointer.
-; vftcisb, vftcidb
-(define_insn "*vftci<mode>"
- [(set (match_operand:VECF_HW 0 "register_operand" "=v")
- (unspec:VECF_HW [(match_operand:VECF_HW 1 "register_operand" "v")
- (match_operand:HI 2 "const_int_operand" "J")]
- UNSPEC_VEC_VFTCI))
+; vftcisb, vftcidb, wftcixb
+(define_insn "vftci<mode>"
+ [(set (match_operand:VF_HW 0 "register_operand" "=v")
+ (unspec:VF_HW [(match_operand:VF_HW 1 "register_operand" "v")
+ (match_operand:HI 2 "const_int_operand" "J")]
+ UNSPEC_VEC_VFTCI))
(set (reg:CCRAW CC_REGNUM)
(unspec:CCRAW [(match_dup 1) (match_dup 2)] UNSPEC_VEC_VFTCICC))]
"TARGET_VX && CONST_OK_FOR_CONSTRAINT_P (INTVAL (operands[2]), 'J', \"J\")"
- "vftci<sdx>b\t%v0,%v1,%x2"
+ "<vw>ftci<sdx>b\t%v0,%v1,%x2"
[(set_attr "op_type" "VRR")])
(define_expand "vftci<mode>_intcc"
[(parallel
- [(set (match_operand:VECF_HW 0 "register_operand")
- (unspec:VECF_HW [(match_operand:VECF_HW 1 "register_operand")
- (match_operand:HI 2 "const_int_operand")]
- UNSPEC_VEC_VFTCI))
+ [(set (match_operand:VF_HW 0 "register_operand")
+ (unspec:VF_HW [(match_operand:VF_HW 1 "register_operand")
+ (match_operand:HI 2 "const_int_operand")]
+ UNSPEC_VEC_VFTCI))
(set (reg:CCRAW CC_REGNUM)
(unspec:CCRAW [(match_dup 1) (match_dup 2)] UNSPEC_VEC_VFTCICC))])
- (set (match_operand:SI 3 "memory_operand" "")
+ (set (match_operand:SI 3 "nonimmediate_operand")
(unspec:SI [(reg:CCRAW CC_REGNUM)] UNSPEC_CC_TO_INT))]
"TARGET_VX && CONST_OK_FOR_CONSTRAINT_P (INTVAL (operands[2]), 'J', \"J\")")