HP OpenVMS Systems Documentation

Content starts here

HP OpenVMS Programming Concepts Manual

Previous Contents Index

Chapter 15
Alignment on VAX, Alpha, and I64 Systems

This chapter describes the importance and techniques of alignment for OpenVMS VAX, OpenVMS Alpha1, and OpenVMS I64 systems It contains the following subsections:

Section 15.1 describes alignment on OpenVMS VAX, OpenVMS Alpha, and OpenVMS I64 systems.

Section 15.2 describes using compilers for alignment.

Section 15.3 describes using various tools to uncover unaligned data.


1 Reprinted from an article in the March/April 1993 issue of Digital Systems Journal, Volume 15, Number 2, titled "Alpha AXP(TM) Migration: Understanding Data Alignment on OpenVMS AXP Systems" by Eric M. LaFranchi and Kathleen D. Morse. Copyright 1993 by Cardinal Business Media, Inc., 101 Witmer Road, Horsham, PA 19044.

15.1 Alignment

Alignment is an aspect of a data item that refers to its placement in memory. The mixing of byte, word, longword, and quadword data types can lead to data that is not aligned on natural boundaries. A naturally aligned datum of size 2**N is stored in memory at a starting byte address that is a multiple of 2**N, that is, an address that has N low-order zero bits. Data is naturally aligned when its address is an integral multiple of the size of the data in bytes (for example, when the following occurs):

  • A byte is aligned at any address.
  • A word is aligned at any address that is a multiple of 2.
  • A longword is aligned at any address that is a multiple of 4.
  • A quadword is aligned at any address that is a multiple of 8.

Data that is not aligned is referred to as unaligned. Throughout this chapter, the term aligned is used instead of naturally aligned.

Table 15-1 shows examples of common data sizes, their alignment, the number of zero bits in an aligned address for that data, and a sample aligned address in hexadecimal.

Table 15-1 Aligned Data Sizes
Data Size Alignment Zero Bits Aligned Address Example
Byte Byte 0 10001, 10002, 10003, 10004
Word Word 1 10002, 10004, 10006, 10008
Longword Longword 2 10004, 10008, 1000C, 10010
Quadword Quadword 4 10008, 10010, 10018, 10020

An aligned structure has all its members aligned. An unaligned structure has one or more unaligned members. Figure 15-1 shows examples of aligned and unaligned structures.

Figure 15-1 Aligned and Unaligned Structures

15.1.1 Alignment and Performance

To achieve optimal performance, use aligned instruction sequence references and naturally aligned data. When unaligned data is referenced, more overhead is required than when referencing aligned data. This condition is true for OpenVMS VAX, OpenVMS Alpha, and OpenVMS I64 systems. Data need not be aligned to obtain correct processing results: alignment is a concern for performance, not program correctness. Because natural alignment is not always possible, OpenVMS VAX, OpenVMS Alpha, and OpenVMS I64 systems provide help to manage the impact of unaligned data references.

Although alignment is not required on VAX systems for stack, data, or instruction stream references, Alpha systems require that the stack and instructions be longword aligned. Alignment on OpenVMS VAX (VAX Only)

On VAX systems, memory references that are not longword aligned result in a transparent performance degradation. The full effect of unaligned memory references is hidden by microcode, which detects the unaligned reference and generates a microtrap to handle the alignment correction. This fix of alignment is done entirely in microcode. Aligned references, on the other hand, avoid the microtraps to handle fixes. Even with this microcode fix, an unaligned reference can take up to four times longer than an aligned reference. Alignment on OpenVMS Alpha and I64

On Alpha and I64 systems, you can check and correct alignment the following three ways:

  • For Alpha, allow privileged architecture library code (PALcode) to fix the alignment faults for you. For I64, allow the OpenVMS fault handler to fix the alignment faults for you.
  • Use directives to the compiler.
  • Fix the data yourself to make sure data is aligned.

Though Alpha systems do not use microcode to automatically handle unaligned references, PALcode traps the faults and corrects unaligned references as the data is processed. If you use the shorter load/store instruction sequences and your data in unaligned, then you incur an alignment fault PALcode fixup. The use of PALcode to correct alignment faults results in the slowest of the three ways to process your data.

By using directives to the compiler, you can tell your compiler to create a safe set of instructions. If it is unaligned, the compiler uses a set of unaligned load/store instructions. These unaligned load/store instructions are called safe sequences because they never generate unaligned data exceptions. Code sequences that use the unaligned load/store instructions are longer than the aligned load/store instruction sequences. By using unaligned load/store instructions and longer instruction sequences, you can obtain the desired results without incurring an alignment trap. This technique allows you to avoid the significant performance impact of a trap and subsequent data fixes.

By fixing the data yourself so that it is aligned, you can use a short instruction stream. This results in the fastest way to process your data. When aligning data, the following recommendations are suggested:

  • If references to the data must be made atomic, then the data must be aligned. Otherwise, an unaligned fault causes a fatal reserved operand fault in this case.
  • If you fix alignment problems in public interfaces, then you could break existing programs.

To detect unaligned reference information, you can use utilities such as the OpenVMS Debugger and Performance and Coverage Analyzer (PCA). You can also use the OpenVMS Alpha handler to generate optional informational exceptions for process space references. This allows condition handlers to track unaligned references. Alignment fault system services allow you to enable and disable the delivery of these informational exceptions. Section 15.3.3 discusses system services that you can use to report both image and systemwide alignment problems.

15.2 Using Compilers for Alignment (Alpha and I64 Only)

On Alpha and I64 systems, compilers automatically align data by default. If alignment problems are not resolved, they are at least flagged. The following sections present how the compilers for HPC, BLISS, HP Fortran, and MACRO-32 deal with alignment.

15.2.1 The HP C Compiler (Alpha and I64 Only)

On Alpha and I64 systems, the HP C compiler naturally aligns all explicitly declared data, including the elements of data structures. The pragmas member_alignment and nomember_alignment allow data structures to be aligned or packed (putting the next piece of data on the next byte boundary) in the same manner as the VAX C compiler. Additional pragmas of member_alignment save and member_alignment restore exist to save and restore the state of member alignment. These prevent alignment assumptions in one include file from affecting other source code. The following program examples show the use of these pragmas:

        #pragma member_alignment save   (1)
        #pragma nomember_alignment      (2)

          char  byte;
          short word;
          long  longword;
        } mystruct;
        #pragma member_alignment restore  (3)

  1. Saves the current alignment setting.
  2. Sets nomember_alignment, which means that the data is to be packed in the structure mystruct.
  3. Resets the alignment setting for the code that follows.

The base alignment of a data structure is set to be the alignment of the largest member in the structure. If the largest element of a data structure is a longword, for example, then the base alignment of the data structure is longword alignment.

The malloc() function of the HP C Run-Time Library retrieves pointers that are at least quadword aligned. Because it is the exception rather than the rule to encounter unaligned data in C programs, the compiler assumes most data references are aligned. Pointers, for example, are always assumed to be aligned; only data structures declared with the pragma nomember_alignment are assumed to contain unaligned data. If the HP C compiler believes the data might be unaligned, it generates the safe instruction sequences; that is, it uses the unaligned load/store instructions. Also, you can use the /WARNING=ALIGNMENT compiler qualifier to turn on alignment checking by the compiler. This results in a compiler warning for unaligned data references.

On OpenVMS Alpha and OpenVMS I64 systems, dereferencing a pointer to a longword- or quadword-aligned object is more efficient than dereferencing a pointer to a byte- or word-aligned object. Therefore, the compiler can generate more optimized code if it makes the assumption that a pointer object of an aligned pointer type does point to an aligned object.

Because the compiler determines the alignment of the dereferenced object from the type of the pointer, and the program is allowed to compute a pointer that references an unaligned object (even though the pointer type indicates that it references an aligned object), the compiler must assume that the dereferenced object's alignment matches or exceeds the alignment indicated by the pointer type. Specifying /ASSUME=ALIGNED_OBJECTS (the default) allows the compiler to make such an assumption. With this assumption made, the compiler can generate more efficient code for pointer dereferences of aligned pointer types.

To prevent the compiler from assuming the pointer type's alignment for objects that it points to, use the /ASSUME=NOALIGNED_OBJECTS qualifier.

See the HP C User's Guide for OpenVMS Systems for additional information. Compiler Example of Memory Structure of VAX C and HP 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 HP C.

    char  byte;
    short word;
    long  longword;

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 and I64 systems, when compiled using the HP C compiler, the structure is padded to achieve natural alignment, if needed, as shown in Figure 15-3.

Figure 15-3 Alignment Using HP C Compiler

On Alpha and I64 systems, note where HP C places some padding to align naturally all the data structure elements. HP C would also align the structure itself on a longword boundary. The HP 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 and I64 systems, the BLISS compiler provides greater control over alignment than the HP C compiler. The BLISS compiler also makes different assumptions about alignment.

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

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

On Alpha and I64 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:


On Alpha and I64 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 HP 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 HP Fortran Compiler (Alpha and I64 Only)

Fortran 90 Version is supported on OpenVMS I64. Fortran 77 is not supported on OpenVMS I64. HP Fortran for OpenVMS I64 Systems features the same command-line options and language features as HP Fortran for OpenVMS Alpha Systems with a few exceptions, as described in Porting Applications from HP OpenVMS Alpha to HP OpenVMS Industry Standard 64 for Integrity Servers.

On Alpha and I64 systems, the defaults for the HP 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, HP Fortran provides two directives to control the alignment of RECORD statement data and COMMON block data. The CDEC$OPTIONS directive controls whether the HP 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 HP 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 and I64)

On Alpha and I64 systems, as with the C, BLISS, and HP Fortran languages, unaligned data references in Macro-32 code work correctly, though they perform slower than aligned references because the system must take an unaligned address fault to complete the unaligned reference. If it is known that a data reference is unaligned, the compiler can generate unaligned quadword loads and masks to manually extract the data. This is slower than an aligned load but much faster than taking an alignment fault. Global data labels that are not longword or quadword aligned are flagged with information-level messages. In addition, unaligned memory modification references cannot be made atomic with /PRESERVE=ATOMICITY or .PRESERVE ATOMICITY. If this is attempted, it will cause a fatal reserved operand fault.

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.

Although the Macro-32 compilers attempt to track information about the values that may appear in registers as the program proceeds, they only attend to enough information to determine the likelihood of word and longword alignment. Because the atomicity of the MOVQ instruction can be preserved only if the address is quadword aligned, in generating code for MOVQ, the Macro-32 compiler assumes quadword alignment of the address if it believes it to be longword aligned.

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 the /UNALIGNED qualifier to the MACRO/MIGRATION command, 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
    .symbol_alignment LONG
    .symbol_alignment NONE
    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 Precedence of Alignment Controls

The order of precedence of the compiler's alignment controls, from strongest (.SYMBOL_ALIGNMENT) to weakest (built-in assumptions and tracking mechanisms), is as follows:

  1. .SYMBOL_ALIGNMENT directive
  2. .SET_REGISTER directive
  3. /UNALIGN qualifier
  4. Built-in assumptions and tracking mechanisms

Previous Next Contents Index