[an error occurred while processing this directive]

HP OpenVMS Systems

ask the wizard
Content starts here

Fortran floating-point condition handler?

» close window

The Question is:

 
Dear Wizard,
I'm trying to convert a conditional handler (in Fortran) from VAX to Alpha.
The VAX-code traps floating zero divide and sets the result to 0.0. How can
I do this on Alpha CPU's?
 
Here's the VAX-code:
 
        Integer*4       Function Cond_handl(SigArgs,MechArgs)
 
C       Condition handler for VAX FORTRAN
 
 
C          Floating Zero Divide ------ -0.0 -> 0.0
C          Reserved operand Fault ---- -0.0 -> 0.0
 
 
	Implicit	None
	Include	 '($SSDEF)'
	Include	 '($LIBDCFDEF)'
 
	Integer*4	SigArgs(1:*)
     $       ,MechArgs(1:*)
 
	Integer*4	Lib$Fixup_Flt
     $       ,Lib$Decode_Fault
 
	External	 Fix_Zero_Divide
 
	If (SigArgs(2).eq.SS$_FLTDIV_F .or.
     $       SigArgs(2).eq.SS$_FLTDIV) Then
           Cond_Handl = LIB$DECODE_FAULT(SigArgs,
     $          MechArgs,
     $          %Descr(Fix_Zero_divide))
	Else If (SigArgs(2).eq.SS$_ROPRAND) Then
           Cond_handl = Lib$Fixup_Flt(SigArgs,MechArgs,)
	Else
           Cond_handl = SS$_Resignal
	End If
 
	Return
	End
 
C===========================================================================
===
 
C	       Action routine taking care of "floating zero divide"
 
C===========================================================================
===
 
      Integer*4       Function Fix_zero_divide(OpCode,Instr_Pc,Psl,
     $     Registers,Op_Count,
     $     Op_Types,Read_Ops,
     $     Write_Ops,SigArgs,
     $     Signal_Rout,Context,
     $     User_arg,Orig_Registers)
 
C       User action routine to handle special faults
 
C	     Floating zero divide ---------- -0.0 -> 0.0
 
      Implicit None
      Include '($SsDef)'
      Include '($PslDef)'
      Include '($LibDcfDef)'
 
      Integer*4	OpCode
     $     ,Instr_Pc
     $     ,Psl
 
      Integer*4	Registers(0:15)
     $     ,Op_Count
     $     ,Op_Types(1:*)
     $     ,Read_Ops(1:*)
     $     ,Write_Ops(1:*)
     $     ,SigArgs(1:*)
     $     ,Signal_rout
     $     ,Context
     $     ,User_arg
     $     ,Orig_Registers(0:15)
 
      Integer*4	Result_operand
     $     ,Op_DType
     $     ,Op_Size
 
      Byte	    Op_Sizes(9)
      Data    Op_Sizes	/0,0,0,0,0,4,8,8,16/
 
      Integer*2	Zero   (8)
      Data	     Zero   /8*0/
 
 
C --- Get Resultant operand
 
      Result_operand = Op_Count
 
C --- Get resultant operand datatype
 
      Op_DType = IBITS(Op_Types(2),LIB$V_DCFTYP,LIB$S_DCFTYP)
 
C --- Get resultant operand size
 
      Op_Size = Op_Sizes(Op_DType)
 
C --- Clear Resultant operand
 
      Call Lib$MOVC3(OP_Size,Zero,%Val(Write_Ops(Result_Operand)))
 
C --- Clear C Bit
 
      Psl = IBCLR(Psl,PSL$V_C)
 
C --- Return Status and control to LIB$DECODE_FAULT
 
      Fix_Zero_Divide = SS$_Continue
      Return
      End
 
TIA
 
Best regards / pa
 
 


The Answer is :

 
  If you require VAX format floating points (F-float, D-float or G-float),
  then this requirement is not particularly efficient on an OpenVMS Alpha
  system -- Alpha systems achieve additional performance by explicitly and
  deliberately not providing (by default) precise reporting of various
  floating point error conditions.  The most efficient method is to have
  the compiler produce floating instructions modified by the /S qualifier
  -- current Compaq compilers only support this option for IEEE format
  floating point formats (S-float or T-float).  There is no compiler
  support for the instruction-level /S mode with VAX format floating
  point instructions.
 
  In the case of /S modified floating point instructions, a divide-by-zero
  exception is a FAULT, with the PC pointing at the DIVS/SU or DIVT/SU
  instruction that cause the exception.  To handle this, you can examine
  the divide instruction at the return PC, decode the result register,
  zero that register in the context block, increment the return PC by 4,
  and then continue.
 
  If you must use VAX format floating point, then you can consider using
  the synchronous exception qualifier to the compiler.  This should put a
  TRAPB following every floating point instruction which will make
  divide-by-zero look like a synchronous trap.  When a divide-by-zero
  TRAP occurs, decode the result register of the instruction at return
  PC - 4, zero that register in the context block, and then continue
  from the return PC.  TRAPB instructions can cause performance problems
  on older Alpha implementations, but are rather less expensive on EV6
  (21264) systems.
 
  In addition, you can use /IEEE_MODE=UNDERFLOW_TO_ZERO to cause the
  divide-by-zero to return zero.  This does not change the results of the
  divide-by-zero exceptions, but it does have the side effect of causing
  other floating exceptions be signaled as faults, rather than traps.
  When the exception is a fault (or the special case of a synchronous
  trap), then the methods above can be used.
 
  Another approach is also possible, but is not generally recommended.
  If you are willing to write a program that runs specifically only on
  the EV6 (21264) implementation and not on other Alpha microprocessor
  members (also following the Alpha architecture), then you can use the
  synchronous exception method described above without using the
  synchronous exception qualifier to the compiler.  The EV6 implementation
  has specifically chosen to make all floating point exceptions result in
  synchronous traps.  There is emphatically no promise that future Alpha
  microprocessors or Alpha systems will also provide this.
 
  To understand the tradeoffs involved here, you must realize the difference
  between a "fault", a "trap", and a "synchronous trap".  You must further
  realize that different Alpha implementations will make different choices
  here -- the lattermost approach may or may not work on other Alpha
  microprocessor implementations, and cannot be depended to be available
  across all Alpha microprocessors, nor to continue to work on future
  generations of Alpha microprocessors.
 
  In both Compaq C and Fortran, the /S instruction trap qualifier is
  controlled by the /IEEE_MODE compiler qualifier.
 
    FAST   generates no instruction trap mode qualifier, or the /U
           instruction trap mode, depending various other compiler
           command line qualifiers.
 
           During program execution, only finite values (no infinities,
	   NaNs, or denorms) are created.  Exceptional conditions, such
	   as floating point overflow and divide by zero, are fatal.
 
    UNDERFLOW_TO_ZERO
    DENORM_RESULTS
           generates the /SU instruction trap mode qualifier on IEEE
           floating point instructions.  This is the best and most
           likely keyword to use on the compilation when using the
	   techniques described above.
 
           UNDERFLOW_TO_ZERO generate infinities and NaNs.  Flush
           denormalized results and underflow to zero without
	   exceptions.  DENORM_RESULTS is the same, save that
           denorms are generated.
 
    INEXACT
           generates the /SUI instruction trap mode qualifier on IEEE
           floating point instructions.  The OpenVMS Wizard strongly
	   recommends you do not use this keyword.  (This qualifier
           is not documented for Fortran.)
 
           This is the same as DENORM_RESULTS, except that inexact
           values are trapped.  This is the slowest mode.

answer written or last revised on ( 17-NOV-1999 )

» close window