Posting this to replace a post I made, by accident only in the google-something
part of the list. Some editing, and additional examples.
MOVE PICS9-9 TO PICS9-8
D204 3010 3028 MVC 16(5,3),40(3) PICS9-8 PICS9-9
940F 3010 NI 16(3),X'0F' PICS9-8
F844 3010 3010 ZAP 16(5,3),16(5,3) PICS9-8 PICS9-8
MOVE PICS9-11 TO PICS9-9
F844 3028 3019 ZAP 40(5,3),25(5,3) PICS9-9 PICS9-11+1
MOVE PICS9-9-2 TO PICS9-9
D204 3028 3030 MVC 40(5,3),48(3) PICS9-9 PICS9-9-2
MOVE PICS9-8-2 TO PICS9-8
D204 3010 3020 MVC 16(5,3),32(3) PICS9-8 PICS9-8-2
Firstly, it is an Enterprise COBOL thing. From the "Enterprise COBOL for z/OS,
Version 3.4, Compiler and Runtime Migration Guide" (that's the first one that
came up, I'd suspect it is repeated in other Migration Guide):
"For example, Enterprise COBOL will not generate a negative zero result, while
OS/VS COBOL could"
It pre-dates Enterprise COBOL, and is introduced in VS COBOL II, due to
NUMPROC. Prior to COBOL II, all references to packed-decimal data involved
decimal instructions. With COBOL II, plain MVC and CLC area weapons of choice,
where possible/meaningful, over ZAP and CLC. The decimal compare, CP, treats
postive and negative zero as equal (treats them as zero). CLC does not (as it
doesn't know they are packed-decimal).
The "no negative zero" does not seem to be documented in anything to do with
COBOL II that I can find, and from the standard documentation set for COBOL
only appears in the Migration guides.
Enterprise COBOL has to ensure that a negative zero can never be a result of a
statement. There is no action in Enterprise COBOL that can result in a negative
zero (except see the list at the bottom).
From the POP for any decimal instruction which can cause an overflow:
"In the absence of overflow, the sign of a zero result is made positive. If
overflow occurs, a zero result is given the sign of the second operand but with
the preferred sign code."
A decimal instruction can't, except for overflow, produce a negative zero.
COBOL doesn't mind overflow. It is part of the language that a larger field
going to a smaller field is simply truncated.
Prior to COBOL II, with decimal instructions for packed-decimal fields, where
unproblematic overflow occured which happened to create a negative zero, it
didn't matter since a negative zero in a decimal instruction is just zero
anyway.
Now the actual generated code. Defining one field with 11 digits, two with nine
and two with eight:
1.
MOVE PICS9-9 TO PICS9-8
D204 3010 3028 MVC 16(5,3),40(3) PICS9-8 PICS9-9
940F 3010 NI 16(3),X'0F' PICS9-8
F844 3010 3010 ZAP 16(5,3),16(5,3) PICS9-8 PICS9-8
2.
MOVE PICS9-11 TO PICS9-9
F844 3028 3019 ZAP 40(5,3),25(5,3) PICS9-9 PICS9-11+1
3.
MOVE PICS9-9-2 TO PICS9-9
D204 3028 3030 MVC 40(5,3),48(3) PICS9-9 PICS9-9-2
4.
MOVE PICS9-8-2 TO PICS9-8
D204 3010 3020 MVC 16(5,3),32(3) PICS9-8 PICS9-8-2
In 2, a longer field is the source, and ZAP is used, and if the trunction of
the longer field happened to logically yield a negative zero, the ZAP would
present the result as a positive zero. If an MVC had been used, offset by one
byte, a ZAP-to-itself would have been needed to ensure the positive zero if
that had resulted in a negative zero. So cut to the chase, and just ZAP.
In 3, with two fields of the same size and an odd number of digits, an MVC is
possible and a ZAP not needed because there can be no truncation resulting in a
potential negative zero. There is a presumption that the source field is valid
(not negative zero already).
4 is similar to 3, just with an even number of digits. There is the same
presumption as in 3, and a further presumption that the leading nybble can only
be zero.
Now number 1, the original code in the question:
The MVC does nothing with packed-decimal signs, it is just copying a lump of
data.
The NI is indeed effecting truncation (nothing to do with compiler option TRUNC
in Enterprise COBOL, although a compiler option of the same name, many years
ago, was involved in that).
Source is a nine-digit-in-five-bytes. The code shown will ensure that the
8-digit-in-five-bytes receiving field will have a zero in the high-order nybble.
What about the ZAP? It is due to the potential for a negative-zero in the data
in the source field, which Enterprise COBOL must prevent from infecting the
result. If the source field was -900000000, then the MVC followed by the NI
would yield negative zero. So follow the MVC/NI with a ZAP.
You can't just ZAP then NI, because the potential -900000000 would become the
forbidden negative zero.
The ZAP after a decimal add, subtract, multiply or divide is interesting. It is
again there for the case of an overflow which has resulted in a negative zero
but I can't think why it is not preceded by a branch on condition for the
overflow value in the Condition Code.
Other points raised in the discussion:
Non-preferred signs going into ZAP (or any decimal instruction) will come out
as preferred signs (C or D). Looking at other code generated with
NUMPROC(NOPFD) may well show a number of ZAPs-to-itself to rectify the sign for
comparisons, for instance.
If the source has an invalid sign (0-9) a S0C7 will ensue.
If the source has a non-preferred sign, a preferred sign, equivalent, of
course, will be produced.
If the source is a negative zero, a positive zero will be produced, allowing a
CLC to be used, accurately, for comparisons for equality for packed-decimal
fields.
The code generated, in isolation at least, is not affected by compiler option
OPT, because it is an Enterprise COBOL thing. If it were not done, you get the
chance of a negative zero.
There is absolutely no difference in the procedure code generated by OPT(STD)
and OPT(FULL). The only "extra" in OPT(FULL) is the identification and removal
from the object of unreferenced storage items. If there are unused fields in
WORKING-STORAGE or LOCAL-STORAGE, the object will be smaller.
With Enterprise COBOL V5, which has three levels of optimsation (0, 1 and 2,
and yes, even 0 does some optimisations, clever, eh?) the FULL part of OPT up
to V4 is replaced by a new option, STGOPT.
Given all the above, what is the potential for any field containing a negative
zero? Date external to the program (file, DB, LINKAGE SECTION, message,
whatever), careless use of REDEFINES, careless use of group MOVEs. So something
to be aware of.
----------------------------------------------------------------------
For IBM-MAIN subscribe / signoff / archive access instructions,
send email to [email protected] with the message: INFO IBM-MAIN