[an error occurred while processing this directive]

HP OpenVMS Systems

C Programming Language
Content starts here HP C

HP C
User's Guide for OpenVMS Systems


Previous Contents Index

6.1.5 Compiler-Mode Macros

The following predefined macros are defined if the corresponding compiler mode is selected:

  • __DECC_MODE_STRICT
  • __DECC_MODE_RELAXED
  • __DECC_MODE_VAXC
  • __DECC_MODE_COMMON
  • __DECC_MODE_MS
  • __MS

6.1.6 Pointer-Size Macro

The following predefined macro is defined if the /POINTER_SIZE command-line qualifier is specified:

__INITIAL_POINTER_SIZE

Specifying /POINTER_SIZE, /POINTER_SIZE=32, or /POINTER_SIZE=SHORT defines __INITIAL_POINTER_SIZE to 32.

Specifying /POINTER_SIZE=64, or /POINTER_SIZE=LONG defines __INITIAL_POINTER_SIZE to 64.

If /POINTER_SIZE is not specified, __INITIAL_POINTER_SIZE is defined to 0. This lets you use #ifdef __INITIAL_POINTER_SIZE to test whether or not the compiler supports 64-bit pointers, because compilers lacking pointer-size controls will not define this macro at all.

6.1.7 The __HIDE_FORBIDDEN_NAMES Macro

The C standard specifies exactly what identifiers in the normal name space are declared by the standard header files. A compiler is not free to declare additional identifiers in a header file unless the identifiers follow defined rules (the identifier must begin with an underscore followed by an uppercase letter or another underscore).

When running the HP C compiler for OpenVMS systems in strict ANSI C mode (/STANDARD=ANSI89), versions of the standard header files are included that hide many identifiers that do not follow the rules. The header file <stdio.h> , for example, hides the definition of the macro TRUE. The compiler accomplishes this by predefining the macro __HIDE_FORBIDDEN_NAMES in strict ANSI mode.

You can use the /UNDEFINE="__HIDE_FORBIDDEN_NAMES" command-line qualifier to prevent the compiler from predefining this macro and, thereby, including macro definitions of the forbidden names.

The header files are modified to only define additional VAX C names if __HIDE_FORBIDDEN_NAMES is undefined. For example, <stdio.h> might contain the following:


#ifndef __HIDE_FORBIDDEN_NAMES 
#define TRUE 1 
#endif 

6.2 Built-In Functions

Sections 6.2.1, Section 6.2.2, and 6.2.3 describe the HP C built-in functions available in all compiler modes on OpenVMS Alpha, I64, and VAX systems.

These functions allow you to directly access hardware and machine instructions to perform operations that are cumbersome, slow, or impossible in other C compilers.

These functions are very efficient because they are built into the HP C compiler. This means that a call to one of these functions does not result in a reference to a function in the HP C Run-Time Library (RTL) or to a function in your program. Instead, the compiler generates the machine instructions necessary to carry out the function directly at the call site. Because most of these built-in functions closely correspond to single VAX or Alpha machine instructions, the result is small, fast code.

Some of these built-in functions (such as those that operate on strings or bits) are of general interest. Others (such as the functions dealing with process context) are of interest if you are writing device drivers or other privileged software. Some of the functions discussed in the following sections are privileged and unavailable to user mode programs.

Be sure to include the <builtins.h> header file in your source program to access these built-in functions. VAX C required you to place the #pragma builtins preprocessor directive, rather than #include <builtins.h> , in your source file before using one or more built-in functions. HP C supports #pragma builtins for compatibility with VAX C, but using #include <builtins.h> is recommended.

Note

HP C implements #pragma builtins as if it were #include <builtins.h> ; if you get an error from #pragma builtins , it is the same kind of error you would get if you specified #include <builtins.h> .

Also see Section 5.4.2.

Some of the built-in functions have optional arguments or allow a particular argument to have one of many different types. To describe all valid combinations of arguments, the following built-in function descriptions list several different prototypes for the function. As long as a call to a built-in function matches one of the prototypes listed, the call is valid. Furthermore, any valid call to a built-in function behaves as if the corresponding prototype were in scope of the call. The compiler, therefore, performs the argument checking and conversions specified by that prototype.

The majority of the built-in functions are named after the processor instruction that they generate. The built-in functions provide direct and unencumbered access to those VAX instructions. Any inherent limitations to those instructions are limitations to the built-in functions as well. For instance, the MOVC3 instruction and the _MOVC3 built-in function can move at most 65,535 characters.

For more information on these built-in functions, see the corresponding machine instruction in the VAX MACRO and Instruction Set Reference Manual, Alpha Architecture Handbook, or Alpha Architecture Reference Manual. In particular, refer to the structure of queue entries manipulated by the built-in queue functions.

6.2.1 Built-In Functions for OpenVMS Alpha Systems (ALPHA ONLY)

The following sections describe the HP C built-in functions available on OpenVMS Alpha systems.

6.2.1.1 Translation Macros for VAX C Built-in Functions

On HP C for OpenVMS Alpha Systems, the <builtins.h> header file contains macro definitions that translate some VAX C built-in functions to the equivalent HP C for OpenVMS Alpha built-in functions. Consequently, the following VAX C built-in functions are effectively supported:

_BBCCI
_BBSSI
_INSQHI
_INSQTI
_INSQUE
_REMQHI
_REMQTI
_REMQUE
_PROBER
_PROBEW

For more detail on any of these functions, see <builtins.h> or the description of the corresponding native Alpha function in this chapter. For example, for a description of _INSQHI, see __PAL_INSQHIL.

6.2.1.2 In-line Assembly Code---ASMs

HP C supports in-line assembly code, commonly referred to as ASMs on UNIX platforms.

Like built-in functions, ASMs are implemented with a function-call syntax. But unlike built-in functions, to use ASMs you must include the <c_asm.h> header file containing prototypes for the three types of ASMs, and the #pragma intrinsic preprocessor directive.

These functions have the following format:


__int64 asm (const char *, ...); /* for integer operations, like MULQ */
float fasm (const char *, ...); /* for single precision float instructions, like MULS */
double dasm (const char *, ...); /* for double precision float instructions, like MULT */
#pragma intrinsic (asm, fasm, dasm)

const char *

The first argument to the asm , fasm , or dasm function contains the instruction(s) to be generated inline and the metalanguage that describes the interpretation of the arguments.

...

The source and destination arguments (if any) for the instruction being generated, and any other values used in the generated instructions.

These values are made available to the instructions through the normal argument passing conventions of the calling standard (the first integer argument is available in register R16).

The #pragma intrinsic directive in the <c_asm.h> header file is required when using ASMs. It notifies the compiler that:

  • These functions are not user-defined functions.
  • The special ASM processing should be applied to analyze at compile time the first argument and generate machine-code instructions as specified by the contents of the string.

The metalanguage for the argument references has the following form:


<metalanguage_sequence> : <register_alias> 
                        | <register_number> 
                        | <register_macro> 
                        ; 
 
<register_number>       : "$" number 
                        ; 
 
<register_macro>        : "%" <macro_sequence> 
                        ; 
 
<macro_sequence>        : number 
                        | <register_name> 
                        | "f" number | "F" number 
                        | "r" number | "R" number 
                        ; 
 
<register_name> :     /* argument registers: R16-R21 */ 
                     "a0" | "a1" | "a2" | "a3" | "a4" | "a5" 
 
                     /* return value: R0 or F0, depending on type */ 
                   | "v0"   
 
                     /* scratch registers: R1, R22-R24, R28 */ 
                   | "t0" | "t1" | "t2" | "t3" | "t4"  
 
                     /* save registers: R2-R15 */ 
                   | "s0" | "s1" | "s2" | "s3" | "s4"  | "s5"  | "s6"  | "s7" 
                   | "s8" | "s7" | "s8" | "s9" | "s10" | "s11" | "s12" | "s13" 
 
                     /* stack pointer: R30 */ 
                   | "sp" | "SP" | "$sp" | "$SP" 
 
                   | "RA" | "ra"           /* return addr:        R26  */ 
                   | "PV" | "pv"           /* procedure value:    R27  */ 
                   | "AI" | "ai"           /* arg info:           R25  */ 
                   | "FP" | "fp"           /* frame pointer:      R29  */ 
                   | "RZ" | "rz" | "zero"  /* sink/source: R31 == zero */ 

Syntactically, the metalanguage can appear anywhere within an instruction sequence.

The literal string that contains instructions, operands, and metalanguage must follow the general form:


<string_contents>       :  <instruction_seq>         
                        |  <string_contents> ";" <instruction_seq> 
                        |  error 
                        |  <string_contents> error 
                        ; 
 
<instruction_seq>       :  instruction_operand 
                        |  directive 
                        ; 

An instruction_operand is generally recognized as an assembly language instruction separated by white space from a sequence of comma-separated operands.

You can code multiple instruction sequences into one literal string, separating them by semicolons.

Since the C language concatentates adjacent string literals into a single string, successive instructions can be written as separate strings, one per line (as is normally done in assembly language) as long as each instruction is terminated by a semicolon (as shown in the examples).

There are semantic and syntax rules associated with ASMs:

  • The first argument to an ASM call is interpreted as the instructions to be assembled in the metalanguage, and must be fully understood by the compiler at compile time. Therefore, it must be a literal string (or a macro expanding to a literal string) and must not be a run-time value containing a string. Therefore, the following are not allowed: indirections, table lookups, structure dereferences, and so on.
  • The remaining arguments are loaded into the argument registers like normal function arguments, except that the second argument to the ASM call is treated as the first argument for purposes of the calling standard.
    For example, in the following test, the six arguments are loaded into arg registers a0 through a5, and the result of each subexpression is stored in the value return register v0. Since v0 is the calling standard's return value register (R0 for an integer function), the result of the final MULQ is the value returned by the "call":


       if (asm("mulq %a0, %a1,  %v0;" 
               "mulq %a2, %v0,  %v0;" 
               "mulq %a3, %v0,  %v0;" 
               "mulq %a4, %v0,  %v0;" 
               "mulq %a5, %v0,  %v0;", 1, 2, 3, 4, 5, 6) != 720){ 
         error_cnt++; 
         printf ("Test failed\n"); 
            } 
    

    The following example does not work. There is no value loaded into the floating-point return register. Furthermore, it results in a compile-time warning stating that r2 is used before it is set, because the arguments are loaded into the arg registers and not into r2:


    z =  fasm("mulq %r2, %a1, %r5", x=10, y=5); 
    

    The correct way of doing this is to specify an argument register number in place of r2. A correct version of the above would be:


    z = fasm("mulq   %a0, %a1, %a1;" 
             "stq    %a1, 0(%a2);" 
             "ldt    %f0, 0(%a2);" 
             "cvtqf  %f0, %f0;",  x=10, y=5, &temp); 
    

    Note that the memory location used for the transfer from integer to floating-point register is made available to the asm code by passing as an argument the address of a variable allocated in the C code for that purpose.
  • A return register must be specified in the metalanguage for the result to appear in the expected place.
  • For instructions that do not take any argument and do not have a return type, leave out the arguments. For example:


    asm("MB"); 
    

6.2.1.3 Absolute Value ( __ABS)

The __ABS built-in is functionally equivalent to its counterpart, abs , in the standard header file <stdlib.h> .

Its format is also the same:


#include <stdlib.h>
int __ABS (int x);

This built-in does, however, offer performance improvements because there is less call overhead associated with its use.

If you include <stdlib.h> , the built-in is automatically used for all occurrences of abs . To disable the built-in, use #undef abs .

6.2.1.4 Acquire and Release Longword Semaphore (__ACQUIRE_SEM_LONG, __RELEASE_SEM_LONG)

The __ACQUIRE_SEM_LONG and __RELEASE_SEM_LONG functions provide a counted semaphore capability where the positive value of a longword is interpreted as the number of resources available.

The __ACQUIRE_SEM_LONG function loops until the longword has a positive value and then decrements it within a load-locked/store-conditional sequence; it then issues a memory barrier. This function returns 1 if the resource count was successfully decremented within the specified number of retries, and 0 otherwise. With no explicit retry count, the function does not return until it succeeds.

The __RELEASE_SEM_LONG function issues a memory barrier and then does an __ATOMIC_INCREMENT_LONG on the longword.

The __ACQUIRE_SEM_LONG function has the following formats:


int __ACQUIRE_SEM_LONG (volatile void *address);
int __ACQUIRE_SEM_LONG_RETRY (volatile void *address, int retry);

The __RELEASE_SEM_LONG function has the following format:


int __RELEASE_SEM_LONG (volatile void *address);

address

The longword-aligned address of the resource count.

retry

A retry count of type int that indicates the number of times the operation is attempted (which is at least once, even if the retry argument is 0). If the operation cannot be performed successfully in the specified number of retries, the function returns without updating the longword.

6.2.1.5 Add Aligned Word Interlocked ( __ADAWI)

The __ADAWI function adds its source operand to the destination. This function is interlocked against similar operations by other processors or devices in the system.

This function has the following format:


int __ADAWI (short src, volatile short *dest);

src

The value to be added to the destination.

dest

A pointer to the destination. The destination must be aligned on a word boundary. (You can achieve alignment using the _align or __align storage-class modifier.)

The __ADAWI function returns a simulated VAX processor status longword (PSL), the lower 4 bits of which are significant. These 4 bits are the condition codes and are defined as follows:

  • Bit 3 is the negative condition code (N bit).
    In general, it is set by negative result instructions. The bit is cleared by positive result or zero instructions. For those instructions that affect the bit according to a stored result, the N bit reflects the actual result even if the sign of the result is algebraically incorrect as a result of overflow.
  • Bit 2 is the zero condition code (Z bit).
    Typically it is set by instructions that store an exactly zero result and cleared if the result is not zero. Again, this reflects the actual result even if overflow occurs.
  • Bit 1 is the overflow condition code (V bit).
    In general, it is set after arithmetic operations in which the magnitude of the algebraically correct result is too large to be represented in the available space, and cleared after operations whose result fits. Instructions in which overflow is impossible or meaningless either clear the bit or leave it unaffected. Note that all overflow conditions that set the V bit can also cause traps if the appropriate trap enable bits are set.
  • Bit 0 is the carry condition code (C bit).
    Usually it is set after arithmetic operations in which a carry out of, or borrow into, the most significant bit occurred. The bit is cleared after arithmetic operations that had no carry or borrow, and is either cleared or unaffected by other instructions.

6.2.1.6 Add Atomic Longword ( __ADD_ATOMIC_LONG)

The __ADD_ATOMIC_LONG function adds the specified expression to the aligned longword pointed to by the address parameter within a load-locked/store-conditional code sequence.

This function has the following format:


int __ADD_ATOMIC_LONG (void *address, int expression, ...);

address

The address of the aligned longword.

expression

An integer expression.

...

An optional retry count of type int . If specified, the retry count indicates the number of times the operation is attempted (which will be at least once, even if the count argument is 0). If the operation cannot be performed successfully in the specified number of retries, a value of 0 is returned. If the operation is successful, a value of 1 is returned.

Note

If the optional retry count is omitted, this function loops back for a retry unconditionally on failure. In this case, the function can never return a failure value. It either returns a value of 1 upon successful completion, or hangs in an endless failure loop.

6.2.1.7 Add Atomic Quadword ( __ADD_ATOMIC_QUAD)

The __ADD_ATOMIC_QUAD function adds the specified expression to the aligned quadword pointed to by the address parameter within a load-locked/store-conditional code sequence.

This function has the following format:


int __ADD_ATOMIC_QUAD (void *address, int expression, ...);

address

The address of the aligned quadword.

expression

An integer expression.

...

An optional retry count of type int . If specified, the retry count indicates the number of times the operation is attempted (which will be at least once, even if the count argument is 0). If the operation cannot be performed successfully in the specified number of retries, a value of 0 is returned. If the operation is successful, a value of 1 is returned.

Note

If the optional retry count is omitted, this function loops back for a retry unconditionally on failure. In this case, the function can never return a failure value. It either returns a value of 1 upon successful completion, or hangs in an endless failure loop.


Previous Next Contents Index