C expressions as read-write __asm operands

If you use the same __asm operand for both input and output, you must take care that you tell the compiler that the input __asm operand refers to the same variable as the corresponding output __asm operand. For example, the code format string in Figure 1 uses one register to store a single __asm operand that is used for both input and output.

Definition of __asm operands for both input and output via an operand list

This topic describes how to use a code format string to define __asm operands that can be used for both input and output.

You can use either input and output operand strings both incorrectly (Figure 1) and correctly (Figure 3). The code in Figure 1 is incorrect because the AR statement reads the first operand and then modifies it, but the =r constraint specifies the output aspect only.

Figure 1. Incorrect __asm operand definition for both input and output
   __asm  ( " AR %0,%1" :  "=r"(x) : "r"(y) );   1   
Note: No input operand is specified for variable x. The compiler will not know that input and output are stored in the same variable.
The compiler-generated HLASM source code in Figure 2 is the result of the incorrect definition in Figure 1.
Figure 2. Incorrect compiler-generated HLASM source code from the incorrect __asm operand definition for both input and output
   L  2,@4y   1 
   LA 1,@3x
   AR 4,2
   ST 4,0(,1)     
Note: GPR 4, which is meant for input as well as output, is not loaded from variable x before the code format string is embedded because the code format string in Figure 1 specified variable x as an output operand only.
If a code format string uses a single __asm operand for both input and output, you must ensure that the embedded assembly statements will perform both of the following tasks:
  • Define the variable as an input operand as well as an output operand.
  • Define both an input operand and an output operand that refers to the same variable. The variable name is not sufficient for this purpose. See Figure 3.
Figure 3 shows the code format string that will embed the correct assembler statements (as shown in Figure 4).
Figure 3. Successful definition of an __asm operand for both input and output
   __asm  ( " AR %0, %1" :  "=r"(x) : "r"(y), "0"(x) );
                  1            2            3   4 
Notes:
  1. %0 is the first operand in the code format string.
  2. This example has one output __asm operand, "=r"(x).
  3. Within the input __asm operand list "r"(y), "0"(x), the __asm operands are separated by a comma.
  4. An input operand "0"(x) is added to the input field. The constraint of this __asm operand is the ("0"), which tells the compiler that:
    • This input __asm operand is the same as the output __asm operand %0. (A numeral zero in the constraint ("0") refers to %0; a numeral one in a constraint would refer to %1; and so on.)
    • The register needs to be loaded with variable x, as shown in Figure 4, before the code format string is embedded in the HLASM output.
The compiler-generated HLASM source code in Figure 4 is the result of the correct definition in Figure 3.
Figure 4. Correct compiler-generated HLASM source code from the correct __asm operand definition for both input and output
   L  2,@4y        
   L  4,@3x        1  
   LA 1,@3x        
   AR 4,2        
   ST 4,0(,1)     
Note: The compiler inserted L 4,@3x at the beginning of the instruction sequence because the code format string in Figure 3 included both the output operand "=r"(x) and the input operand "0"(x). Together, these statements tell the compiler that the register for the first operand %0 will be used for variable x, which has a value that can be either an input or an output operand.

Definition of an __asm operand for both input and output via the "+" constraint

You can also use the "+" constraint to specify that an __asm operand is used for both input and output.

In Figure 5, the "+" constraint is used to define that the variable x is used both as input and output.

Figure 5. The + constraint to define an __asm operand for both input and output
   __asm  ( " AR %0, %1" :  "+r"(x) : "r"(y)); 
Note: This example is parsed as though the operand list in Figure 3 is given.

Note that an operand can be matched only once. When you use the "+" constraint to implicitly define matching input and output __asm operands, do not explicitly define a corresponding __asm operand.

Figure 6 shows an erroneous example of an __asm operand that is defined both implicitly and explicitly. The notes identify the unnecessary code.

Figure 6. Error: Redundant definition of an __asm operand
   __asm  ( " AR %0, %1" :  "+r"(x) : "r"(y), “0”(x)); 
                  1             2                 3        
Notes:
  1. %0 is the first operand in the code format string.
  2. This example has one output __asm operand, "+r"(x). The "+" constraint implicitly defines a matching input __asm operand.
  3. You do not have to define __asm operand "0"(x) explicitly.