This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

IA-64 patch for problem with casting FP denorms to larger FP type


This fixes PR 2498.

The getf and stf instruction require that inputs be correctly rounded for
their type, and hence we can't optimize away float extend operations the way
we were previously doing it.  This problem shows up best when denormalized
numbers are present, as in PR 2498.  This patch fixes the problem by removing
the bad optimization, and just always emitting a fnorm instruction for
float extend operations.

This was tested with an ia64-linux bootstrap and testsuite run.  As previously
mentioned, libstdc++ fails to build, but that is unrelated to this patch.

This patch has been added to both the trunk and the gcc3 branch.

2001-04-11  Jim Wilson  <wilson@redhat.com>

	* config/ia64/ia64.md (extendsfdf2, extendsftf2, extenddftf2): Simplify
	to just emit an fnorm.

Index: ia64.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/ia64/ia64.md,v
retrieving revision 1.61
diff -p -r1.61 ia64.md
*** ia64.md	2001/03/28 21:55:09	1.61
--- ia64.md	2001/04/11 23:30:06
***************
*** 821,900 ****
  
  ;; Convert between floating point types of different sizes.
  
  ;; ??? 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.
  
! (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")))]
    ""
!   "@
!    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")])
  
! (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")))]
    ""
!   "@
!    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")])
  
! (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")))]
    ""
!   "@
!    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")])
  
  (define_insn "truncdfsf2"
    [(set (match_operand:SF 0 "fr_register_operand" "=f")
--- 821,860 ----
  
  ;; 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.  See also how the
! ;; mips port handles SIGN_EXTEND as operands to integer arithmetic insns via
! ;; se_register_operand.
  
! (define_insn "extendsfdf2"
!   [(set (match_operand:DF 0 "fr_register_operand" "=f")
! 	(float_extend:DF (match_operand:SF 1 "fr_register_operand" "f")))]
    ""
!   "fnorm.d %0 = %1"
!   [(set_attr "itanium_class" "fmac")])
  
! (define_insn "extendsftf2"
!   [(set (match_operand:TF 0 "fr_register_operand" "=f")
! 	(float_extend:TF (match_operand:SF 1 "fr_register_operand" "f")))]
    ""
!   "fnorm %0 = %1"
!   [(set_attr "itanium_class" "fmac")])
  
! (define_insn "extenddftf2"
!   [(set (match_operand:TF 0 "fr_register_operand" "=f")
! 	(float_extend:TF (match_operand:DF 1 "fr_register_operand" "f")))]
    ""
!   "fnorm %0 = %1"
!   [(set_attr "itanium_class" "fmac")])
  
  (define_insn "truncdfsf2"
    [(set (match_operand:SF 0 "fr_register_operand" "=f")


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]