Special Forms

angavrilov edited this page Sep 13, 2010 · 3 revisions

This page describes special forms supported by the GPU code translator.

Variable definition

  • let
  • let*

These forms are fully supported. Types of variables without explicit type declarations are inferred from their initialization forms. The NIL constant is allowed as an initialization form for variables of any type; for types other than boolean it denotes lack of any initialization.

Special variable bindings are implemented by transforming them into normal lexical variables after function inlining. Likewise, referenced specials without local bindings are converted to hidden kernel parameters. This is transparent except for the fact that assignments don’t propagate out of kernel invocations, and are not visible to other GPU threads.

The following expressions are handled specially when used as variable initialization forms:

  • (unevaluated expr)

When used as an initform this denotes that the expression should be used to derive the type of the variable, but not actually evaluated.

  • (make-array ’(dims…) :element-type ’type)

This has the same meaning as a fully specified array type declaration. Any other combination of specified arguments is an error.

Variable assignment

  • setq


  • setf

Supported as a special form; allows some built-in functions as an assignment target.

(setf (values ...) ...)
is transformed to multiple-value-setq.

Macro definition

  • macrolet
  • symbol-macrolet

Fully supported.

Local function definition

  • flet
  • labels
  • lambda

Supported via complete and unconditional inlining. Note that since hardware GPU threads don’t have stacks, the C compiler works this way too.

Keyword arguments are supported, provided that the keywords are specified directly as constants in the function calls. Recursion is not allowed.

  • function

Since funcall and apply are not implemented, it is useless at the moment.

Multiple-value return

  • values

Supported as a special form. Arguments are guaranteed to be evaluated in standard order.

  • multiple-value-setq

Supported as a special form; only allows simple variables as lvalues.

  • multiple-value-bind

Supported as a special form. Since all variables must have a definite type, the value expression must explicitly provide values for all listed variables.

  • multiple-value-call

Supported in the simplest form where the function is a lambda and there is only one argument, via transformation to multiple-value-bind.

  • multiple-value-prog1



  • if

Supported. The condition expression must return a boolean value.

Control flow

  • progn
  • block
  • return-from
  • tagbody
  • go


  • catch
  • throw

Supported for constant tag argumens via transformation to block & return-from after function inlining.


  • locally


  • the

Supported. Unlike the standard lisp behavior, ‘the’ forces a cast to the resulting type.

  • cast

A new special form. Has the same syntax and behavior as the, but makes the intention more explicit (cast also never warns about conversions that might lose precision).

Supported declarations:

  • type
  • special
  • optimize

Handled in a standard way.

  • gpu-optimize

Similar to optimize. Guaranteed to override it if specified at the same nesting level. Allows some gpu-specific properties.

  • shared

Marks variable bindings that must be allocated in shared memory. The syntax is similar to ignore or dynamic-extent.

This declaration can only be used with let and let*. The variables cannot have any initialization forms, except for the ones listed above as specially handled. Variable identity is determined via the binding form before function inlining.

Unsupported standard forms

  • eval-when

Handled identically to progn.

  • load-time-value
  • unwind-protect

Not implemented due to the lack of obvious use cases in GPU code.

  • progv

Cannot be supported because special bindings are statically transformed to lexicals.

Verbatim C code

When strictly necessary, the following special form can be used to insert arbitrary C expressions into the code:

  • (gpu::inline-verbatim (ret-type &key statement?) body…)

The return type must be specified in internal format, which is identical to CFFI syntax for atomic types. The statement? flag specifies that the code expects a statement context.

String and character constants in the body are directly inserted into the C code generated by the translator. Other expressions (except keywords) are handled by the usual generation logic.

Keyword constants can be used to attach additional properties to the following ordinary expression or string. These flags are:

  • :stmt
    When used within a statement verbatim form, this means that the expression appears in a statement position, i.e. directly within a {} code block. By default subexpressions are assumed to be in expression context, and statement extraction is applied appropriately.
  • :return
    When used within a statement verbatim form with a non-void return type, this specifies that the following expression/string evaluates to the return value. If no return value is needed, it is skipped completely.
  • :return!
    The same as :return, but the expression is always included in the produced code.
  • :return-nth index
  • :return-nth! index
    The same as above, but for multiple-value return. “:return” is identical to “:return-nth 0”.
  • :type typespec
    May be used to enforce a type check on the result of the following expression.

Multiple flags may specified one after another; once a non-flag expression is encountered, the flag state is reset. Any non-listed keywords are reserved as possible future flags.