![]() |
![]() 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.
|