Blocks

OpenCL C 2.0 adds support for the clang block syntax.

Example: int multiplier = 7; int (^myBlock)(int) = ^(int num) { return num * multiplier; };

Description

OpenCL C 2.0 adds support for the clang block syntax. Like function types, the Block type is a pair consisting of a result value type and a list of parameter types very similar to a function type. Blocks are intended to be used much like functions with the key distinction being that in addition to executable code they also contain various variable bindings to automatic (stack) or global memory.

This syntax is already part of the clang source tree on which most vendors have based their OpenCL implementations. Additionally, blocks based closures are supported by the clang open source C compiler as well as Mac OS X’s C and Objective C compilers. Specifically, Mac OS X’s Grand Central Dispatch allows applications to queue tasks as a block.

Declaring and Using a Block

You use the ^ operator to declare a Block variable and to indicate the beginning of a Block literal. The body of the Block itself is contained within {}, as shown in the example (as usual with C, ; indicates the end of the statement).

The Block is able to make use of variables from the same scope in which it was defined.

If you declare a Block as a variable, you can then use it just as you would a function:


    int multiplier = 7;
    int (^myBlock)(int) = ^(int num) {
        return num * multiplier;
    };

    printf(“%d\n”, myBlock(3));
    // prints 21

Declaring a Block Reference

Block variables hold references to Blocks. You declare them using syntax similar to that you use to declare a pointer to a function, except that you use ^ instead of *. The Block type fully interoperates with the rest of the C type system. The following are valid Block variable declarations:


    void (^blockReturningVoidWithVoidArgument)(void);
    int (^blockReturningIntWithIntAndCharArguments)(int, char);

A Block that takes no arguments must specify void in the argument list. A Block reference may not be dereferenced via the pointer dereference operation *, and thus a Block’s size may not be computed at compile time.

Blocks are designed to be fully type safe by giving the compiler a full set of metadata to use to validate use of Blocks, parameters passed to blocks, and assignment of the return value.

You can also create types for Blocks—doing so is generally considered to be best practice when you use a block with a given signature in multiple places:


    typedef float (^MyBlockType)(float, float);

    MyBlockType myFirstBlock = // …;
    MyBlockType mySecondBlock = // …;

Block Literal Expressions

A Block literal expression produces a reference to a Block. It is introduced by the use of the ^ token as a unary operator.


    Block_literal_expression ::= ^ block_decl compound_statement_body
    block_decl ::=
    block_decl ::= parameter_list
    block_decl ::= type_expression

where type expression is extended to allow ^ as a Block reference where * is allowed as a function reference.

The following Block literal:


    ^ void (void) { printf("hello world\n"); }

produces a reference to a Block with no arguments with no return value.

The return type is optional and is inferred from the return statements. If the return statements return a value, they all must return a value of the same type. If there is no value returned the inferred type of the Block is void; otherwise it is the type of the return statement value. If the return type is omitted and the argument list is ( void ), the ( void ) argument list may also be omitted.

So:


    ^ ( void ) { printf("hello world\n"); }

and:


    ^ { printf("hello world\n"); }

are exactly equivalent constructs for the same expression.

The compound statement body establishes a new lexical scope within that of its parent. Variables used within the scope of the compound statement are bound to the Block in the normal manner with the exception of those in automatic (stack) storage. Thus one may access functions and global variables as one would expect, as well as static local variables.

Local automatic (stack) variables referenced within the compound statement of a Block are imported and captured by the Block as const copies. The capture (binding) is performed at the time of the Block literal expression evaluation.

The compiler is not required to capture a variable if it can prove that no references to the variable will actually be evaluated.

The lifetime of variables declared in a Block is that of a function.

Block literal expressions may occur within Block literal expressions (nested) and all variables captured by any nested blocks are implicitly also captured in the scopes of their enclosing Blocks.

A Block literal expression may be used as the initialization value for Block variables at global or local static scope.

You can also declare a Block as a global literal in program scope.


    int GlobalInt = 0;

    int (^getGlobalInt)(void) = ^{ return GlobalInt; };

Control Flow

The compound statement of a Block is treated much like a function body with respect to control flow in that continue, break and goto do not escape the Block.

Restrictions

The following Blocks features are currently not supported in OpenCL C.

  • The __block storage type.

  • The Block_copy() and Block_release() functions that copy and release Blocks.

  • Blocks with variadic arguments.

  • Arrays of Blocks.

Additional restrictions in addition to the above feature restrictions are:

  • A Block variable must be assigned to a Block literal expression that can be determined at compile time.

  • The unary operators (* and &) cannot be used with a Block.

  • Blocks cannot be used as expressions of the ternary selection operator (?:).

  • A Block cannot reference another Block.

Specification

OpenCL Specification

Copyright © 2007-2013 The Khronos Group Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and/or associated documentation files (the "Materials"), to deal in the Materials without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Materials, and to permit persons to whom the Materials are furnished to do so, subject to the condition that this copyright notice and permission notice shall be included in all copies or substantial portions of the Materials.