-
Notifications
You must be signed in to change notification settings - Fork 7
Special Forms
This page describes special forms supported by the GPU code translator.
- 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.
- setq
Supported.
- setf
Supported as a special form; allows some built-in functions as an assignment target.
(setf (values ...) ...)is transformed to multiple-value-setq.
- macrolet
- symbol-macrolet
Fully supported.
- 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.
- 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
Supported.
- if
Supported. The condition expression must return a boolean value.
- progn
- block
- return-from
- tagbody
- go
Supported.
- catch
- throw
Supported for constant tag argumens via transformation to block & return-from after function inlining.
- locally
Supported.
- 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).
- 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.
- 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.
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.