Document revision date: 30 March 2001

## OpenVMS Programming Concepts Manual

Previous | Contents | Index

#### 15.2.1.1 Compiler Example of Memory Structure of VAX C and Compaq C

The following code examples, and Figure 15_2, and Figure 15-3 illustrate a C data structure containing byte, word, and longword data and how it would be laid out in memory by VAX C and Compaq C.

      struct
      {
        char  byte;
        short word;
        long  longword;
      }mystruct;

On VAX systems, when compiled using the VAX C compiler, the previous structure has a memory layout as shown in Figure 15-2, where each piece of data begins on the next byte boundary.

Figure 15-2 Alignment Using VAX C Compiler

On Alpha systems, when compiled using the Compaq C compiler, the structure is padded to achieve natural alignment, if needed, as shown in Figure 15-3.

Figure 15-3 Alignment Using Compaq C Compiler

On Alpha systems, note where Compaq C places some padding to align naturally all the data structure elements. Compaq C would also align the structure itself on a longword boundary. The Compaq C compiler aligns the structure on a longword boundary because the largest element in the structure is a longword.

### 15.2.2 The BLISS Compiler

On Alpha systems, the BLISS compiler provides greater control over alignment than the Compaq C compiler. The BLISS compiler also makes different assumptions about alignment.

Compaq does not ship the BLISS compiler on Alpha systems.

The Alpha BLISS compiler, like the VAX BLISS compiler, allows explicit specification of program section (PSECT) alignment.

On Alpha systems, BLISS compilers align all explicitly declared data on naturally aligned boundaries.

On Alpha systems, you can align declared data in BLISS source code with the align attribute, although the alignment specified cannot be greater than that for the PSECT in which the data is contained. The alignment attribute indicates a specific address boundary by means of a boundary value, N, which specifies that the binary address of the data segment must end in at least N zeros. To specify the static byte datum A to be aligned on a longword boundary, for example, use the following declaration:

    OWN
    A:BYTE ALIGN(2)

On Alpha systems, when the BLISS compiler cannot determine the base alignment of a BLOCK, it assumes full word alignment, unless told otherwise by a command qualifier or switch declaration. Like the Compaq C compiler, if the BLISS compilers believe that the data is unaligned, they generate safe instruction sequences. If you specify the qualifier /CHECK=ALIGNMENT in the BLISS command line, then warning information is provided when they detect unaligned memory references.

### 15.2.3 The Compaq Fortran Compiler (Alpha Only)

On Alpha systems, the defaults for the Compaq Fortran compiler emphasize compatibility and standards conformance. Normal data declarations (data declared outside of COMMON block statements) are aligned on natural boundaries by default. COMMON block statement data is not aligned by default, which conforms to the FORTRAN-77 and FORTRAN-90 standards.

The qualifier /ALIGN=(COMMONS=STANDARD) causes COMMON block data to be longword aligned. This adheres with the FORTRAN-77 and FORTRAN-90 standards, which state that the compiler is not allowed to put padding between INTEGER*4 and REAL*8 data. This can cause REAL*8 data to be unaligned. To correct this, apply the NATURAL rule; for instance, apply /ALIGN=(COMMONS=NATURAL to get natural alignment up to quadwords and the best performance, though this does not conform to standards.

To pack COMMON block and RECORD statement data, specify /ALIGN=NONE. The qualifier /ALIGN=NONE is equivalent to /NOALIGN, /ALIGN=PACKED, or /ALIGN=(COMMON=PACKED,RECORD=PACKED. To pack just RECORD statement data, specify /ALIGN=(RECORD=PACKED).

Besides command line qualifiers, Compaq Fortran provides two directives to control the alignment of RECORD statement data and COMMON block data. The CDEC$OPTIONS directive controls whether the Compaq Fortran compiler naturally aligns fields in RECORD statements or data items in COMMON blocks for performance reasons, or whether the compiler packs those fields and data items together on arbitrary byte boundaries. The CDEC$OPTIONS directive, like the /ALIGN command qualifier, takes class and rule parameters. Also, the CDE$OPTIONS directive overrides the compiler option /ALIGN.

By default, the Compaq Fortran compiler emits alignment warnings, but these can be turned off by using the qualifier /WARNINGS=NOALIGNMENT.

### 15.2.4 The MACRO-32 Compiler (Alpha Only)

On Alpha systems, as with the C, BLISS, and Compaq Fortran languages, unaligned data references in MACRO-32 code work correctly, though they perform slower than aligned references. The MACRO-32 language provides you with direct control over alignment. There is no implicit padding for alignment done by the MACRO-32 compiler; data remains at the alignment you specify.

The MACRO-32 compiler recognizes the alignment of all locally declared data and flags all references to declared data that is unaligned. By default, the MACRO-32 compiler assumes that addresses in registers used as base pointers are longword aligned at routine entry.

For the MOVQ instruction, the compiler assumes that the base address is longword aligned, unless the compiler determines by its register-tracking logic that the address can not be longword aligned. Only longword alignment is tracked; quadword register alignment is not tracked. If you use the OpenVMS Alpha MOVQ instruction, the data must be quadword aligned, because the compiler does not translate it into unaligned loads.

External data is data that is not contained in the current source being compiled. External data is assumed to be longword aligned by the MACRO-32 compiler. The compiler detects and flags unaligned global label references. This enables you to locate external data that is not aligned.

To preserve atomicity, the compiler assumes that the data is longword aligned. Unaligned data causes a trap and voids the atomicity. Therefore, you must ensure that such data is aligned.

To fix unaligned data references, the easiest way is for you to align the data, if possible. If you cannot align the data, the data address can be moved into a register and then the register declared as unaligned. When you compile with /UNALIGNED, you tell the compiler to treat all data references as unaligned and to generate safe unaligned sequences. You can also use the .SET_REGISTERS directive, which affects data references only for the specified registers for a section of code.

The .PSECT and .ALIGN directives are supported. The compiler knows the alignment of locally declared data. The compiler makes certain assumptions about the alignment, but does allow programmer control over those assumptions. The MACRO-32 compiler provides two directives for changing the compiler's assumptions about alignment, which results in letting the compiler produce more efficient code. These two directives are as follows:

- .SET_REGISTERS allows you to specify whether a register points to aligned or unaligned data. You use this directive when the result of an operation is the opposite of what the compiler expects. Also, use the same directive to declare registers that the compiler would not otherwise detect as input or output registers.
  For example, consider the DIVL instruction. After executing this instruction in the following example, the MACRO-32 compiler assumes that R1 is unaligned. A future attempt at using R1 as a base register will cause the compiler to generate an unaligned fetch sequence. However, suppose you know that R1 is always aligned after the DIVL instruction. You can then use the .SET_REGISTERS directive to inform the compiler of this. When the compiler sees the MOVL from 8(r1), it knows that it can use the shorter aligned fetch (LDL) to retrieve the data. At run time, however, if R1 is not really aligned, then this results in an alignment trap. The following example shows the setting of a register to be aligned:

      divl   r0,r1            ;Compiler now thinks R1 unaligned

      .set_registers aligned=r1

      movl   8(r1),r2         ;Compiler now treats R1 as aligned

- .SYMBOL_ALIGNMENT allows you to specify the alignment of any memory reference that uses a symbolic offset. The .SYMBOL_ALIGNMENT directive associates an alignment attribute with a symbol definition used as a register offset; you can use it when you know the base register will be aligned for every use of the symbolic offset. This attribute guarantees to the compiler that the base register has that alignment, and this enables the compiler to generate optimal code.
  In the example that follows, QUAD_OFF has a symbol alignment of QUAD, LONG_OFF, a symbol alignment of LONG, and NONE_OFF has no symbol alignment. In the first MOVL instruction, the compiler assumes that R0, since it is used as a base register with QUAD_OFF, is quadword aligned. Since QUAD_OFF has a value of 4, the compiler knows it can generate an aligned longword fetch. For the second MOVL, R0 is assumed to be longword aligned, but since LONG_OFF has a value of 5, the compiler realizes that offset+ base is not longword aligned and would generate a safe unaligned fetch sequence. In the third MOVL, R0 is assumed to be unaligned, unless the compiler knows otherwise from other register tracking, and would generate a safe unaligned sequence. The .SYMBOL_ALIGNMENT alignment remains in effect until the next occurrence of the directive.

      .symbol_alignment QUAD
       quad_off=4
      .symbol_alignment LONG
      long_off=5
      .symbol_alignment NONE
      none_off=6

      movl quad_off(r0),r1    ;Assumes R0 quadword aligned
      movl long_off(r0),r2    ;Assumes R0 longword aligned
      movl none_off(r0),r3    ;No presumed alignment for R0

### 15.2.5 The VAX Environment Software Translator---VEST (Alpha Only)

On Alpha systems, the DECmigrate for OpenVMS Alpha VAX Environment Software Translator (VEST) utility is a tool that translates binary OpenVMS VAX image files into OpenVMS Alpha image files. Image files are also called executable files. Though it is similar to compiler, VEST is for binaries instead of sources.

VEST deals with alignment in two different modes: pessimistic and optimistic. VEST is optimistic by default; but whether optimistic or pessimistic, the alignment of program counter (PC) relative data is known at translation time, and the appropriate instruction sequence can be generated.

In pessimistic mode, all non PC-relative references are treated as unaligned using the safe access sequences. In optimistic mode, the emulated VAX registers (R0--R14) are assumed to be quadword aligned upon entry to each basic block. Autoincrement and autodecrement changes to the base registers are tracked. The offset plus the base register alignment are used to determine the alignment and the appropriate access sequence is generated.

The /OPTIMIZE=NOALIGN qualifier on the VEST command tells VEST to be pessimistic; it assumes that base registers are not aligned, and should generate the safe instruction sequence. Doing this can slow execution speed by a factor of two or more, if there are no unaligned data references. On the other hand, it can result in a performance gain if there are a significant number of unaligned references, since safe sequences avoid any unaligned data traps.

Additional controls preserve atomicity in longword data that is not naturally aligned. Wherever possible, data should be aligned in the VAX source code and the image rebuilt before translating the image with DECmigrate. This results in better performance on both VAX and Alpha systems.

## 15.3 Using Tools for Finding Unaligned Data

Tools that aid the uncovering of unaligned data include the OpenVMS Debugger, Performance and Coverage Analyzer (PCA), and eight system services. These tools are discussed in the following sections.

### 15.3.1 The OpenVMS Debugger

By using the OpenVMS Debugger, you can turn on and off unaligned data exception breakpoints by using the commands SET BREAK/UNALIGNED_DATA and CANCEL BREAK/UNALIGNED_DATA. These commands must be used with the SET BREAK/EXCEPTION command. When the debugger breaks at the unaligned data exception, the context is like any other exception. You can examine the program counter (PC), processor status (PS), and virtual address of the unaligned data exception. Example 15-1 shows the output from the debugger using the SET OUTPUT LOG command of a simple program.

Example 15-1 OpenVMS Debugger Output from SET OUTPUT LOG Command

    #include <stdio.h>
    #include <stdlib.h>

    main( )
    {
         char *p;
         long *lp;

              /* malloc returns at least quadword aligned printer */
         p = (char *)malloc( 32 );

              /* construct unaligned longword pointer and place into lp */
         lp = (long *)((char *)(p+1));

              /* load data into unaligned longword */
         lp[0] = 123456;

         printf( "data - %d\n", lp[0] );
         return;
    }

    ------- Compile and Link commands -------
    $ cc/debug debug_example
    $ link/debug debug_example
    $ run debug_example
    ------- DEBUG session using set output log -------
    Go
    ! break at routine DEBUG_EXAMPLE\main
    !     598:           p - (char *)malloc( 32 );
    set break/unaligned_data
    set break/exception
    set radix hexadecimal
    Go
    !Unaligned data access: virtual address - 003CEEA1, PC - 00020048
    !break on unaligned data trap preceding DEBUG_EXAMPLE\main\%LINE 602
    !     602:           printf( "data - %d\n", lp[0] );
    ex/inst 00020048-4
    !DEBUG_EXAMPLE\main\%LINE 600+4:                 STL         R1,(R0)
    ex r0
    !DEBUG_EXAMPLE\main\%R0: 00000000 003CEEA1

### 15.3.2 The Performance and Coverage Analyzer---PCA

The PCA allows you to detect and fix performance problems. Because unaligned data handling can significantly increase overhead, PCA has the capability to collect and present information on aligned data exceptions. PCA commands that collect and display unaligned data exceptions are:

- SET UNALIGNED_DATA
- PLOT/UNALIGNED_DATA PROGRAM BY LINE

Also, PCA can display data according to the PC of the fault, or by the virtual address of the unaligned data.

### 15.3.3 System Services (Alpha Only)

On Alpha systems, there are eight system services to help locate unaligned data. The first three system services establish temporary image reporting; the next two provide process-permanent reporting, and the last three provide for system alignment fault tracking. The symbols used in calling all eight of these system services are located in $AFRDEF in the OpenVMS Alpha MACRO-32 library, SYS$LIBRARY:STARLET.MLB. You can also call these system services in C with #include <afrdef.h>.

The first three system services can be used together; they report on the currently executing image. They are as follows:

- SYS$START_ALIGN_FAULT_REPORT. This service enables unaligned data exception for the current image. You can use either a buffered or an exception method of reporting, but you can enable only one method at a time.
  - Buffered method. This method requires that the buffer address and size be specified. You use the SYS$GET_ALIGN_FAULT_DATA service to retrieve buffered alignment data under program control.
  - Exception method. This method requires no buffer. Unaligned data exceptions are signaled to the image, at which point a user-written condition handler takes whatever action is desired. If no user-written handler is set up, then an informational exception message is broadcast for each unaligned data trap, and the program continues to execute.
- SYS$STOP_ALIGN_FAULT_REPORT. This service cancels unaligned data exception reporting for the current image if it were previously enabled. If you do not explicitly call this routine, then reporting is disabled by the operating systems' image rundown logic.
- SYS$GET_ALIGN_FAULT_DATA. This service retrieves the accumulated, buffered alignment data when using the buffered collection method.

You can use two of the eight system services to report unaligned data exceptions for the current process. The two services are as follows:

- SYS$PERM_REPORT_ALIGN_FAULT. This service enables unaligned data exception reporting for the process. Once you enable this service, the reporting remains in effect for the process until you explicitly disable it. Once enabled, the SS$_ALIGN condition is signaled for all unaligned data exceptions while the process is active. By default, if no user-written exception handler handles the condition, this results in an information display message for each unaligned data exception.
  This service provides a convenient way of running a number of images without modifying the code in each image, and also of recording the unaligned data exception behavior of each image.
- SYS$PERM_DIS_ALIGN_FAULT_REPORT. This service disables unaligned data exception reporting for the process.

The three system services that allow you to track systemwide alignment faults are as follows:

- SYS$INIT_SYS_ALIGN_FAULT_REPORT. This service initializes system process alignment fault reporting.
- SYS$STOP_SYS_ALIGN_FAULT_REPORT. This service disables systemwide alignment fault reporting.
- SYS$GET_SYS_ALIGN_FAULT_DATA. This service obtains data from the system alignment fault buffer.

These services require CMKRNL privilege. Alignment faults for all modes and all addresses can be reported using these services. The user can also set up masks to report only certain types of alignment faults. For example, you can get reports on only kernel modes, only user PC, or only data in system space.

Previous | Next | Contents | Index

| privacy and legal statement |
5841PRO_047.HTML