"operands[2] = gen_lowpart (QImode, operands[0]);")
;
-; fixuns_trunc(dd|td)di2 instruction pattern(s).
+; fixuns_trunc(dd|td|sf|df|tf)(si|di)2 expander
;
-(define_expand "fixuns_truncdddi2"
+; 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"
[(parallel
- [(set (match_operand:DI 0 "register_operand" "")
- (unsigned_fix:DI (match_operand:DD 1 "register_operand" "")))
- (unspec:DI [(const_int DFP_RND_TOWARD_0)] UNSPEC_ROUND)
+ [(set (match_operand:GPR 0 "register_operand" "")
+ (unsigned_fix:GPR (match_operand:FP 1 "register_operand" "")))
+ (unspec:GPR [(match_dup 2)] UNSPEC_ROUND)
(clobber (reg:CC CC_REGNUM))])]
-
- "TARGET_HARD_DFP"
+ "TARGET_HARD_FLOAT"
{
if (!TARGET_Z196)
{
- rtx_code_label *label1 = gen_label_rtx ();
- rtx_code_label *label2 = gen_label_rtx ();
- rtx temp = gen_reg_rtx (TDmode);
- REAL_VALUE_TYPE cmp, sub;
-
- decimal_real_from_string (&cmp, "9223372036854775808.0"); /* 2^63 */
- decimal_real_from_string (&sub, "18446744073709551616.0"); /* 2^64 */
-
- /* 2^63 can't be represented as 64bit DFP number with full precision. The
- solution is doing the check and the subtraction in TD mode and using a
- TD -> DI convert afterwards. */
- emit_insn (gen_extendddtd2 (temp, operands[1]));
- temp = force_reg (TDmode, temp);
- emit_cmp_and_jump_insns (temp,
- const_double_from_real_value (cmp, TDmode),
- LT, NULL_RTX, VOIDmode, 0, label1);
- emit_insn (gen_subtd3 (temp, temp,
- const_double_from_real_value (sub, TDmode)));
- emit_insn (gen_fix_trunctddi2_dfp (operands[0], temp,
- GEN_INT (DFP_RND_TOWARD_MINF)));
- emit_jump (label2);
-
- emit_label (label1);
- emit_insn (gen_fix_truncdddi2_dfp (operands[0], operands[1],
- GEN_INT (DFP_RND_TOWARD_0)));
- emit_label (label2);
+ /* We don't provide emulation for TD|DD->SI. */
+ if (GET_MODE_CLASS (<FP:MODE>mode) == MODE_DECIMAL_FLOAT
+ && <GPR:MODE>mode == SImode)
+ FAIL;
+ emit_insn (gen_fixuns_trunc<FP:mode><GPR:mode>2_emu (operands[0],
+ operands[1]));
DONE;
}
+
+ if (GET_MODE_CLASS (<FP:MODE>mode) == MODE_DECIMAL_FLOAT)
+ operands[2] = GEN_INT (DFP_RND_TOWARD_0);
+ else
+ operands[2] = GEN_INT (BFP_RND_TOWARD_0);
+})
+
+; (sf|df|tf)->unsigned (si|di)
+
+; Emulate the unsigned conversion with the signed version for pre z196
+; machines.
+(define_expand "fixuns_trunc<BFP:mode><GPR:mode>2_emu"
+ [(parallel
+ [(set (match_operand:GPR 0 "register_operand" "")
+ (unsigned_fix:GPR (match_operand:BFP 1 "register_operand" "")))
+ (unspec:GPR [(const_int BFP_RND_TOWARD_0)] UNSPEC_ROUND)
+ (clobber (reg:CC CC_REGNUM))])]
+ "!TARGET_Z196 && TARGET_HARD_FLOAT"
+{
+ rtx_code_label *label1 = gen_label_rtx ();
+ rtx_code_label *label2 = gen_label_rtx ();
+ rtx temp = gen_reg_rtx (<BFP:MODE>mode);
+ REAL_VALUE_TYPE cmp, sub;
+
+ operands[1] = force_reg (<BFP:MODE>mode, operands[1]);
+ real_2expN (&cmp, <GPR:bitsize> - 1, <BFP:MODE>mode);
+ real_2expN (&sub, <GPR:bitsize>, <BFP:MODE>mode);
+
+ emit_cmp_and_jump_insns (operands[1],
+ const_double_from_real_value (cmp, <BFP:MODE>mode),
+ LT, NULL_RTX, VOIDmode, 0, label1);
+ emit_insn (gen_sub<BFP:mode>3 (temp, operands[1],
+ const_double_from_real_value (sub, <BFP:MODE>mode)));
+ emit_insn (gen_fix_trunc<BFP:mode><GPR:mode>2_bfp (operands[0], temp,
+ GEN_INT (BFP_RND_TOWARD_MINF)));
+ emit_jump (label2);
+
+ emit_label (label1);
+ emit_insn (gen_fix_trunc<BFP:mode><GPR:mode>2_bfp (operands[0],
+ operands[1],
+ GEN_INT (BFP_RND_TOWARD_0)));
+ emit_label (label2);
+ DONE;
})
-(define_expand "fixuns_trunctddi2"
+; dd->unsigned di
+
+; Emulate the unsigned conversion with the signed version for pre z196
+; machines.
+(define_expand "fixuns_truncdddi2_emu"
[(parallel
[(set (match_operand:DI 0 "register_operand" "")
- (unsigned_fix:DI (match_operand:TD 1 "register_operand" "")))
+ (unsigned_fix:DI (match_operand:DD 1 "register_operand" "")))
(unspec:DI [(const_int DFP_RND_TOWARD_0)] UNSPEC_ROUND)
(clobber (reg:CC CC_REGNUM))])]
- "TARGET_HARD_DFP"
-{
- if (!TARGET_Z196)
- {
- rtx_code_label *label1 = gen_label_rtx ();
- rtx_code_label *label2 = gen_label_rtx ();
- rtx temp = gen_reg_rtx (TDmode);
- REAL_VALUE_TYPE cmp, sub;
-
- operands[1] = force_reg (TDmode, operands[1]);
- decimal_real_from_string (&cmp, "9223372036854775808.0"); /* 2^63 */
- decimal_real_from_string (&sub, "18446744073709551616.0"); /* 2^64 */
-
- emit_cmp_and_jump_insns (operands[1],
- const_double_from_real_value (cmp, TDmode),
- LT, NULL_RTX, VOIDmode, 0, label1);
- emit_insn (gen_subtd3 (temp, operands[1],
- const_double_from_real_value (sub, TDmode)));
- emit_insn (gen_fix_trunctddi2_dfp (operands[0], temp,
- GEN_INT (DFP_RND_TOWARD_MINF)));
- emit_jump (label2);
-
- emit_label (label1);
- emit_insn (gen_fix_trunctddi2_dfp (operands[0], operands[1],
- GEN_INT (DFP_RND_TOWARD_0)));
- emit_label (label2);
- DONE;
- }
+ "!TARGET_Z196 && TARGET_HARD_DFP"
+{
+ rtx_code_label *label1 = gen_label_rtx ();
+ rtx_code_label *label2 = gen_label_rtx ();
+ rtx temp = gen_reg_rtx (TDmode);
+ REAL_VALUE_TYPE cmp, sub;
+
+ decimal_real_from_string (&cmp, "9223372036854775808.0"); /* 2^63 */
+ decimal_real_from_string (&sub, "18446744073709551616.0"); /* 2^64 */
+
+ /* 2^63 can't be represented as 64bit DFP number with full precision. The
+ solution is doing the check and the subtraction in TD mode and using a
+ TD -> DI convert afterwards. */
+ emit_insn (gen_extendddtd2 (temp, operands[1]));
+ temp = force_reg (TDmode, temp);
+ emit_cmp_and_jump_insns (temp,
+ const_double_from_real_value (cmp, TDmode),
+ LT, NULL_RTX, VOIDmode, 0, label1);
+ emit_insn (gen_subtd3 (temp, temp,
+ const_double_from_real_value (sub, TDmode)));
+ emit_insn (gen_fix_trunctddi2_dfp (operands[0], temp,
+ GEN_INT (DFP_RND_TOWARD_MINF)));
+ emit_jump (label2);
+
+ emit_label (label1);
+ emit_insn (gen_fix_truncdddi2_dfp (operands[0], operands[1],
+ GEN_INT (DFP_RND_TOWARD_0)));
+ emit_label (label2);
+ DONE;
})
-;
-; fixuns_trunc(sf|df|tf)(si|di)2 and fix_trunc(sf|df|tf)(si|di)2
-; instruction pattern(s).
-;
+; td->unsigned di
-(define_expand "fixuns_trunc<BFP:mode><GPR:mode>2"
+; Emulate the unsigned conversion with the signed version for pre z196
+; machines.
+(define_expand "fixuns_trunctddi2_emu"
[(parallel
- [(set (match_operand:GPR 0 "register_operand" "")
- (unsigned_fix:GPR (match_operand:BFP 1 "register_operand" "")))
- (unspec:GPR [(const_int BFP_RND_TOWARD_0)] UNSPEC_ROUND)
+ [(set (match_operand:DI 0 "register_operand" "")
+ (unsigned_fix:DI (match_operand:TD 1 "register_operand" "")))
+ (unspec:DI [(const_int DFP_RND_TOWARD_0)] UNSPEC_ROUND)
(clobber (reg:CC CC_REGNUM))])]
- "TARGET_HARD_FLOAT"
-{
- if (!TARGET_Z196)
- {
- rtx_code_label *label1 = gen_label_rtx ();
- rtx_code_label *label2 = gen_label_rtx ();
- rtx temp = gen_reg_rtx (<BFP:MODE>mode);
- REAL_VALUE_TYPE cmp, sub;
-
- operands[1] = force_reg (<BFP:MODE>mode, operands[1]);
- real_2expN (&cmp, <GPR:bitsize> - 1, <BFP:MODE>mode);
- real_2expN (&sub, <GPR:bitsize>, <BFP:MODE>mode);
-
- emit_cmp_and_jump_insns (operands[1],
- const_double_from_real_value (cmp, <BFP:MODE>mode),
- LT, NULL_RTX, VOIDmode, 0, label1);
- emit_insn (gen_sub<BFP:mode>3 (temp, operands[1],
- const_double_from_real_value (sub, <BFP:MODE>mode)));
- emit_insn (gen_fix_trunc<BFP:mode><GPR:mode>2_bfp (operands[0], temp,
- GEN_INT (BFP_RND_TOWARD_MINF)));
- emit_jump (label2);
- emit_label (label1);
- emit_insn (gen_fix_trunc<BFP:mode><GPR:mode>2_bfp (operands[0],
- operands[1], GEN_INT (BFP_RND_TOWARD_0)));
- emit_label (label2);
- DONE;
- }
+ "!TARGET_Z196 && TARGET_HARD_DFP"
+{
+ rtx_code_label *label1 = gen_label_rtx ();
+ rtx_code_label *label2 = gen_label_rtx ();
+ rtx temp = gen_reg_rtx (TDmode);
+ REAL_VALUE_TYPE cmp, sub;
+
+ operands[1] = force_reg (TDmode, operands[1]);
+ decimal_real_from_string (&cmp, "9223372036854775808.0"); /* 2^63 */
+ decimal_real_from_string (&sub, "18446744073709551616.0"); /* 2^64 */
+
+ emit_cmp_and_jump_insns (operands[1],
+ const_double_from_real_value (cmp, TDmode),
+ LT, NULL_RTX, VOIDmode, 0, label1);
+ emit_insn (gen_subtd3 (temp, operands[1],
+ const_double_from_real_value (sub, TDmode)));
+ emit_insn (gen_fix_trunctddi2_dfp (operands[0], temp,
+ GEN_INT (DFP_RND_TOWARD_MINF)));
+ emit_jump (label2);
+
+ emit_label (label1);
+ emit_insn (gen_fix_trunctddi2_dfp (operands[0], operands[1],
+ GEN_INT (DFP_RND_TOWARD_0)));
+ emit_label (label2);
+ DONE;
})
-; fixuns_trunc(td|dd)si2 expander
-(define_expand "fixuns_trunc<mode>si2"
+; Just a dummy to make the code in the first expander a bit easier.
+(define_expand "fixuns_trunc<mode>si2_emu"
[(parallel
[(set (match_operand:SI 0 "register_operand" "")
(unsigned_fix:SI (match_operand:DFP 1 "register_operand" "")))
- (unspec:SI [(const_int DFP_RND_TOWARD_0)] UNSPEC_ROUND)
+ (unspec:DI [(const_int DFP_RND_TOWARD_0)] UNSPEC_ROUND)
(clobber (reg:CC CC_REGNUM))])]
- "TARGET_Z196 && TARGET_HARD_DFP"
- "")
+
+ "!TARGET_Z196 && TARGET_HARD_DFP"
+ {
+ FAIL;
+ })
+
; fixuns_trunc(tf|df|sf|td|dd)(di|si)2 instruction patterns.
-(define_insn "*fixuns_truncdfdi2_z13"
+; df -> unsigned di
+(define_insn "*fixuns_truncdfdi2_vx"
[(set (match_operand:DI 0 "register_operand" "=d,v")
(unsigned_fix:DI (match_operand:DF 1 "register_operand" "f,v")))
(unspec:DI [(match_operand:DI 2 "immediate_operand" "K,K")] UNSPEC_ROUND)
(clobber (reg:CC CC_REGNUM))]
- "TARGET_VX && TARGET_HARD_FLOAT"
- "@
- clgdbr\t%0,%h2,%1,0
- wclgdb\t%v0,%v1,0,%h2"
- [(set_attr "op_type" "RRF,VRR")
- (set_attr "type" "ftoi")])
+ "TARGET_VX && TARGET_HARD_FLOAT"
+ "@
+ clgdbr\t%0,%h2,%1,0
+ wclgdb\t%v0,%v1,0,%h2"
+ [(set_attr "op_type" "RRF,VRR")
+ (set_attr "type" "ftoi")])
+; (dd|td|sf|df|tf)->unsigned (di|si)
; clfebr, clfdbr, clfxbr, clgebr, clgdbr, clgxbr
; clfdtr, clfxtr, clgdtr, clgxtr
(define_insn "*fixuns_trunc<FP:mode><GPR:mode>2_z196"