HP OpenVMS Systemsask the wizard |
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.
|