(IF "TARGET_FLOAT128")
(TF "TARGET_LONG_DOUBLE_128")])
+; Iterator for ISA 3.0 supported floating point types
+(define_mode_iterator FP_ISA3 [SF
+ DF
+ (KF "FLOAT128_IEEE_P (KFmode)")
+ (TF "FLOAT128_IEEE_P (TFmode)")])
+
; SF/DF suffix for traditional floating instructions
(define_mode_attr Ftrad [(SF "s") (DF "")])
[(set_attr "length" "20")
(set_attr "type" "fp")])
+;; ISA 3.0 adds instructions lxsi[bh]zx to directly load QImode and HImode to
+;; vector registers. At the moment, QI/HImode are not allowed in floating
+;; point or vector registers, so we use UNSPEC's to use the load byte and
+;; half-word instructions.
+
+(define_expand "float<QHI:mode><FP_ISA3:mode>2"
+ [(parallel [(set (match_operand:FP_ISA3 0 "vsx_register_operand")
+ (float:FP_ISA3
+ (match_operand:QHI 1 "input_operand")))
+ (clobber (match_scratch:DI 2))
+ (clobber (match_scratch:DI 3))])]
+ "TARGET_P9_VECTOR && TARGET_DIRECT_MOVE && TARGET_POWERPC64"
+{
+ if (MEM_P (operands[1]))
+ operands[1] = rs6000_address_for_fpconvert (operands[1]);
+})
+
+(define_insn_and_split "*float<QHI:mode><FP_ISA3:mode>2_internal"
+ [(set (match_operand:FP_ISA3 0 "vsx_register_operand" "=<Fv>,<Fv>")
+ (float:FP_ISA3
+ (match_operand:QHI 1 "reg_or_indexed_operand" "r,Z")))
+ (clobber (match_scratch:DI 2 "=wi,v"))
+ (clobber (match_scratch:DI 3 "=r,X"))]
+ "TARGET_P9_VECTOR && TARGET_DIRECT_MOVE && TARGET_POWERPC64
+ && TARGET_UPPER_REGS_DI"
+ "#"
+ "&& reload_completed"
+ [(const_int 0)]
+{
+ rtx result = operands[0];
+ rtx input = operands[1];
+ rtx di = operands[2];
+
+ if (!MEM_P (input))
+ {
+ rtx tmp = operands[3];
+ emit_insn (gen_extend<QHI:mode>di2 (tmp, input));
+ emit_move_insn (di, tmp);
+ }
+ else
+ {
+ machine_mode vmode;
+ rtx di_vector;
+
+ emit_insn (gen_p9_lxsi<QHI:wd>zx (di, input));
+
+ if (<MODE>mode == QImode)
+ vmode = V16QImode;
+ else if (<MODE>mode == HImode)
+ vmode = V8HImode;
+ else
+ gcc_unreachable ();
+
+ di_vector = gen_rtx_REG (vmode, REGNO (di));
+ emit_insn (gen_vsx_sign_extend_<QHI:mode>_di (di, di_vector));
+ }
+
+ emit_insn (gen_floatdi<FP_ISA3:mode>2 (result, di));
+ DONE;
+})
+
+(define_expand "floatuns<QHI:mode><FP_ISA3:mode>2"
+ [(parallel [(set (match_operand:FP_ISA3 0 "vsx_register_operand" "")
+ (unsigned_float:FP_ISA3
+ (match_operand:QHI 1 "input_operand" "")))
+ (clobber (match_scratch:DI 2 ""))
+ (clobber (match_scratch:DI 3 ""))])]
+ "TARGET_P9_VECTOR && TARGET_DIRECT_MOVE && TARGET_POWERPC64"
+{
+ if (MEM_P (operands[1]))
+ operands[1] = rs6000_address_for_fpconvert (operands[1]);
+})
+
+(define_insn_and_split "*floatuns<QHI:mode><FP_ISA3:mode>2_internal"
+ [(set (match_operand:FP_ISA3 0 "vsx_register_operand" "=<Fv>,<Fv>")
+ (unsigned_float:FP_ISA3
+ (match_operand:QHI 1 "reg_or_indexed_operand" "r,Z")))
+ (clobber (match_scratch:DI 2 "=wi,wi"))
+ (clobber (match_scratch:DI 3 "=r,X"))]
+ "TARGET_P9_VECTOR && TARGET_DIRECT_MOVE && TARGET_POWERPC64"
+ "#"
+ "&& reload_completed"
+ [(const_int 0)]
+{
+ rtx result = operands[0];
+ rtx input = operands[1];
+ rtx di = operands[2];
+ rtx tmp = operands[3];
+
+ if (!MEM_P (input))
+ {
+ emit_insn (gen_zero_extend<QHI:mode>di2 (tmp, input));
+ emit_move_insn (di, tmp);
+ }
+ else
+ emit_insn (gen_p9_lxsi<QHI:wd>zx (di, input));
+
+ emit_insn (gen_floatdi<FP_ISA3:mode>2 (result, di));
+ DONE;
+})
+
(define_expand "fix_trunc<mode>si2"
[(set (match_operand:SI 0 "gpc_reg_operand" "")
(fix:SI (match_operand:SFDF 1 "gpc_reg_operand" "")))]
xscvdpsxds %x0,%x1"
[(set_attr "type" "fp")])
+(define_expand "fix_trunc<SFDF:mode><QHI:mode>2"
+ [(use (match_operand:QHI 0 "rs6000_nonimmediate_operand" ""))
+ (use (match_operand:SFDF 1 "vsx_register_operand" ""))]
+ "TARGET_P9_VECTOR && TARGET_DIRECT_MOVE && TARGET_POWERPC64"
+{
+ rtx op0 = operands[0];
+ rtx op1 = operands[1];
+ rtx di_tmp = gen_reg_rtx (DImode);
+
+ if (MEM_P (op0))
+ op0 = rs6000_address_for_fpconvert (op0);
+
+ emit_insn (gen_fctiwz_<SFDF:mode> (di_tmp, op1));
+ emit_insn (gen_p9_stxsi<QHI:wd>x (op0, di_tmp));
+ DONE;
+})
+
(define_expand "fixuns_trunc<mode>si2"
[(set (match_operand:SI 0 "gpc_reg_operand" "")
(unsigned_fix:SI (match_operand:SFDF 1 "gpc_reg_operand" "")))]
xscvdpuxds %x0,%x1"
[(set_attr "type" "fp")])
+(define_expand "fixuns_trunc<SFDF:mode><QHI:mode>2"
+ [(use (match_operand:QHI 0 "rs6000_nonimmediate_operand" ""))
+ (use (match_operand:SFDF 1 "vsx_register_operand" ""))]
+ "TARGET_P9_VECTOR && TARGET_DIRECT_MOVE && TARGET_POWERPC64"
+{
+ rtx op0 = operands[0];
+ rtx op1 = operands[1];
+ rtx di_tmp = gen_reg_rtx (DImode);
+
+ if (MEM_P (op0))
+ op0 = rs6000_address_for_fpconvert (op0);
+
+ emit_insn (gen_fctiwuz_<SFDF:mode> (di_tmp, op1));
+ emit_insn (gen_p9_stxsi<QHI:wd>x (op0, di_tmp));
+ DONE;
+})
+
; Here, we use (set (reg) (unspec:DI [(fix:SI ...)] UNSPEC_FCTIWZ))
; rather than (set (subreg:SI (reg)) (fix:SI ...))
; because the first makes it clear that operand 0 is not live