Sections 6.2.1 and 6.2.2 describe the DEC C built-in functions available in all compiler modes on OpenVMS Alpha and OpenVMS 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 DEC C compiler. This means that a call to one of these functions does not result in a reference to a function in the DEC 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. DEC C supports #pragma builtins for compatibility with VAX C, but Digital recommends using #include <builtins.h> for compatibility with DEC C on other platforms.)
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.
The following sections describe the DEC C built-in functions available on OpenVMS Alpha systems.
On DEC C for OpenVMS Alpha Systems, the <builtins.h> header file contains macro definitions that translate some VAX C built-in functions to the equivalent DEC C for OpenVMS Alpha built-in functions. Consequently, the following VAX C built-in functions are effectively supported:
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.
DEC C supports in-line assembly code, commonly called ASMs on UNIX platforms.
Like builtin-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)
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:
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 whitespace 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.
asm("MB");
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.
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 one of 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);
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);
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:
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.
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.
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.
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.
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, ...);
A value of 1 is returned upon successful completion.
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, ...);
A value of 1 is returned upon successful completion.
The __ALLOCA function allocates n bytes from the stack.
This function has the following format:
void *__ALLOCA (unsigned int n);
A pointer to the allocated memory is returned.
The __AND_ATOMIC_LONG function performs a logical AND of the specified expression with the aligned longword pointed to by the address parameter within a load-locked/store-conditional code sequence.
This function has the following format:
int __AND_ATOMIC_LONG (void *address, int expression, ...);
A value of 1 is returned upon successful completion.
The __AND_ATOMIC_QUAD function performs a logical AND of the specified expression with the aligned quadword pointed to by the address parameter within a load-locked/store-conditional code sequence.
This function has the following format:
int __AND_ATOMIC_QUAD (void *address, int expression, ...);
A value of 1 is returned upon successful completion.
The __ATOMIC_ADD_LONG function adds the specified expression to the aligned longword pointed to by the address parameter within a load-locked/store-conditional code sequence and returns the value of the longword before the addition was performed.
This function has one of the following formats:
int __ATOMIC_ADD_LONG (volatile void *address, int expression); int __ATOMIC_ADD_LONG_RETRY (volatile void *address, int expression, int retry, int *status);
The __ATOMIC_ADD_QUAD function adds the specified expression to the aligned quadword pointed to by the address parameter within a load-locked/store-conditional code sequence and returns the value of the quadword before the addition was performed.
This function has one of the following formats:
int __ATOMIC_ADD_QUAD (volatile void *address, int expression); int __ATOMIC_ADD_QUAD_RETRY (volatile void *address, int expression, int retry, int *status);
The __ATOMIC_AND_LONG function performs a logical AND of the specified expression with the aligned longword pointed to by the address parameter within a load-locked/store-conditional code sequence and returns the value of the longword before the operation was performed.
This function has one of the following formats:
int __ATOMIC_AND_LONG (volatile void *address, int expression); int __ATOMIC_AND_LONG_RETRY (volatile void *address, int expression, int retry, int *status);
The __ATOMIC_AND_QUAD function performs a logical AND of the specified expression with the aligned quadword pointed to by the address parameter within a load-locked/store-conditional code sequence and returns the value of the quadword before the operation was performed.
This function has one of the following formats:
int __ATOMIC_AND_QUAD (volatile void *address, int expression); int __ATOMIC_AND_QUAD_RETRY (volatile void *address, int expression, int retry, int *status);
The __ATOMIC_OR_LONG function performs a logical OR of the specified expression with the aligned longword pointed to by the address parameter within a load-locked/store-conditional code sequence and returns the value of the longword before the operation was performed.
This function has one of the following formats:
int __ATOMIC_OR_LONG (volatile void *address, int expression); int __ATOMIC_OR_LONG_RETRY (volatile void *address, int expression, int retry, int *status);
The __ATOMIC_OR_QUAD function performs a logical OR of the specified expression with the aligned quadword pointed to by the address parameter within a load-locked/store-conditional code sequence and returns the value of the quadword before the operation was performed.
This function has one of the following formats:
int __ATOMIC_OR_QUAD (volatile void *address, int expression); int __ATOMIC_OR_QUAD_RETRY (volatile void *address, int expression, int retry, int *status);
The __ATOMIC_INCREMENT_LONG function increments by 1 the aligned longword pointed to by the address parameter within a load- locked/store-conditional code sequence and returns the value of the longword before the operation was performed.
This function has the following format:
int __ATOMIC_INCREMENT_LONG (volatile void *address);
The __ATOMIC_INCREMENT_QUAD function increments by 1 the aligned quadword pointed to by the address parameter within a load- locked/store-conditional code sequence and returns the value of the quadword before the operation was performed.
This function has the following format:
int __ATOMIC_INCREMENT_QUAD (volatile void *address);
The __ATOMIC_DECREMENT_LONG function decrements by 1 the aligned longword pointed to by the address parameter within a load- locked/store-conditional code sequence and returns the value of the longword before the operation was performed.
This function has the following format:
int __ATOMIC_DECREMENT_LONG (volatile void *address);
The __ATOMIC_DECREMENT_QUAD function decrements by 1 the aligned quadword pointed to by the address parameter within a load- locked/store-conditional code sequence and returns the value of the quadword before the operation was performed.
This function has the following format:
int __ATOMIC_DECREMENT_QUAD (volatile void *address);
The __ATOMIC_EXCH_LONG function stores the value of the specified expression into the aligned longword pointed to by the address parameter within a load-locked/store-conditional code sequence and returns the value of the longword before the operation was performed.
This function has one of the following formats:
int __ATOMIC_EXCH_LONG (volatile void *address, int expression); int __ATOMIC_EXCH_LONG_RETRY (volatile void *address, int expression, int retry, int *status);
The __ATOMIC_EXCH_QUAD function stores the value of the specified expression into the aligned quadword pointed to by the address parameter within a load-locked/store-conditional code sequence and returns the value of the quadword before the operation was performed.
This function has one of the following formats:
int __ATOMIC_EXCH_QUAD (volatile void *address, int expression); int __ATOMIC_EXCH_QUAD_RETRY (volatile void *address, int expression, int retry, int *status);
The __CMP_STORE_LONG function has the following format:
int __CMP_STORE_LONG (volatile void *source, int old_ value, int new_value, volatile void *dest);
This function performs a conditional atomic compare and update operation involving one or two longwords in the same lock region. The value pointed to by source is compared with the longword old_value. If they are equal, the longword new_value is conditionally stored into the value pointed to by dest.
The store will not complete if the compare yields unequal values or if there is an intervening store to the lock region involved. To be in the same lock region, source and dest must point to aligned longwords in the same naturally aligned 16-byte region.
The function returns 0 if the store does not complete, and returns 1 if the store does complete.
The __CMP_STORE_QUAD function has the following format:
int __CMP_STORE_QUAD (volatile void *source, int64 old_value, int64 new_value, volatile void *dest);
This function performs a conditional atomic compare and update operation involving one or two quadwords in the same lock region. The value pointed to by source is compared with the quadword old_value. If they are equal, the quadword new_value is conditionally stored into the value pointed to by dest.
The store will not complete if the compare yields unequal values or if there is an intervening store to the lock region involved. To be in the same lock region, source and dest must point to aligned quadwords in the same naturally aligned 16-byte region.
The function returns 0 if the store does not complete, and returns 1 if the store does complete.
The __CVTGF_C function converts a double-precision, VAX G_floating- point number to a single-precision, VAX F_floating-point number. This conversion chops to single-precision; then the 8-bit exponent range is checked for overflow or underflow.
This function has the following format:
float __CVTGF_C (double operand);
The __CVTGQ function rounds a double-precision, VAX floating-point number to a 64-bit integer value and returns the result.
This function has the following format:
int64 __CVTGQ (double operand);
The __CVTTS_C function converts a double-precision, IEEE T_floating- point number to a single-precision, IEEE S_floating-point number. This conversion chops to single-precision; then the 8-bit exponent range is checked for overflow or underflow.
This function has the following format:
float __CVTTS_C (double operand);
The __CVTTQ function rounds a double-precision, IEEE T_floating- point number to a 64-bit integer value and returns the result.
This function has the following format:
int64 __CVTTQ (double operand);
The __CVTXQ function converts an X_floating-point number to a 64-bit integer value and returns the result.
This function has the following format:
int64 __CVTXQ (long double operand);
The __CVTXT_C function converts an X_floating-point number to an IEEE T_floating-point number and returns the result.
This function has the following format:
double __CVTXT_C (long double operand);
Built-in functions are provided to copy selected portions of single- and double-precision, floating-point numbers.
These built-in functions have the following format:
float __CPYSF (float operand1, float operand2); double __CPYS (double operand1, double operand2); float __CPYSNF (float operand1, float operand2); double __CPYSN (double operand1, double operand2); float __CPYSEF (float operand1, float operand2); double __CPYSE (double operand1, double operand2);
The copy sign built-ins (__CPYSF and __CPYS) fetch the sign bit in operand1, concatenate it with the exponent and fraction bits from operand2, and return the result.
The copy sign negate built-ins (__CPYSNF and __CPYSN) fetch the sign bit in operand1, complement it, concatenate it with the exponent and fraction bits from operand2, and return the result.
The copy sign exponent built-ins (__CPYSEF and __CPYSE) fetch the sign and exponent bits from operand1, concatenate them with the fraction bits from operand2, and return the result.
The __COS built-in function is functionally equivalent to its counterpart, cos, in the standard header file <math.h>.
Its format is also the same:
#include <math.h> double __COS (double x);
This built-in offers performance improvements because there is less call overhead associated with its use.
If you include <math.h>, the built-in is automatically used for all occurrences of cos. To disable the built-in, use #undef cos.
The following built-in functions provide double-precision, floating- point chopped arithmetic:
__ADDG_C | __ADDT_C | __SUBG_C | __SUBT_C |
__MULG_C | __MULT_C | __DIVG_C | __DIVT_C |
They have the following format:
double __op{G,T}_C (double operand1, double operand2);
Where op is one of ADD, SUB, MUL, DIV, and {G,T} represents VAX or IEEE floating-point arithmetic, respectively.
The result of the arithmetic operation is returned.
The __FABS built-in function is functionally equivalent to its counterpart, fabs, in the standard header file <math.h>.
Its format is also the same:
#include <math.h> double __FABS (double x);
This built-in offers performance improvements because there is no call overhead associated with its use.
If you include <math.h>, the built-in is automatically used for all occurrences of fab. To disable the built-in, use #undef fab.
The following built-in functions provide long double-precision, floating-point chopped arithmetic:
__ADDX_C | __SUBX_C |
__MULX_C | __DIVX_C |
They have the following format:
long double __opX_C (long double operand1, long double operand2);
Where op is one of ADD, SUB, MUL, DIV.
The result of the arithmetic operation is returned.
The __LABS built-in is functionally equivalent to its counterpart, labs, in the standard header file <stdlib.h>.
Its format is also the same:
#include <stdlib.h> long int __LABS (long int x);
This built-in offers 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 labs. To disable the built-in, use #undef labs.
The __LOCK_LONG and __UNLOCK_LONG functions provide a binary spinlock capability based on the low-order bit of a longword.
The __LOCK_LONG function executes in a loop waiting for the bit to be cleared and then sets it within a load-locked/store-conditional sequence; it then issues a memory barrier. The __UNLOCK_LONG function issues a memory barrier and then zeroes the longword.
The __LOCK_LONG_RETRY function returns 1 if the lock was acquired in the specified number of retries and 0 if the lock was not acquired.
The __LOCK_LONG function has one of the following formats:
int __LOCK_LONG (volatile void *address); int __LOCK_LONG_RETRY (volatile void *address, int retry);
The __UNLOCK_LONG function has the following format:
int __UNLOCK_LONG (volatile void *address);
The __MB function directs the compiler to generate a memory barrier instruction.
This function has the following format:
void __MB (void);
The __MEMCPY, __MEMMOVE, and __MEMSET built-ins are functionally equivalent to their run-time routine counterparts in the standard header file <string.h>.
Their format is also the same:
#include <string.h> void *__MEMCPY (void *s1, const void *s2, size_t size); void *__MEMMOVE (void *s1, const void *s2, size_t size); void *__MEMSET (void *s, int value, size_t size);
These built-ins offer performance improvements because there is less call overhead associated with their use.
If you include <string.h>, the built-ins are automatically used for all occurrences of memcpy, memmove, and memset. To disable the built-ins, use #undef memcpy, #undef memmove, and #undef memset.
The __OR_ATOMIC_LONG function performs a logical OR of the specified expression with the aligned longword pointed to by the address parameter within a load-locked/store-conditional code sequence.
This function has the following format:
int __OR_ATOMIC_LONG (void *address, int expression, ...);
A value of 1 is returned upon successful completion.
The __OR_ATOMIC_QUAD function performs a logical OR of the specified expression with the aligned quadword pointed to by the address parameter within a load-locked/store-conditional code sequence.
This function has the following format:
int __OR_ATOMIC_QUAD (void *address, int expression, ...);
A value of 1 is returned upon successful completion.
The following sections describe the Privileged Architecture Library Code (PALcode) instructions that are available as built-in functions.
This function is provided for program debugging. It switches the processor to kernel mode and pushes registers R2 through R7, the updated PC, and PS onto the kernel stack. It then dispatches to the address in the breakpoint vector, which is stored in a control block.
This function has the following format:
void __PAL_BPT (void);
This function is provided for error reporting. It switches the processor to kernel mode and pushes registers R2 through R7, the updated PC, and PS onto the kernel stack. It then dispatches to the address in the bugcheck vector, which is stored in a control block.
This function has the following format:
void __PAL_BUGCHK (void);
This function flushes at least the entire physical page specified by the page frame number value from any data caches associated with the current processor. After a CFLUSH is done, the first subsequent load on the same processor to an arbitrary address in the target page is fetched from physical memory.
This function has the following format:
void __PAL_CFLUSH (int value);
This function allows a process to change its mode to Executive in a controlled manner. The change in mode also results in a change of stack pointers: the old pointer is saved and the new pointer is loaded. Registers R2 through R7, PS, and PC are pushed onto the selected stack. The saved PC addresses the instruction following the CHME instruction.
This function has the following format:
void __PAL_CHME (void);
This function allows a process to change its mode to kernel in a controlled manner. The change in mode also results in a change of stack pointers: the old pointer is saved and the new pointer is loaded. Registers R2 through R7, PS, and PC are pushed onto the kernel stack. The saved PC addresses the instruction following the CHMK instruction.
This function has the following format:
void __PAL_CHMK (void);
This function allows a process to change its mode to Supervisor in a controlled manner. The change in mode also results in a change of stack pointers: the old pointer is saved and the new pointer is loaded. Registers R2 through R7, PS, and PC are pushed onto the selected stack. The saved PC addresses the instruction following the CHMS instruction.
This function has the following format:
void __PAL_CHMS (void);
This function allows a process to call a routine using the change mode mechanism. Registers R2 through R7, PS, and PC are pushed onto the current stack. The saved PC addresses the instruction following the CHMU instruction.
This function has the following format:
void __PAL_CHMU (void);
This function stalls instruction issuing until all prior instructions are guaranteed to complete without incurring aborts.
This function has the following format:
void __PAL_DRAINA (void);
This function is used for reporting run-time software conditions.
This function has the following format:
void __PAL_GENTRAP (uint64 encoded_software_trap);
This function halts the processor when executed by a process running in kernel mode. This is a privileged function.
This function has the following format:
void __PAL_HALT (void);
This function inserts an entry at the front of a longword queue in an indivisible manner. This operation is interlocked against similar operations by other processors or devices in the system. This function must have write access to header and queue entries. The pointers to head and new_entry must not be equal.
This function has the following format:
int __PAL_INSQHIL (void *head, void *new_ entry); /* At head, interlocked */
There are three possible return values:
This function inserts an entry into the front of a longword queue in an indivisible manner. This operation is interlocked against similar operations by other processors or devices in the system. This function must have write access to the header and queue entries. The pointers to head and new_entry must not be equal. All parts of the queue must be memory resident.
This function has the following format:
int __PAL_INSQHILR (void *head, void *new_ entry); /* At head, interlocked resident */
There are three possible return values:
This function inserts an entry at the front of a quadword queue in an indivisible manner. This operation is interlocked against similar operations by other processors or devices in the system. This function must have write access to header and queue entries. The pointers to head and new_entry must not be equal.
This function has the following format:
int __PAL_INSQHIQ (void *head, void *new_ entry); /* At head, interlocked */
There are three possible return values:
This function inserts an entry into the front of a quadword queue in an indivisible manner. This operation is interlocked against similar operations by other processors or devices in the system. This function must have write access to the header and queue entries. The pointers to head and new_entry must not be equal. All parts of the queue must be memory resident.
This function has the following format:
int __PAL_INSQHIQR (void *head, void *new_ entry); /* At head, interlocked resident */
There are three possible return values:
This function inserts an entry at the end of a longword queue in an indivisible manner. This operation is interlocked against similar operations by other processors or devices in the system. This function must have write access to header and queue entries. The pointers to head and new_entry must not be equal.
This function has the following format:
int __PAL_INSQTIL (void *head, void *new_ entry); /* At tail, interlocked */
There are three possible return values:
This function inserts an entry at the end of a longword queue in an indivisible manner. This operation is interlocked against similar operations by other processors or devices in the system. This function must have write access to the header and queue entries. The pointers to head and new_entry must not be equal. All parts of the queue must be memory resident.
This function has the following format:
int __PAL_INSQTILR (void *head, void *new_ entry); /* At tail, interlocked resident */
There are three possible return values:
This function inserts an entry at the end of a quadword queue in an indivisible manner. This operation is interlocked against similar operations by other processors or devices in the system. This function must have write access to header and queue entries. The pointers to head and new_entry must not be equal.
This function has the following format:
int __PAL_INSQTIQ (void *head, void *new_ entry); /* At tail, interlocked */
There are three possible return values:
This function inserts an entry at the end of a quadword queue in an indivisible manner. This operation is interlocked against similar operations by other processors or devices in the system. This function must have write access to the header and queue entries. The pointers to head and new_entry must not be equal. All parts of the queue must be memory resident.
This function has the following format:
int __PAL_INSQTIQR (void *head, void *new_ entry); /* At tail, interlocked resident */
There are three possible return values:
This function inserts a new entry after an existing entry into a longword queue. This function must have write access to header and queue entries.
This function has the following format:
int __PAL_INSQUEL (void *predecessor, void *new_ entry);
There are two possible return values:
This function inserts a new entry after an existing entry into a longword queue deferred. This function must have write access to header and queue entries.
This function has the following format:
int __PAL_INSQUEL_D (void **predecessor, void *new_ entry); /* Deferred */
There are two possible return values:
This function inserts a new entry after an existing entry into a quadword queue. This function must have write access to header and queue entries.
This function has the following format:
int __PAL_INSQUEQ (void *predecessor, void *new_ entry);
There are two possible return values:
This function inserts a new entry after an existing entry into a quadword queue deferred. This function must have write access to header and queue entries.
This function has the following format:
int __PAL_INSQUEQ_D (void **predecessor, void *new_ entry); /* Deferred */
There are two possible return values:
This function returns the quadword-aligned memory object specified by address.
This function has the following format:
uint64 __PAL_LDQP (void *address);
If the object pointed to by address is not quadword- aligned, the result is unpredictable.
This function writes the quadword value to the memory location pointed to by address.
This function has the following format:
void __PAL_STQP (void *address, uint64 value);
If the location pointed to by address is not quadword- aligned, the result is unpredictable.
These privileged functions return the contents of a particular processor register. The XXXX indicates the processor register to be read.
These functions have the following format:
unsigned int __PAL_MFPR_ASTEN (void); /* AST Enable */ unsigned int __PAL_MFPR_ASTSR (void); /* AST Summary Register */ void *__PAL_MFPR_ESP (void); /* Executive Stack Pointer */ int __PAL_MFPR_FEN (void); /* Floating-Point Enable */ int __PAL_MFPR_IPL (void); /* Interrupt Priority Level */ int __PAL_MFPR_MCES (void); /* Machine Check Error Summary */ void *__PAL_MFPR_PCBB (void); /* Privileged Context Block Base */ int64 __PAL_MFPR_PRBR (void); /* Processor Base Register */ int __PAL_MFPR_PTBR (void); /* Page Table Base Register */ void *__PAL_MFPR_SCBB (void); /* System Control Block Base */ unsigned int __PAL_MFPR_SISR (void); /* Software Interrupt Summary Register */ void *__PAL_MFPR_SSP (void); /* Supervisor Stack Pointer */ int64 __PAL_MFPR_TBCHK (void *address); /* Translation Buffer Check */ void *__PAL_MFPR_USP (void); /* User Stack Pointer */ void *__PAL_MFPR_VPTB (void); /* Virtual Page Table */ int64 __PAL_MFPR_WHAMI (void); /* Who Am I */
These privileged functions load a value into one of the special processor registers. The XXXX indicates the processor register to be loaded.
These functions have the following format:
void __PAL_MTPR_ASTEN (unsigned int mask); /* AST Enable */ void __PAL_MTPR_ASTSR (unsigned int mask); /* AST Summary Register */ void __PAL_MTPR_DATFX (int value); /* Data Alignment Trap Fixup */ void __PAL_MTPR_ESP (void *address); /* Executive Stack Pointer */ void __PAL_MTPR_FEN (int value); /* Floating- Point Enable */ void __PAL_MTPR_IPIR (int64 number); /* Interprocessor Interrupt Request */ int __PAL_MTPR_IPL (int value); /* Interrupt Priority Level */ void __PAL_MTPR_MCES (int value); /* Machine Check Error Summary */ void __PAL_MTPR_PRBR (int64 value); /* Processor Base Register */ void __PAL_MTPR_SCBB (void *address); /* System Control Block Base */ void __PAL_MTPR_SIRR (int level); /* Software Interrupt Request Register */ void __PAL_MTPR_SSP (int *address); /* Supervisor Stack Pointer */ void __PAL_MTPR_TBIA (void); /* User Stack Pointer */ void __PAL_MTPR_TBIAP (void); /* Translation Buffer Invalidate All Process */ void __PAL_MTPR_TBIS (void *address); /* Translation Buffer Invalidate Single */ void __PAL_MTPR_TBISD (void *address); /* Translation Buffer Invalidate Single Data */ void __PAL_MTPR_TBISI (void *address); /* Translation Buffer Invalidate Single Instruction */ void __PAL_MTPR_USP (void *address); /* User Stack Pointer */ void __PAL_MTPR_VPTB (void *address); /* Virtual Page Table */
This function checks the read accessibility of the first and last byte of the given address and length pair.
This function has the following format:
int __PAL_PROBER (const void *base_address, int length, char mode);
There are two possible return values:
This function checks the write accessibility of the first and last byte of the given address and length pair.
This function has the following format:
int __PAL_PROBEW (const void *base_address, int length, char mode);
There are two possible return values:
This function returns the Processor Status (PS).
This function has the following format:
uint64 __PAL_RD_PS (void);
This function removes the first entry from a longword queue in an indivisible manner. This operation is interlocked against similar operations by other processors or devices in the system. This function must have write access to the header and queue entries.
This function has the following format:
int __PAL_REMQHIL (void *head, void **removed_ entry); /* At head, interlocked */
There are four possible return values:
This function removes the first entry from a longword queue in an indivisible manner. This operation is interlocked against similar operations by other processors or devices in the system. This function must have write access to the header and queue entries. All parts of the queue must be memory resident.
This function has the following format:
int __PAL_REMQHILR (void *head, void **removed_ entry); /* At head, interlocked resident */
There are four possible return values:
This function removes the first entry from a quadword queue in an indivisible manner. This operation is interlocked against similar operations by other processors or devices in the system. This function must have write access to the header and queue entries.
This function has the following format:
int __PAL_REMQHIQ (void *head, void **removed_ entry); /* At head, interlocked */
There are four possible return values:
This function removes the first entry from a quadword queue in an indivisible manner. This operation is interlocked against similar operations by other processors or devices in the system. This function must have write access to the header and queue entries. All parts of the queue must be memory resident.
This function has the following format:
int __PAL_REMQHIQR (void *head, void **removed_ entry); /* At head, interlocked resident */
There are four possible return values:
This function removes the last entry from a longword queue in an indivisible manner. This operation is interlocked against similar operations by other processors or devices in the system. This function must have write access to the header and queue entries.
This function has the following format:
int __PAL_REMQTIL (void *head, void **removed_ entry); /* At tail, interlocked */
There are four possible return values:
This function removes the last entry from a longword queue in an indivisible manner. This operation is interlocked against similar operations by other processors or devices in the system. This function must have write access to the header and queue entries. All parts of the queue must be memory resident.
This function has the following format:
int __PAL_REMQTILR (void *head, void **removed_ entry); /* At tail, interlocked resident */
There are four possible return values:
This function removes the last entry from a quadword queue in an indivisible manner. This operation is interlocked against similar operations by other processors or devices in the system. This function must have write access to the header and queue entries.
This function has the following format:
int __PAL_REMQTIQ (void *head, void **removed_ entry); /* At tail, interlocked */
There are four possible return values:
This function removes the last entry from a quadword queue in an indivisible manner. This operation is interlocked against similar operations by other processors or devices in the system. This function must have write access to the header and queue entries. All parts of the queue must be memory resident.
This function has the following format:
int __PAL_REMQTIQR (void *head, void **removed_ entry); /* At tail, interlocked resident */
There are four possible return values:
This function removes an entry from a longword queue. This function must have write access to header and queue entries.
This function has the following format:
int _PAL_REMQUEL (void *entry, void **removed_ entry);
There are three possible return values:
This function removes an entry from a longword queue deferred. This function must have write access to header and queue entries.
This function has the following format:
int __PAL_REMQUEL_D (void **entry, void **removed_ entry); /* Deferred */
There are three possible return values:
This function removes an entry from a quadword queue. This function must have write access to header and queue entries.
This function has the following format:
int __PAL_REMQUEQ (void *entry, void **removed_ entry);
There are three possible return values:
This function removes an entry from a quadword queue deferred. This function must have write access to header and queue entries.
This function has the following format:
int __PAL_REMQUEQ_D (void **entry, void **removed_ entry); /* Deferred */
There are three possible return values:
This function returns ownership of the data structure that contains the current hardware privileged context (the HWPCB) to the operating system and passes ownership of the new HWPCB to the processor.
This function has the following format:
void __PAL_SWPCTX (void *address);
This function swaps the previous state of the Asynchronous System Trap (AST) enable bit for the new state. The new state is supplied in bit 0 of new_state_mask. The previous state is returned, zero-extended.
A check is made to determine if an AST is pending. If the enabling conditions are present for an AST at the completion of this instruction, the AST occurs before the next instruction.
This function has the following format:
unsigned int __PAL_SWASTEN (int new_state_mask);
This function writes the low-order three bits of mask into the Processor Status software field (PS<SW>).
This function has the following format:
void __PAL_WR_PS_SW (int mask);
The __RPCC function reads the current process cycle counter.
This function has the following format:
uint64 __RPCC (void);
The __SIN built-in is functionally equivalent to its counterpart, sin, in the standard header file <math.h>.
Its format is also the same:
#include <math.h> double __SIN (double x);
This built-in offers performance improvements because there is less call overhead associated with its use.
If you include <math.h>, the built-in is automatically used for all occurrences of sin. To disable the built-in, use #undef sin.
The following built-in functions provide single-precision, floating- point chopped arithmetic:
__ADDF_C | __ADDS_C | __SUBF_C | __SUBS_C |
__MULF_C | __MULS_C | __DIVF_C | __DIVS_C |
They have the following format:
float __op{F,S}_C (float operand1, float operand2);
Where op is one of ADD, SUB, MUL, DIV, and {F,S} represents VAX or IEEE floating-point arithmetic, respectively.
The result of the arithmetic operation is returned.
The __INTERLOCKED_TESTBITCC_QUAD function performs the following functions in interlocked fashion:
This function has one of the following formats:
int __INTERLOCKED_TESTBITCC_QUAD (volatile void *address, int bit_position); int __INTERLOCKED_TESTBITCC_QUAD_RETRY (volatile void *address, int bit_position, int retry, int *status);
The __TESTBITCCI function performs the following operations in interlocked fashion:
This function has the following format:
int __TESTBITCCI (void *address, int position, ...);
The __INTERLOCKED_TESTBITSS_QUAD function performs the following functions in interlocked fashion:
This function has one of the following formats:
int __INTERLOCKED_TESTBITSS_QUAD (volatile void *address, int bit_position); int __INTERLOCKED_TESTBITSS_QUAD_RETRY (volatile void *address, int expression, int retry, int *status);
The __TESTBITSSI function performs the following operations in interlocked fashion:
This function has the following format:
int __TESTBITSSI (void *address, int position, ...);
The __TRAPB function allows software to guarantee that, in a pipeline implementation, all previous arithmetic instructions will be completed without incurring any arithmetic traps before any instructions after the TRAPB instruction are issued.
This function has the following format:
void __TRAPB (void);
The __UMULH function performs a quadword multiply high instruction.
This function has the following format:
uint64 __UMULH (uint64 operand1, uint64 operand2);
The two operands are multiplied as unsigned integers to produce a 128-bit result. The high-order 64 bits are returned. Note that uint64 is a typedef for the Alpha data type unsigned __int64.
The following sections describe the DEC C built-in functions available on OpenVMS VAX systems.
The DEC C built-in functions use enumerated typedefs to define possible return values. We recommend that you use the enumerated types to store and compare return values.
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.
The _ADAWI function has the following format:
typedef enum { _adawi_sum_neg=-1, _adawi_sum_zero, _adawi_sum_pos} _ADAWI_STATUS; _ADAWI_STATUS _ADAWI (short __src, short *__ dest);
There are three possible return values:
The _BBCCI function performs the following functions in interlocked fashion:
The _BBCCI function has the following format:
typedef enum { _bbcci_oldval_1, _bbcci_oldval_0} _BBCCI_STATUS; _BBCCI_STATUS _BBCCI (int __position, void *__ address);
The return value of _bbcci_oldval_1 (0) or _bbcci_oldval_0 (1) is the complement of the value of the specified bit before being cleared.
The _BBSSI function performs the following functions in interlocked fashion:
The _BBSSI function has the following format:
typedef enum { _bbssi_oldval_0, _bbcci_oldval_1} _BBSSI_STATUS; _BBSSI_STATUS _BBSSI (int __position, void *__ address);
The return value of _bbssi_oldval_0 (0) or _bbssi_oldval_1 (1) is the value of the specified bit before being set.
The _FFC function finds the position of the first clear bit in a field. The bits are tested for clear status starting at bit 0 and extending to the highest bit in the field.
The _FFC function has the following format:
typedef enum { _ff_bit_not_found, _ff_bit_found} _FF_STATUS; _FF_STATUS _FFC (int __start, char __ size, const void *__base, int *__ positionbox);
There are two possible return values:
The _FFS function finds the position of the first set bit in a field. The bits are tested for set status starting at bit 0 and extending to the highest bit in the field.
The _FFS function has the following format:
typedef enum { _ff_bit_not_found, _ff_bit_found} _FF_STATUS; _FF_STATUS _FFS (int __start, char __ size, const void *__base, int *__ positionbox);
There are two possible return values:
The _HALT function halts the processor when executed by a process running in kernel mode. This is a privileged function.
The _HALT function has the following format:
void _HALT (void);
The _INSQHI function inserts an entry into the front of a queue in an indivisible manner. This operation is interlocked against similar operations by other processors or devices in the system.
The _INSQHI function has the following format:
typedef enum {_insqi_inserted_many, _insqi_not_inserted, _insqi_ inserted_only} _INSQI_STATUS; _INSQI_STATUS _INSQHI (void *__new_entry, void *__ head);
There are three possible return values:
The _INSQTI function inserts an entry at the end of a queue in an indivisible manner. This operation is interlocked against similar operations by other processors or devices in the system.
The _INSQTI function has the following format:
typedef enum {_insqi_inserted_many, _insqi_not_inserted, _insqi_ inserted_only} _INSQI_STATUS; _INSQI_STATUS _INSQTI (void *__new_entry, void *__ head);
There are three possible return values:
The _INSQUE function inserts a new entry into a queue following an existing entry.
The _INSQUE function has the following format:
typedef enum { _insque_inserted_only, _insque_inserted_many} _ INSQUE_STATUS; _INSQUE_STATUS _INSQUE (void *__new_entry, void *__ predecessor);
There are two possible return values:
The _LOCC function locates the first character in a string matching the target character.
The _LOCC function has the following format:
unsigned short _LOCC (char __target, unsigned short __length, const char *__string, ...);
If the target character is found, the return value is the number of bytes remaining in the string; otherwise, the return value is 0.
The _MFPR function returns the contents of a processor register. This is a privileged function.
The _MFPR function has the following formats:
void _MFPR (int register_num, int *destination); void _MFPR (int register_num, unsigned int *destination);
The _MOVC3 function copies a block of memory.
The _MOVC3 function has the following format:
void _MOVC3 (unsigned short __length, const char *_ _src, char *__dest, ...);
A pointer to a pointer to char. The _MOVC3 function sets this output argument to the address of the byte beyond the source string. Although this is an optional argument, it is required if enddest is specified.
A pointer to a pointer to char. The _MOVC3 function sets this output argument to the address of the byte beyond the destination string.
The _MOVC5 function allows the source string specified by the pointer and length pair to be moved to the destination string specified by the other pointer and length pair. If the source string is smaller than the destination string, the destination string is padded with the specified character.
The _MOVC5 function has the following format:
void _MOVC5 (unsigned short __srclen, const char *_ _src, char __fill, unsigned short __destlen, char *__ dest, ...);
A pointer to an unsigned short integer. The _MOVC5 function sets this output argument to the number of unmoved bytes remaining in the source string. This argument is optional if the endscr argument is not specified.
A pointer to a pointer to char. The _MOVC5 function sets this output argument to the address of the byte beyond the source string. Although this is an optional argument, it is required if enddest is specified.
A pointer to a pointer to char. The _MOVC5 function sets this output argument to the address of the byte beyond the destination string.
The _MOVPSL function stores the value of the Processor Status Longword (PSL).
The _MOVPSL function has the following format:
void _MOVPSL (void *__psl);
The _MTPR function loads a value into one of the special processor registers. It is a privileged function.
The _MTPR function has the following format:
int _MTPR (int src, int register_num);
The return value is the V condition flag from the Processor Status Longword (PSL).
The _PROBER function checks to see if you can read the first and last byte of the given address and length pair.
The _PROBER function has the following format:
typedef enum { _probe_not_accessible, _probe_accessible} _PROBE_ STATUS; _PROBE_STATUS _PROBER (char __mode, unsigned short __length, const void *__address);
There are two possible return values:
The _PROBEW function checks the write accessibility of the first and last byte of the given address and length pair.
The _PROBEW function has the following format:
typedef enum { _probe_not_accessible, _probe_accessible} _PROBE_ STATUS; _PROBE_STATUS _PROBEW (char __mode, unsigned short __length, const void *__address);
There are two possible return values:
The _READ_GPR function returns the value of a general-purpose register.
The _READ_GPR function has the following format:
int _READ_GPR (int register_num);
The return value is the value of the general-purpose register.
The _REMQHI function removes the first entry from the queue in an indivisible manner. This operation is interlocked against similar operations by other processors or devices in the system.
The _REMQHI function has the following format:
typedef enum { _remqi_removed_more, _remqi_not_removed, _remqi_ removed_empty, _remqi_empty} _REMQI_STATUS; _REMQI_STATUS _REMQHI (void *__head, void *__ removed_entry);
There are four possible return values:
The _REMQTI function removes the last entry from the queue in an indivisible manner. This operation is interlocked against similar operations by other processors or devices in the system.
The _REMQTI function has the following format:
typedef enum { _remqi_removed_more, _remqi_not_removed, _remqi_ removed_empty, _remqi_empty} _REMQI_STATUS; _REMQI_STATUS _REMQTI (void *__head, void *__ removed_entry);
There are four possible return values:
The _REMQUE function removes an entry from a queue.
The _REMQUE function has the following format:
typedef enum { _remque_removed_more, _remque_removed_empty, _remque_empty} _REMQUE_STATUS; _REMQUE_STATUS _REMQUE (void *__entry, void *__ removed_entry);
There are three possible return values:
The _SCANC function locates the first character in a string with the desired attributes. The attributes are specified through a table and a mask.
The _SCANC function has the following format:
unsigned short _SCANC (unsigned short __length, const char *__string, const char *__table, char __ mask, ...);
The return value is the number of bytes remaining in the string if a match was found; otherwise, the return value is 0.
The _SKPC function locates the first character in a string that does not match the target character.
The _SKPC function has the following format:
unsigned short _SKPC (char __target, unsigned short __length, const char *__string, ... );
The return value is the number of bytes remaining in the string if an unequal byte was located; otherwise, the return value is 0.
The _SPANC function locates the first character in a string without certain attributes. The attributes are specified through a table and a mask.
The _SPANC function has the following format:
unsigned short _SPANC (unsigned short __length, const char *__string, const char *__table, char __ mask, ...);
The return value is the number of bytes remaining in the string if a match was found; otherwise, the return value is 0.