Using inline assembly with IBM XL C/C++ compiler for Linux on z Systems, Part 1
Primer
Assembler instructions for embedding applications on mainframe computers
Content series:
This content is part # of # in the series: Using inline assembly with IBM XL C/C++ compiler for Linux on z Systems, Part 1
This content is part of the series:Using inline assembly with IBM XL C/C++ compiler for Linux on z Systems, Part 1
Stay tuned for additional content in this series.
IBM XL C/C++ compiler for Linux on z Systems Version 1, released in 2015, enables support for incorporating user's assembler codes directly into C/C++ programs (inline assembly). Besides the ability to generate highly optimized codes, maximizing hardware utilization, the new compiler provides advanced users with greater flexibility to access instructions at chip level. With inline assembly, software engineers are able to handcraft assembler codes for the most performance-sensitive parts of C/C++ programs. This will further accelerate the execution of the applications to the full extent of the programmers' ingenuity.
In this series
Articles included in this series:
- Part 1: Primer: Assembler instructions to be embedded in C/C++ applications on mainframe computers
- Part 2: Accelerate performance
- Part 3: Basic features
- Part 4: Advanced features
See descriptions of all four parts of this series.
Registers
There are 16 general registers, identified by numbers 0 to 15, each of which contains 64 bit positions. With the exception of general register 0, which cannot be designated as containing base address or index, general registers 1 to 15 can be used as base address registers and index registers in address arithmetic operations. In general arithmetic and logical operations, general registers can be used as accumulators. Designated usage of some general registers of z Systems running Linux are listed in Table 1.
Table 1: Designated usage of general registers on Linux on z Systems
Register name | Special usage |
---|---|
r2, r3 | Parameters, return values |
r4, r5, r6 | Parameters |
r13 | Base register for literal pool |
r14 | Return address |
r15 | Stack pointers |
General registers 0 to 15 will be regarded to as r0 to r15. There are instructions, such as multiply (MR
) and divide (DR
), requiring two adjacent general
registers to be coupled into an operand. In these operations, the program must designate an even-odd pair of general registers. The operand of the register pair is specified with the
even-numbered register. Figure 1 shows how the general registers are represented individually and in pairs.
Figure 1: Designation of 16 general registers, individually and in pairs

In addition to general registers, floating-point registers and vector registers are used by inline assembly. They will be described in detail in the subsequent articles about inline assembly with floating-point registers and vector registers.
Condition code
Condition code (cc) consists of bits 18 and 19 of the program status word (PSW) in the processor. Being a 2-bit value, cc can be set to 0, 1, 2, or 3, depending on the results obtained from executing certain instructions. Once set, cc remains unchanged until it is modified by another instruction. Most arithmetic and logical operations, as well as some other operations, set the cc. Execution-branching instructions can specify a selection of the cc values as a criterion for branching.
The snippet in Listing 01 demonstrates a usage of the cc at high level. Detail about inline assembly formats will be described in the next article about inline assembly for general instructions.
Listing 1: BRC and condition code
1 #include <stdio.h> 2 3 void myAdd(int a, int b) { 4 int noOverflow = 1; 5 asm("AR %0, %2\n" // If an overflow occurs, AR will set cc to 3 6 "BRC 0xE, OK\n" // BRC inspects cc: if it is not 3 (no overflow), branch to line 8, that is, skip line 7 7 "XR %1, %1\n" // XR unsets noOverflow variable 8 "OK:\n" 9 : "+r"(a), "+r"(noOverflow) 10 : "r"(b) 11 : "cc" // cc in the clobber list to inform the compiler that condition 12 ); // code might be changed by the assembler instructions 13 if (noOverflow){ 14 printf ("Sum is %d\n", a); 15 } else { 16 printf ("Overflow\n"); 17 } 18 } 19 int main() { 20 int a, b; 21 a = 11, b = -2; // With a=11, b= -2, no overflow will occur, 22 myAdd(a, b); // "Sum is 9" will be printed out 23 a = 0x7fffffff, b = 0x7fffffff; // a and b are set with large values to cause overflow 24 myAdd(a, b); // Overflow will occur. "Overflow" will be printed out 25 return 0; 26 }
%0, %1 and %2
refer to the first (variable a), second (variable noOverflow) and third operand (variable b) in lines 9
and 10.
The ADD (AR
) instruction on line 5 sets the condition code as follows:
0 | Result of the addition is zero. No overflow |
1 | Result is less than zero. No overflow |
2 | Result is greater than zero. No overflow |
3 | Overflow occurs |
The value of the cc will be inspected by the branch on condition (BRC
) instruction on line 6 to determine the subsequent path of execution. If the cc is 0, 1 or 2
(that is, no overflow), execution will branch to label "OK" on line 8, effectively skipping the exclusive OR (XR
) instruction on line 7. If cc is 3 (that
is, overflow did occur), the execution will continue with the next instruction on line 7; the XR
instruction unsets the value of the noOverflow
variable.
The code in Listing 1 prints out the sum when there was no overflow and displays "Overflow" when overflow did occur.
Listing 2: Compiling and running the program in Listing 1
$ xlc -o ex1 ./example01.c $ ./ex1 Sum is 9 // Result of 11 + (– 2) Overflow // Overflow caused by adding a = 0x7fffffff to b = 0x7fffffff
For information about the condition-code values that may be set for all instructions, refer to the documents included with the system. In particular, a link to Appendix C. Condition-Code Settings of the book z/Architecture Principles of Operation, IBM Publication No. SA22-7832-10.
Assembler instructions
The general instructions operate on data stored in general registers and in storage. Other general instructions work with data residing in the PSW, time-of-day clock or coming from the instructions stream. Some instructions include character(s) with their names to indicate the length of the operands such as H (halfword) for 16-bit, F (word) 32-bit and G (doubleword) 64-bit. When the operands of an instruction are 32-bit long, the instruction name might or might not contain the letter F. If there is an instruction with the same name but with 64-bit operands, its name will include the letter G. An instruction with the same name but with a 64-bit first operand and a 32-bit second operand will have the letters GF in its name. For complete description of each instruction, refer the documents accompanying the system.
For the ease of discussion, assembler instructions in this article are categorized into loosely-defined groups. The article only focuses on some general instructions that are most likely used by software engineers. You can find an exhaustive list of assembler instructions in the References section.
Group of algebraic arithmetic instructions
These instructions perform algebraic operations on the operands. Operands of arithmetic operations can be a single register, a memory address, or an immediate value. In cases when there are two operands, the operation is applied on both operands, but the results are saved back in the first one. Accordingly, the instruction performs both READ and WRITE operations on the first operand.
For many algebraic arithmetic instructions, the condition code will be set as follows:
0 | Result of the operation is zero. No overflow |
1 | Result is less than zero. No overflow |
2 | Result is greater than zero. No overflow |
3 | Overflow occurs |
The following section will discuss some formats, which might be used more frequently.
OP R1, R2: Register-and-register
format
The value saved in the register specified by the second operand, R2 is used to perform operations, such as add, subtract, multiply, or divide
with the value currently stored in the register identified by the first operand, R1. The result of the operation is then saved in the first operand,
R1.R1 ← R1 OP R2
OP R1, I2: Register-and-immediate
format
The immediate value specified by the second operand I2 is used to perform the required operation to the value currently stored in the register
identified by the first operand, R1. The result of the operation is then saved in the first operand,
R1.R1 ← R1 OP I2
OP R1,
D2 (X2,B2):
Register-and-storage format
The value saved in the effective address specified by the second operand is used to perform the required operation with the value
currently stored in the register identified by the first operand, R1. The result of the operation is then saved in the first operand,
R1.R1 ← R1 OP [value-stored-in-effective-address D2 (X2,B2)]
The effective address in operand two is computed as follows:
D2: the displacement from the base address + B2: the base address + X2: the index to the base address
Example of algebraic arithmetic instructions
Assembler instructions can be embedded into a program by either (1) adding them directly to assembler codes or (2)
using inline assembly with the C/C++ codes. This section will demonstrate how to insert an algebraic arithmetic instruction named Add halfword (AH
) into a C program.
AH
instruction algebraically adds the contents of a two-byte field (halfword), which is in the storage specified by the second operand, to the contents of the
first-operand register. The result is then stored in the first-operand register. The snippet in Listing 3 is a C program before asm
instructions are inserted.
Listing 3: C program example02.c before inserting asm instructions
1 #include <stdio.h> 2 int main() { 3 int a = 0; 4 int ar[] = {0x00112233, 0x44556677}; 5 printf ("a = 0x%08x, ar[0] = 0x%08x, ar[1] = 0x%08x\n", a, ar[0], ar[1]); 6 return 0; 7 }
In the runtime, example02.c prints out the values of a, ar[0], and ar[1], as exhibited in Listing 4.
Listing 4: Compiling and running example02.c
$ xlc -o ex2 ./example02.c $ ./ex2 a = 0x00000000, ar[0] = 0x00112233, ar[1] = 0x44556677
The aim in this example is to insert AH
instruction into the code so that it will add the two-byte value stored at address of ar to the value of
a. Since the two-byte value stored at ar is 0x0011 and the current value of a is 0x0, the expected value of a
after the operation is 0x11.
(1) Injecting AH instruction manually to the Assembler code
The assembler file named example02.s is produced by compiling
example02.c with –S.
$ xlc example02.c –c –S
The most important contents of the assembler code example02.s are listed in Listing 5.
Listing 5: Contents of assembler file example02.s before inserting assembler instructions
.L_main: 1 STMG %r13,%r15,104(%r15) 2 LARL %r13,$CONSTANT_AREA 3 LAY %r15,-184(,%r15) # Reserve 184 bytes on the stack; r15 to hold the top of the stack 4 MVHI 176(%r15),0 # Move 0 (value of a) to bytes 176 → 179 from r15 5 MVHHI 168(%r15),17 # Bytes 168 →169 from r15 hold 0x00 and 0x11 (which is 1710) 6 MVHHI 170(%r15),8755 # Bytes 170 →171 from r15 hold 0x22 and 0x33 (which is 875510) 7 MVHHI 172(%r15),17493 # Bytes 172 →173 from r15 hold 0x44 and 0x55 (which is 1749310) 8 MVHHI 174(%r15),26231 # Bytes 174 →175 from r15 hold 0x66 and 0x77 (which is 2623110) LA %r2,16(,%r13) # Load parameters for printf LGF %r3,176(,%r15) LGF %r4,168(,%r15) LGF %r5,172(,%r15) BRASL %r14,printf # Call printf
On lines 4 to 8, the stack is populated with values of a (which is 0), ar[0] (which is 0x00112233), and ar[1] (which is 0x44556677).
Figure 2 is a visual representation of the stack after the execution of line 8. From line 9, the program prepares the parameters to be passed to printf
.
Function printf
is then called with BRASL
instruction.
Figure 2: Values on the stack after the execution of line 8

To achieve the expected results, AH
instructions (Register-and-storage format) must be added to example02.s in the location just
before the program starts preparing parameters for printf
. In particular, it will be inserted as in Listing 6.
Listing 6: Inserting assembler instructions to assembler file example02.s
.L_main: 1 STMG %r13,%r15,104(%r15) 2 LARL %r13,$CONSTANT_AREA 3 LAY %r15,-184(,%r15) # Reserve 184 bytes on the stack, r15 to hold the top of the stack 4 MVHI 176(%r15),0 # Move 0 (value of a) to bytes 176 → 179 from r15 5 MVHHI 168(%r15),17 # Bytes 168 →169 from r15 hold 0x00 and 0x11 (which is 1710) 6 MVHHI 170(%r15),8755 # Bytes 170 →171 from r15 hold 0x22 and 0x33 (which is 875510) 7 MVHHI 172(%r15),17493 # Bytes 172 →173 from r15 hold 0x44 and 0x55 (which is 1749310) 8 MVHHI 174(%r15),26231 # Bytes 174 →175 from r15 hold 0x66 and 0x77 (which is 2623110) 9 LA %r1,168(,%r15) # Load address of array ar on the stack to r1 10 L %r0,176(,%r15) # Load value of a (bytes 176 → 179 from r15) to r0 11 AH %r0, 0(%r1) # Add 2-byte stored in displacement 0 from address of ar (r1) to r0 12 ST %r0,176(,%r15) # Results of AH in r0 is stored back to a (bytes 176 → 179 from r15) LA %r2,16(,%r13) # Load parameters for printf LGF %r3,176(,%r15) LGF %r4,168(,%r15) LGF %r5,172(,%r15) BRASL %r14,printf # Call printf
AH
needs to know the address of ar so that it can read two bytes in the location. It also requires the current value in a to perform the
addition. Lines 9 to 10 are added to help prepare the information for AH.
- Line 9:
LA
loads address of ar to r1. - Line 10:
L
loads current value of a to r0. - r0 and r1 are then used by
AH
on line 11.
On line 11, AH
performs the following operations:
- Retrieving the two-byte value stored in displacement 0 from address of ar
Since ar ={0x00112233, 0x44556677}, the two bytes at its displacement 0 form 0x0011. - Adding the two-byte value to the content of r0
Since r0 at this moment holds value of a, which is 0, the sum will be 0x11. - Putting the results back to r0: Thus r0 will hold value 0x11.
After the execution of AH
on line 11, r0 will hold the new value. The result will be stored back to a by ST
instruction on line
12.
The result of inserting assembler instructions AH
and others on lines 9 to 12 can be verified by compiling the edited assembler code and executing the new executable.
Listing 7: Compiling and executing the edited assembler codes
$ xlc -o ex2_new ./example02.s $ ./ex2_new a = 0x00000011, ar[0] = 0x00112233, ar[1] = 0x44556677 → a is 0x11, as expected
(2) Using inline assembly to embed AH
instruction to the C code
Inline assembly provides a vehicle to achieve equivalent result to the
above with much less effort.
Listing 8: Inserting inline asm statement to C file example02.c
1 #include <stdio.h> 2 int main() { 3 int a = 0; 4 int ar[] = {0x00112233, 0x44556677}; 5 asm( "AH %0, %1" : "+r"(a) : "m"(ar[0]) ); // AH is inserted here 6 printf ("a = 0x%08x, ar[0] = 0x%08x, ar[1] = 0x%08x\n", a, ar[0], ar[1]); 7 return 0; 8 }
Inline assembly only requires the user to add the main instruction (AH
, in this case). It leaves the burden of adding supporting operations such LOAD ADDRESS
,
LOAD
, and STORE
on lines 9, 10 and 12 with the compiler. Using inline assembly within the C code in this manner should produce the same output at
execution.
Listing 9: Compiling and executing the new C file with inline assembly
$ xlc -o ex2_asm ./example02_asm.c $ ./ex2_asm a = 0x00000011, ar[0] = 0x00112233, ar[1] = 0x44556677 → a is 0x11, as expected
The inline assembly instruction in this example makes use of the memory constraint, which will be discussed in subsequent article about Linux on z Systems inline assembly.
Group of Compare instructions
When there are two operands, instructions in this group compare the first operand with the second operand. The result of the comparison is recorded in the condition code as follows:
0 | Two operands are equal |
1 | The first operand is less than the second one |
2 | The first operand is more than the second one |
3 | Not applicable |
COMP R1, R2: Register-and-register
format
The value saved in the register specified by the second operand, R2 is compared with the value currently stored in the register identified by
the first operand, R1.
COMP R1, I2: Register-and-immediate
format
The immediate value specified by the second operand I2 is compared with the value currently stored in the register identified by the first
operand, R1.
COMP R1,
D2 (X2,B2):
Register-and-storage format
The value saved in the effective address specified by the second operand is compared with the value currently stored in the
register identified by the first operand, R1.
COMP D1(B1),
I2: Storage-and-immediate format
The immediate value specified by the second operand
I2 is compared to the value saved in the effective address specified by the first operand.
Example of Compare instructionsCH 5, 0x30 (0, 9)
The Compare halfword (CH
) instruction compares a 16-bit signed integer (halfword) in
storage with the contents of a register. CH
treats the first operand as a 32-bit signed integer; the displacement is treated as a 12-bit unsigned integer.
In this example, the state before the operation is assumed as follows:
Table 2: Values in registers and memory locations before CH is called
Symbols in Op code OP R1, D2(X2,B2) | Assembler format CH 5, 0x30 (0, 9) | Meaning | Contents | ||
---|---|---|---|---|---|
OP R1 D2 X2 B2 | CH 5 0x30 0 9 | Compare Halfword Register 5 Displacement Index 0 Register 9 | 0xFFFF 9000 = – 2867210 0x30 0x0 0x00012050 | ||
Storage location 12080 – 12081 | 0x9000 = – 2867210 |
The effective address is: B2 + X2 + D2 = 0x00012050 + 0x0 + 0x30 = 0x00012080.
The value of 2 bytes stored in address location 12080 is 0x9000 or –
2867210.
The content in register 5 is 0xFFFF 9000 or – 2867210.
Since the two numbers are equal, condition code 0 is set.
Again, instead of computing the effective address directly as above, inline assembly provides memory constraints, which can significantly simplify the process.
Group of branch on condition instructions
Branch on condition instruction inspects the condition code in the current PSW. If the condition code has one of the values specified by the mask, the "next instructions address" in the PSW will be replaced by the branch address stipulated in the branch instruction. Otherwise, normal instruction sequencing proceeds.
The branch on condition instructions do not change the condition code.
BC M1, R2: Register-and-register
format
If the condition code has one of the values specified by the mask M1, the execution is branched to the address stored in the general register
stipulated by the second operand, R2.
BC M1,
D2 (X2,B2):
Register-and-storage format
If the condition code has one of the values specified by the mask M1, the execution is branched to the address computed
based on D2, X2, and
B2.
The mask
The M operand is a four-bit mask. The four condition codes (0, 1, 2, and 3) correspond with the four bits of the mask as follows:
Table 3: Relationship between condition code and mask
2-bit condition code | 4-bit mask | Mask value | |||
---|---|---|---|---|---|
002 or 010 | 1 | 0 | 0 | 0 | 0x8 |
012 or 110 | 0 | 1 | 0 | 0 | 0x4 |
102 or 210 | 0 | 0 | 1 | 0 | 0x2 |
112 or 310 | 0 | 0 | 0 | 1 | 0x1 |
The expected condition code is the criterion to select the corresponding mask bit. If the mask bit selected by the condition code is one, the branch will be successful. Otherwise, normal instruction sequencing proceeds. As described in Listing 1, in order to branch only when the condition code is not equal to 3, or equivalently when the condition code is any of {0, 1, 2}, the mask must be 11102 or 0xE in hexadecimal representation.
When all four mask bits are zeros, or when R2 operand holds zero, the branch instruction is equivalent to a no-operation. Similarly, if the mask is 11112, the
branch is unconditional unless R2 is zero. Execution of BCR
15, 0 may results in significant performance degradation.
Example of BRC instructions
The following function absoluteValue takes an integer and returns the absolute value of an integer. Obviously, it can be as trivial as
int absoluteValue(int a) { return a < 0 ? –a : a; }
In this example, however, it is crafted with Compare and BRC instructions to demonstrate how the instructions are used together with the condition code and the mask.
Listing 10: Inline assembly statements using Compare and Branch instructions
1 int absoluteValue(int a) { 2 asm (" CFI %0, 0\n" // Compare value of a with 0 3 " BRC 0xA, DONE\n" // If a >= 0, go to DONE i.e. skip line 4 4 " LCR %0, %0\n" // Coming here means a <0, load-complement a to negate it 5 " DONE:\n" 6 :"+r"(a) 7 ); 8 return a; 9 }
%0
refers to the first operand of the inline assembly statement: variable a.
On line 2, a is compared against zero. As described in the Group of Compare instructions section CFI
instruction sets condition code in PSW as follows:
Table 4: Relationship between cc and mask
Compare a against 0 | Condition code | Mask bits |
---|---|---|
a = 0 | 0 = 002 | 1000 |
a < 0 | 1 = 012 | 0100 |
a > 0 | 2 = 102 | 0010 |
The logic in function absoluteValue(int a) dictates that it return a if a is equal to or greater than 0. This is equivalent to the condition code being set to either 0 or 2. The corresponding mask pattern for these cases is 1010 (that is, 0xA in hexadecimal).
BRC on line 3 checks if the current condition code in PSW matches the mask 0xA. If there is a match, it will branch to label DONE on line 5, effectively making it ready for the function to return a without modification. Following this path, absoluteValue(int a) returns a if a >= 0.
If BRC finds no match on line 3, load complement (LCR) instruction on line 4 is executed. LCR
loads the two's complement of the second operand (variable
a) in the first-operand location (variable a, itself), effectively negating the value of a. Following this path, the function
will return –a when a is negative.
To maximize the performance of their programs, software engineers can select the optimal instructions from a great wealth of assembler instructions on z Systems. For example, the above function can be written differently to achieve higher performance such as in Listing 12 below.
Group of Load instructions
When there are two operands, Load instructions place the second operand, unchanged or sign-extended, in the first-operand location.
The direction of the operation is
Operand1← Operand2.
L R1, R2: Register-and-register
format
The value saved in the register specified by the second operand, R2 is placed, unchanged or sign-extended, in the register identified by the
first operand, R1.
L R1, I2: Register-and-immediate
format
The immediate value specified by the second operand I2 is placed, unchanged or sign-extended, in the register identified by the first operand,
R1.
L R1,
D2 (X2,B2):
Register-and-storage format
The value saved in the effective address specified by the second operand is placed, unchanged or sign-extended, in the register
identified by the first operand, R1.
Example of Load instructions
The function absoluteValue mentioned in Example of BRC instructions can be
modified slightly to demonstrate the usage of load instructions.
Listing 11: Example of load instruction
1 int absoluteValue(int a) { 2 asm (" LTR %0, %0\n" // Load and test value of a 3 " BRC 0xA, DONE\n" // If a >= 0, go to DONE i.e. skip line 4 4 " LCR %0, %0\n" // Coming here means a < 0, load-complement a to negate it 5 " DONE:\n" 6 :"+r"(a) 7 ); 8 return a; 9 }
On line 2, load and test (LTR
) instruction performs two operations:
- Placing the second operand unchanged in the first operand location.
- Updating the condition code based on the loaded value.
0 | The loaded value is zero |
1 | The loaded value is less than zero |
2 | The loaded value is greater than zero |
3 | Not applicable |
Since both operands are the same register holding variable a, LTR
on line 2 is equivalent to a test whether a is less than, equal
to or greater than 0 without moving data.
On line 3, BRC
inspects if the current condition code matches the mask 0xA. If there is a match (that is, a >= 0), it will branch to label DONE
on line 5, and thus the function to return a without modification. Otherwise (that is, a < 0), LCR
on line 4 will
load the two's complement of a to negate its value. The function thus returns –a.
This very same function can be written with different assembler instructions to achieve higher performance. In the next example, a single LOAD
instruction will replace
those two LOAD
instructions, one BRANCH
instruction and a LABEL
.
Listing 12: Using a different asm instruction
1 int absoluteValue(int a) { 2 asm (" LPGFR %0, %0\n" :"+r"(a) ); // Load-Positive a 3 return a; }
LPGFR
instruction loads the absolute value of the second operand in the first operand. Since both the operands are variable a, the instruction effectively
performs the assignment a = | a |. The functions can return the expected value after LPGFR
.
Group of Store instructions
When there are two operands, store (ST
) instructions place the first operand in the second-operand location.
The direction of the operation is Operand1→ Operand2.
ST R1,
D2 (X2,B2):
Register-and-storage format
The value saved in the first operand, R1 is placed unchanged to the effective address specified by the second
operand.
Note: There are many other instructions on z Systems. This article only discusses some representative instructions.
Example of store instructions
In the following example, ST
instruction will store the value of variable a to the address
which currently holds variable b. Since a = 1 and b = 0 before the operation, b will become 1 afterward. With
b = 1, the function will return 0.
The example makes use of memory constraint "m", which can significantly simplify the address computation.
Listing 13: Example of ST instruction
1 int main() { 2 int a = 1, b = 0; // b = 0 3 asm("ST %1,%0\n" // Store value of a to the address which currently holds b 4 :"=m"(b) 5 :"r"(a) 6 ); 7 return a==b ? 0 : 1; // Based on line 2, b is expected to become 1. Accordingly, function must return 0 8 }
Conclusion
In general, if an instruction operates on two operands, the direction of the operation depends on the type of the instruction. COMPARE and TEST instructions will record the condition code with their results. BRANCH instructions inspect the condition code to determine the next path of execution. LOAD instructions, when there are two operands, will load the second operand to the first one, that is, Operand1 ← Operand2. On the other hand, STORE instructions store the first operand to the second one, that is, Operand1 → Operand2. Arithmetic instructions will apply the operation on both operands and then store the results to the first one, that is, Operand1 ← Operand1 OP Operand2.
Although Linux on z Systems operates on the same architecture as IBM z/OS®, z/TPF, z/VSE®, and z/VM®, inline assembly for Linux on z Systems only accepts assembler instructions. High Level Assembler (HLASM) instructions and macros such as DS, DD, GETMAIN will not be accepted.
Advanced users can improve the runtime performance by fine-tuning the assembler code generated by the compiler. The effort, however, should be dedicated to the most
performance-sensitive parts of the program. While inserting inline asm
statements and/or assembler instructions to the program may improve the execution, it may also
impede the advanced optimizations carried out by the compiler and thus result in significant performance degradation. For example, if a label is used in the inline assembly, certain
optimization such as inlining will be impacted. Careful planning and thorough testing are essential when working with the assembler codes.
Acknowledgements
I would like to thank Ms. Visda Vokhshoori, the z/OS Lead for Compiler Optimizations at Toronto Software Lab, IBM Canada. Her technical advice played an important role in the composition of this article.
Resources
- Visit the IBM XL C/C++ for Linux on z Systems product pages for more information.
- Get connected. Join the Rational C/C++ Cafe community.
References
- z/Architecture Principles of Operation, IBM Publication No. SA22-7832-10
- IBM z/Architecture Reference Summary, IBM Publication No. SA22-7871-08