Learn the PowerPC instruction on which this technique is based.
In IBM i, a space pointer is used to address bytes within a space. The addressability contained in a space pointer is the Single-Level Store (SLS) virtual address or the process-local Teraspace address stored in the 8-byte address portion. The distinguishing SLS addressing mechanism used by IBM i and its ancestors (AS/400 and System/38) is no doubt one of the cornerstones of the system. From the point of view of storage management, SLS is also the base of the object-based architecture of the system.
The huge SLS addressing space is divided into non-overlapping 16 MB segments. All Machine Interface (MI) objects are composed of one or more SLS segments. An associated space (either primary or secondary) of an MI object occupies one SLS segment. For programs running in the SLS storage model, program storage such as automatic storage frames, static storage frames, and heap storage are also composed of SLS segments. In a segmented addressing space, comparing two addresses in different segments to see which one is less or greater is obviously meaningless. So in ILE high-level languages (HLLs), how can we be sure that two space pointers do not address the same SLS segment?
The answer to this question might surprise you. In an ILE HLL program, to tell that two space pointers do not address the same SLS segment (I will refer to this condition as "UNEQ" in the remaining part of this article) look for the following:
- 1.The two space pointers address different SLS segments.
- 2.One of the space pointers addresses the SLS addressing space, while the other one does not (for example, addressing the Teraspace of an MI process or being a null pointer).
- 3.One of the space pointers addresses the Teraspace, while the other one does not (for example, addressing the SLS or being a null pointer).
You need to test for the following condition:
(pointer-A is NOT greater than pointer-B) AND (pointer-A is NOT less than pointer-B) AND (pointer-A is NOT equal to pointer-B) |
Say ptra@ and ptrb@ are two pointer variables used as space pointers within an ILE RPG program. The if statement to tell that ptra@ and ptrb@ do not address the same SLS segments should like the following:
if NOT (ptra@ > ptrb@) AND NOT (ptra@ < ptrb@) AND NOT (ptra@ = ptrb@); // ptra@ and ptrb@ do not address the same SLS segment endif; |
In IBM i and its ancestors, different types of pointers are the basic data types of the high-level Machine Interface of the system. The type of a pointer defines the capability that you have through it. For example, you can execute a program via a system pointer addressing the program object; however, you cannot access the contents of the program via the system pointer. In ILE HLL programs, a comparison of two pointers for the greater than (GT), less than (LT), or equal to (EQ) conditions are implicitly treated as the comparison of the addressability contained in these space pointers. (RPG pointer variables defined with the PROCPTR keyword are an exception.) In IBM i, the key PowerPC instruction used for the addressability comparisons is the CMPLA instruction (discussed later in this article), which possibly results in one of four mutually exclusive comparison results (negative (LT), positive (GT), equal (EQ), and Summary Overflow (SO)) to indicate the four possible relationships between the addresses (say, addr_a and addr_b):
- 1.LT—addr_a and addr_b address the same 16 MB segment (range from SID-000000 to SID-FFFFFF). addr_a is less than addr_b. Here, SID refers to the high-order 5 bytes of an 8-byte address, which is also the SLS segment identifier for an SLS address.
- 2.GT—addr_a and addr_b address the same 16 MB segment. addr_a is greater than addr_b.
- 3.EQ—addr_a and addr_b address the same 16 MB segment. addr_a is equal to addr_b.
- 4.UNEQ—addr_a and addr_b do not address the same 16 MB segment.
The following tiny ILE RPG example, cmpla01.rpgle, tests the relationship between the addressability stored in the two input space pointers and returns the comparison result via the 1-byte parameter rtn. The program logic to determine the UNEQ condition is the same as the above-shown RPG code.
d i_main pr extpgm('CMPLA01') d ptra@ * d ptrb@ * d rtn
d i_main pi d ptra@ * d ptrb@ * d rtn
STMT /free NUM: select; 16 when ptra@ > ptrb@; // GT 17 rtn = 'G'; 18 when ptra@ < ptrb@; // LT 19 rtn = 'L'; 20 when ptra@ = ptrb@; // EQ 21 rtn = 'E'; 22 other; // UNEQ 23 rtn = 'U'; 24 endsl;
26 *inlr = *on; /end-free |
Example programs written in ILE C, ILE CL, and ILE COBOL that implement the same program logic are available as cmpla02.c, cmpla03.clle, and cmpla04.cblle, respectively. ILE RPG program cmpla99.rpgle calls CMPLA01 through CMPLA04 to see whether it can detect the UNEQ condition successfully.
d pgms ds d d inz('CMPLA01 + d CMPLA02 + d CMPLA03 + d CMPLA04 ') d pgmarr d ptra@ s * d ptrb@ s * d rtn s d inx s 5u 0 d msg s
c cmpplist plist c parm ptra@ c parm ptrb@ c parm rtn
c exsr prep_ptr_uneq c for inx = 1 to 4 c eval rtn = *blank
c call pgmarr(inx) cmpplist c eval msg = pgmarr(inx) + rtn c msg dsply c endfor c c seton lr /free begsr prep_ptr_uneq; ptra@ = %addr(rtn); // ptra@ addresses the SSF ptrb@ = %alloc(1); // ptrb@ addresses the heap storage endsr; /end-free |
Note: Make sure CMPLA99 is compiled with parameter STGMDL(*SGNLVL) on V7R
Calling CMPLA99, the output might look like the following:
4 > CALL CMPLA99 DSPLY CMPLA01 U DSPLY CMPLA02 U DSPLY CMPLA03 U DSPLY CMPLA04 U |
Now we've proven the method to test for the condition that the addressability contained in two space pointers is not in the same SLS segment. If you are interested with why this technique works, please read on.
Analyze Addressability Comparisons in ILE HLL Programs at the RISC Instruction Level
The following are the PowerPC instructions generated (at V5R
RISC INSTRUCTIONS (CMPLA01) |
|||
Location |
Object text |
Source statement |
Pseudocode/Comments |
000570 000574 000578 000580 000584 000588 000590 000594 000598 0005B0 0005B4 0005B8 0005BC 0005CC 0005D0 0005D4 0005D8 0005DC ... 0006D4 |
E29E0206 7ABA E2DE 7AF E E2980006 7AB 7DB9B080 40EF0020 7B372720 40920014 7AD22720 29320009 7DB9B040 3B400001 418D0008 3B400000 2E 41920018 E25E01E6 3B 9B140000 480000FC E29E0206
|
LQ 20,0X200(30),6 SELRI 26,21,0,41 LQ 22,0X SELRI 24,23,0,41 LQ 18,0X0(26),6 SELRI 25,19,0,41 LQ 20,0X0(24),6 SELRI 22,21,0,41 CMPLA 3,25,22 BC 7,15,0X20 RLDICL 23,25,4,60 CMPLI 4,1,23,9 BC 4,18,0X14 RLDICL 18,22,4,60 CMPLI 2,1,18,9 BC 4,10,0X8 CMPL 3,1,25,22 ADDI 26,0,1 BC 12,13,0X8 ADDI 26,0,0 CMPI 4,1,26,0 BC 12,18,0X18 LQ 18,0X1E0(30),6 SELRI 20,19,0,41 ADDI 24,0,199 STB 24,0X0(20) B 0XFC LQ 20,0X200(30),6
ADDI 19,0,241 |
stmt_16: // when ptra@ > ptrb@;
// Load ptra@ [1] r25 = addr_a // [1.1] // Load ptrb@ [2] r22 = addr_b // Compare addr_a and addr_b using CMPLA [3] if NOT SO; then goto check_gt_cnd // [4] SO: r23 = bits 0-3 of addr_a // [4.SO] // Compare r23 with the immediate value 9 if addr_a is NOT Teraspace-addr; then goto check_gt_cnd r18 = high-order 4 bits of addr_b // Compare r18 with the immediate value 9 if addr_b is NOT Teraspace-addr; then goto check_gt_cnd cmp_tera_addrs: // [4.TS] Compare two Teraspace addresses using CMPL check_gt_cnd: r26 = 1 // [5] if CR3.GT is set; then goto end_stmt_16 r26 = 0 // CR3.GT is NOT set end_stmt_16: if r26 == 0, then goto stmt_18 // Not GT stmt_17: rtn = 'G' // The GT condition is met
goto stmt_26 // Branch to address stmt_26: *inlr = *on; stmt_18: // when ptra@ < ptrb@;
stmt_26: // *inlr = *on; |
Notes
[1] Load the 16-byte space pointer ptra@ into General Purpose Register (GPR) 18 and GPR 19 (r18, r19) via the IBM i-specific Load Quadwrod (LQ) instruction. The last operand (the PT field) of LQ is set to 6, which means that acceptable MI pointer types are the SLS space pointer and the Teraspace space pointer.
[1.1] If the previous LQ instruction succeeds, r25 is set to the value of r19 (the 8-byte address portion of space pointer ptra@); otherwise, r25 is set to the value zero.
[2] Load space pointer ptrb@ into r20 and r21. The 8-byte address portion of space pointer ptrb@ is copied to r22 if ptrb@ is a valid SLS or Teraspace space pointer.
[3] The CMPLA instruction compares the address portion of ptra@ (stored in r25) to the address portion of ptrb@ (stored in r22) and stores the comparison result in Condition Register (CR) field 3 (CR3). I failed to find the CMPLA instruction in public documentation of the PowerPC instruction set. I infer that CMPLA is an IBM i-specific PowerPC instruction. Experiments show that a CMPLA crfD,rA,rB instruction behaves similarly to a Compare Logical (CMPL) PowerPC instruction that does a 64-bit comparison—i.e., CMPLA crfD,1,rA,rB. It compares the contents of rA and rB as unsigned 64-bit integers and places the comparison result in CR field crfD. Bit 0, 1, or 2 of crfD is set when the comparison result is negative (LT), positive (GT), or equal (EQ), respectively. When the two 64-bit numbers stored in rA and rB are not in the same segmented
[4] The BC 7,15,0x20 instruction tests the SO bit of CR field 3 (CR3) (i.e., bit 15 of CR) and branches the execution to address 0005B4 (check-gt-cnd) if the SO bit of CR3 is not set.
[4.SO] If the SO bit of CR3 is set, addr_a and addr_b are checked for Teraspace address. If one of them is not a Teraspace address, execution will be branched to label check_gt_cnd. Since the LT, GT, EQ and SO conditions are mutually exclusive, at this time when the SO bit of CR3 is set, the GT bit of CR3 will not be set. Therefore, the following instructions will be executed sequentially and the execution will continue with the next comparison statement, statement 18 when ptra@ < ptrb@.
Location |
Object Text |
Source Statement |
Pseudocode/Comments |
0005B4 0005B8 0005BC ... 0005DC |
3B400001 418D0008 3B400000 2E 41920018
E29E0206 |
ADDI 26,0,1 BC 12,13,0X8 ADDI 26,0,0 CMPI 4,1,26,0 BC 12,18,0X18
LQ 20,0X200(30),6 |
check_gt_cnd: r26 = 1 // [5] if CR3.GT is set; then goto end_stmt_16 r26 = 0 // CR3.GT is NOT set end_stmt_16: if r26 == 0, then goto stmt_18 // Not GT
stmt_18: // when ptra@ < ptrb@; |
[4.TS] When both addr_a and addr_b are Teraspace addresses, they are compared as unsigned 64-bit integers using the CMPL instruction. The comparison result is also stored in CR3.
[5] The value of r26 is set to 1. The BC 12,13,0X8 instruction tests the GT bit of CR3 (bit 13 of CR). If the GT bit of CR3 is set (meaning the addressability contained in ptra@ is greater than the addressability contained in ptrb@), execution is in turn branched to labels end_stmt_16, stmt_17, and finally statement 26 *inlr = *on. If the GT bit of CR3 is not set, execution will be branched to label stmt_18 to process the next comparison statement, statement 18 when ptra@ < ptrb@.
The logic of the RISC instructions generated for the subsequent two comparison statements (when ptra@ < ptrb@ and when ptra@ = ptrb@) in cmpla01.rpgle are similar to those generated for the when ptra@ > ptrb@ statement—comparing addr_a and addr_b using CMPLA, then checking the LT and EQ condition. Since all possible result conditions (LT, GT, EQ, and SO) of CMPLA are mutually exclusive, when addr_a and addr_b and are not in the same SLS segment, none of the LT, GT, and EQ conditions (tested in statement 16, 18, and 20) will be met. So when all of the NOT LT, NOT GT, and NOT EQ conditions are met, we can be sure that addr_a and addr_b and are not in the same SLS segment.
Note that the RISC instructions generated for statement 16 of cmpla01.rpgle reveals that two Teraspace addresses are always treated as "in the same space" even though they do not address the Teraspace of the same MI process.
If you want a more elegant and efficient way to achieve the task of cmpla01.rpgle, consider the OMI Compare Pointer for Space Addressability (CMPPSPAD) instruction, an example of which is available as cmpla06.emi.
LATEST COMMENTS
MC Press Online