Miscellaneous Directives

List and description of miscellaneous directives.

[no]autothread

#pragma _CRI autothread
#pragma _CRI noautothread
Scope: Local

The [no]autothread directive turns autothreading on or off for selected blocks of code.

[no]bounds

#pragma _CRI bounds
#pragma _CRI nobounds
The bounds directive specifies that pointer and array references are to be checked. The nobounds directive specifies that this checking is to be disabled. For each dimension, the checks verify that the subscript is greater than or equal to 0 and less than the upper bound. For pointers, the upper bound is computed based on the amount of the memory on the node. This amount is scaled at runtime by the number of UPC threads in the job for UPC pointers-to-shared with definite blocksize. For arrays, the (possibly implicit) declared upper bound of the dimension is used. If the dimension is the THREADS-scaled dimension of a UPC shared array with definite blocksize, the upper bound for the check is computed at runtime based on the number of UPC threads in the job. Both directives may be used only within function bodies. They apply until the end of the function body or until another bounds/nobounds directive appears. They ignore block boundaries.

Use #pragma _CRI bounds

int a[30];
#pragma _CRI bounds
void f(void)
{
   int x;
   x = a[30];
   .
   .
   .
}

cache

#pragma _CRI cache base_name [,base_name ...]
base_name
The base name of the object that should be placed into the cache. This can be the base name of any object such as an array, scalar structure, and so on, without member references like C[10]. If a pointer in the list is specified, only the references, not the pointer itself, are cached.

The cache directive asserts that all memory operations with the specified symbols as the base are to be allocated in cache. This is an advisory directive. The cache directive is meaningful for stores in that it allows the user to override a decision made by the automatic cache management. This directive may be locally overridden by the use of a #pragma loop_info directive. This directive overrides automatic cache management decisions. To use the directive, place it only in the specification part, before any executable statement.

cache_nt

#pragma _CRI cache_nt base_name [,base_name ...]
base_name
The base name of the object that should use non-temporal reads and writes. This can be the base name of any object such as an array, scalar structure, and so on, without member references like C[10]. If a pointer in the list is specified, only the references, not the pointer itself, have the cache non-temporal property.

Use this directive to identify objects that should not be placed in cache. This is an advisory directive that specifies objects that should use non-temporal reads and writes.

This directive overrides the automatic cache management level that was specified using the -h cachen option on the compiler command line. This directive may be overridden locally by use of a loop_info directive.

duplicate

#pragma _CRI duplicate actual as dupname[, dupname] ...
#pragma _CRI duplicate actual as (dupname[, dupname] ...)
Scope: Global

The actual argument is the name of the actual function to which duplicate names will be assigned. The dupname list contains the duplicate names that will be assigned to the actual function. The dupname list may be optionally parenthesized. The word as must appear as shown between the actual argument and the comma-separated list of dupname arguments. The duplicate directive can appear anywhere in the source file, in global scope. The actual name specified on the directive line must be defined somewhere in the source as an externally accessible function; the actual function cannot have a static storage class.

Because duplicate names are simply additional names for functions and are not functions themselves, they cannot be declared or defined anywhere in the compilation unit. To avoid aliasing problems, duplicate names may not be referenced anywhere within the source file, including appearances on other directives. In other words, duplicate names may only be referenced from outside the compilation unit in which they are defined.

#pragma _CRI duplicate

#include <complex.h>
extern void maxhits(void);
#pragma _CRI duplicate maxhits as count, quantity /* OK */
void maxhits(void)
{
#pragma _CRI duplicate maxhits as tempcount
/* Error: #pragma _CRI duplicate can't appear in local scope */
}
double _Complex minhits;
#pragma _CRI duplicate minhits as lower_limit
/* Error: minhits is not declared as a function */
extern void derivspeed(void);
#pragma _CRI duplicate derivspeed as accel
/* Error: derivspeed is not defined */
static void endtime(void)
{
}
#pragma _CRI duplicate endtime as limit
/* Error: endtime is defined as a static function */

#pragma _CRI duplicate

The directive argument dupname cannot be referenced in same compilation unit.
void converter(void)
{
structured(void);
}
#pragma _CRI duplicate converter as factor, multiplier 
/* OK */
void remainder(void)
{
}
#pragma _CRI duplicate remainder as factor, structured
/* Error: factor and structured are referenced in this file */

#pragma _CRI duplicate

Use duplicate names to provide alternate external names for functions.
main.c:
extern void fctn(void), FCTN(void);
main()
{
fctn();
FCTN();
}
fctn.c:
#include <stdio.h>
void fctn(void)
{
printf("Hello world\n");
}
#pragma _CRI duplicate fctn as FCTN
Files main.c and fctn.c are compiled and linked using the following command line: cc main.c fctn.c. When the executable file a.out is run, the program generates the following output:
Hello world
Hello world

ident

#pragma _CRI ident text

The ident pragma directs the compiler to store the string indicated by text into the object (.o) file. This can be used to place a source identification string into an object file.

memory

#pragma memory (list-of-attributes) [if(if-expr)]
heap-allocation-statement

#pragma memory (list-of-attributes) [if(if-expr)] list-of-vars
variable-declaration

The memory directive is a mechanism that allows developers to place variables and memory allocations in a specific type of memory. This directive is intended for systems with more than one type of explicitly-addressable memory, particularly when the entire application footprint will not fit into the desired type of memory (or the developer would like to place different memory regions in different types of memory). For example, the Intel Xeon Phi (codenamed Knights Landing or KNL) has both "normal" DDR memory and a limited capacity of "high-bandwidth" MCDRAM memory. Please refer to the memory(7) man page for full details on using this directive.

message

#pragma _CRI message "text"

The message directive directs the compiler to write the message defined by text to stderr as a warning message. Unlike the error directive, the compiler continues after processing a message directive.

#pragma _CRI message

#define FLAG 1
#ifdef FLAG
#pragma _CRI message "FLAG is Set"
#else
#pragma _CRI message "FLAG is NOT Set"
#endif

optimize

#pragma optimize [(option[ option])]

The optimize directive enables optimization in the function in which it appears, overriding the optimization level set via the compiler command line. The optimize directive with no option specified is equivalent to optimize -O2.

The optimize directive accepts the following subset of the command line options which control optimization. Refer to craycc(1) for a description of these options.
  • -h acc
  • -h add_paren
  • -h [no]aggress
  • -h [no]autothread
  • -h [no]autoprefetch
  • -h cache n
  • -h fp_trap
  • -h fusion n
  • -h init_stack_value
  • -h loop_trips
  • -h omp
  • -h overindex
  • -h [no]pattern
  • -h scalar n
  • -h thread n
  • -h unroll n
  • -h vector n

See the optimize(7) man page for more information.

[no]opt

#pragma _CRI opt
#pragma _CRI noopt
Scope: Global

The noopt directive disables all automatic optimizations and causes optimization directives to be ignored in the source code that follows the directive. Disabling optimization removes various sources of potential confusion in debugging. The opt directive restores the state specified on the command line for automatic optimization and directive recognition. These directives have global scope and override related command line options.

The following example illustrates the use of the opt and noopt compiler directives:
#include <stdio.h>

void sub1(void)
{
        printf("In sub1, default optimization\n");
}

#pragma _CRI noopt

void sub2(void)
{
        printf("In sub2, optimization disabled\n");
}
#pragma _CRI opt

void sub3(void)
{
        printf("In sub3, optimization enabled\n");
}

main()
{
        printf("Start main\n");
        sub1();
        sub2();
        sub3();
}

prefetch

#pragma _CRI prefetch [([lines(num)][, level(num)][, write][, nt])] var[, var] ...
lines(num)
Specifies the number of cache lines to be prefetched. num is an expression that evaluates to an integer constant at compilation time. By default, the number of cache lines prefetched is 1.
level(num)
Specifies the level of cache into which data is loaded. num is an expression that evaluates to an integer constant at compilation time. The cache level defaults to 1, the level closest to the processing unit. This level specification has little effect for current x86 targets.
write
Specifies that the prefetch is for data to be written. When data is to be written, a prefetch instruction can move a block into the cache so that the expected store will be to the cache. Prefetch for write generally brings the data into the cache in an exclusive or modified state. By default, the prefetch is for data to be read. If the target architecture does not support prefetch for write, the prefetch will automatically become a prefetch for read.
nt
Specifies that the prefetch is for non-temporal data. By default, the prefetch is for temporal data. Data with temporal locality (persistence), is expected to be accessed multiple times.

The general prefetch directive instructs the compiler to generate explicit prefetch instructions which load data from memory into cache prior to read or write access. The memory location to be prefetched is defined by var, which specifies any valid variable, member, or array element reference.

The compiler issues the prefetch instruction when it encounters the prefetch directive. The directive allows the user to influence almost every aspect of prefetch behavior. The default behavior prefetches one cache line, into L1 cache, for read access, and assumes temporal locality. The prefetch directive can be used inside and outside of loops, in a loop preamble, or before a function call to reduce cache-miss memory latency. The compiler will attempt to avoid multiple prefetches to the same cache line, which can be created as a result of optimization. All variables specified on the same prefetch directive line share the same behavior. If different behavior is needed for different variables, use multiple prefetch directive lines. The general prefetch directive supersedes the effects of any relevant loop_info [no]prefetch directives and the -h [no]autoprefetch command line option. The Cray Fortran compiler command line option -x prefetch can be used to disable all general prefetch directives in Fortran source code. The compiler command line option -h nopragma=prefetch can be used to disable all general prefetch directives in C and C++ source code.

prefetch directive

void
add( long * restrict a, long * restrict b, const int n )
{
   int i;
#pragma _CRI prefetch (lines(2)) b[0]  
   for ( i = 0; i < n; i++ ) {
#pragma _CRI prefetch b[i+16]
      a[i] += b[i];
   }
   return;
}

probability directives

#pragma probability const
#pragma probability_almost_always
#pragma probability_almost_never
const
Expression that evaluates to a floating point constant at compilation time. (0.0 <= const <= 1.0.)

The probablity directives specify information used by interprocedure analysis (IPA) and the optimizer to produce faster code sequences. The specified probability is a hint, rather than a statement of fact. This information is used to guide inlining decisions, branch elimination optimizations, branch hint marking, and the choice of the optimal algorithmic approach to the vectorization of conditional code. These directives can appear anywhere executable code is legal. Each directive applies to the block of code where it appears. It is important to realize that the directive should not be applied to a conditional test directly; rather, it should be used to indicate the relative probability of a then or else branch being executed.

Specify almost_never and almost_always by using the probability const values 0.0 and 1.0, respectively.

probability directive

This example states that the probability of entering the block of code with the assignment statement is 0.3 or 30%. This also means that a[i] is expected to be greater than b[i] 30% of the time. Note that the probability directive appears within the conditional block of code, rather than before it. This removes some of the ambiguity that has plagued other implementations that tie the directive directly to the conditional code.

   if ( a[i] > b[i] ) {
#pragma probability 0.3
        a[i] = b[i];
}

__builtin_expect intrinsic & probablity directive

These two code fragments are roughly equivalent.

if ( __builtin_expect( a[i] > b[i], 0 ) ) {
    a[i] = b[i];
}
   if ( a[i] > b[i] ) {
#pragma _CRI probability_almost_never
        a[i] = b[i];
}

weak

#pragma _CRI weak var
var
The name of an external
#pragma _CRI weak sym1 = sym2
sym1
Defines an externally visible weak symbol
sym2
Defines an externally visible strong symbol defined in the current compilation.
Scope: Global

When statically linking, the weak directive specifies an external identifier that may remain unresolved throughout the compilation. This directive has no effect when dynamically linking. A weak external reference can be a reference to a function or to a data object. A weak external does not increase the total memory requirements of the program.The first form allows the declaration of one or more weak references on one line. The second form allows the assignment of a strong reference to a weak reference. The weak directive must appear at global scope.

Declaring an object as a weak external directs the linker to do one of these tasks:
  • Link the object only if it is already linked (a strong reference exists); otherwise, leave it is as an unsatisfied external. The linker does not display an unsatisfied external message if weak references are not resolved.
  • If a strong reference is specified in the weak directive, resolve all weak references to it.

The linker treats weak externals as unsatisfied externals, so they remain silently unresolved if no strong reference occurs during compilation. Be responsible to ensure that run time references to weak external names do not occur unless the linker (using some "strong” reference elsewhere) has actually linked the entry point in question.

weak directive

Attributes of weak externals depend on the form of the directive:
  • First form, weak externals must be declared, but not defined or initialized, in the source file.
  • Second form, weak externals may be declared, but not defined or initialized, in the source file.
  • Either form, weak externals cannot be declared with a static storage class.
extern long x;
#pragma _CRI weak x /* x is a weak external data object */
extern void f(void);
#pragma _CRI weak f /* f is a weak external function */

extern void g(void);
#pragma _CRI weak g=fun;   /* g is a weak external function
                               with a strong reference to fun */

long y = 4;
#pragma _CRI weak y   /* ERROR - y is actually defined */

static long z;
#pragma _CRI weak z   /* ERROR - z is declared static */

void fctn(void)
{
#pragma _CRI weak a   /* ERROR - directive must be at global scope */
}