;; Convert between floating point types of different sizes.
+;; At first glance, it would appear that emitting fnorm for an extending
+;; conversion is unnecessary. However, the stf and getf instructions work
+;; correctly only if the input is properly rounded for its type. In
+;; particular, we get the wrong result for getf.d/stfd if the input is a
+;; denorm single. Since we don't know what the next instruction will be, we
+;; have to emit an fnorm.
+
;; ??? Optimization opportunity here. Get rid of the insn altogether
;; when we can. Should probably use a scheme like has been proposed
;; for ia32 in dealing with operands that match unary operators. This
-;; would let combine merge the thing into adjacent insns.
+;; would let combine merge the thing into adjacent insns. See also how the
+;; mips port handles SIGN_EXTEND as operands to integer arithmetic insns via
+;; se_register_operand.
-(define_insn_and_split "extendsfdf2"
- [(set (match_operand:DF 0 "grfr_nonimmediate_operand" "=f,f,f,f,m,*r")
- (float_extend:DF
- (match_operand:SF 1 "grfr_nonimmediate_operand" "0,f,m,*r,f,f")))]
+(define_insn "extendsfdf2"
+ [(set (match_operand:DF 0 "fr_register_operand" "=f")
+ (float_extend:DF (match_operand:SF 1 "fr_register_operand" "f")))]
""
- "@
- mov %0 = %1
- mov %0 = %1
- ldfs %0 = %1%P1
- setf.s %0 = %1
- stfd %0 = %1%P0
- getf.d %0 = %1"
- "reload_completed"
- [(set (match_dup 0) (float_extend:DF (match_dup 1)))]
- "
-{
- if (true_regnum (operands[0]) == true_regnum (operands[1]))
- {
- emit_insn (gen_movdi (pic_offset_table_rtx, pic_offset_table_rtx));
- DONE;
- }
-}"
- [(set_attr "itanium_class" "unknown,fmisc,fld,tofr,stf,frfr")])
+ "fnorm.d %0 = %1"
+ [(set_attr "itanium_class" "fmac")])
-(define_insn_and_split "extendsftf2"
- [(set (match_operand:TF 0 "fr_nonimmediate_operand" "=f,f,f,f,Q")
- (float_extend:TF
- (match_operand:SF 1 "grfr_nonimmediate_operand" "0,f,Q,*r,f")))]
+(define_insn "extendsftf2"
+ [(set (match_operand:TF 0 "fr_register_operand" "=f")
+ (float_extend:TF (match_operand:SF 1 "fr_register_operand" "f")))]
""
- "@
- mov %0 = %1
- mov %0 = %1
- ldfs %0 = %1%P1
- setf.s %0 = %1
- stfe %0 = %1%P0"
- "reload_completed"
- [(set (match_dup 0) (float_extend:TF (match_dup 1)))]
- "
-{
- if (true_regnum (operands[0]) == true_regnum (operands[1]))
- {
- emit_insn (gen_movdi (pic_offset_table_rtx, pic_offset_table_rtx));
- DONE;
- }
-}"
- [(set_attr "itanium_class" "unknown,fmisc,fld,frfr,stf")])
+ "fnorm %0 = %1"
+ [(set_attr "itanium_class" "fmac")])
-(define_insn_and_split "extenddftf2"
- [(set (match_operand:TF 0 "fr_nonimmediate_operand" "=f,f,f,f,Q")
- (float_extend:TF
- (match_operand:DF 1 "grfr_nonimmediate_operand" "0,f,Q,*r,f")))]
+(define_insn "extenddftf2"
+ [(set (match_operand:TF 0 "fr_register_operand" "=f")
+ (float_extend:TF (match_operand:DF 1 "fr_register_operand" "f")))]
""
- "@
- mov %0 = %1
- mov %0 = %1
- ldfd %0 = %1%P1
- setf.d %0 = %1
- stfe %0 = %1%P0"
- "reload_completed"
- [(set (match_dup 0) (float_extend:TF (match_dup 1)))]
- "
-{
- if (true_regnum (operands[0]) == true_regnum (operands[1]))
- {
- emit_insn (gen_movdi (pic_offset_table_rtx, pic_offset_table_rtx));
- DONE;
- }
-}"
- [(set_attr "itanium_class" "unknown,fmisc,fld,frfr,stf")])
+ "fnorm %0 = %1"
+ [(set_attr "itanium_class" "fmac")])
(define_insn "truncdfsf2"
[(set (match_operand:SF 0 "fr_register_operand" "=f")