Documentation Index
Fetch the complete documentation index at: https://sdk.cerebras.ai/llms.txt
Use this file to discover all available pages before exploring further.
void type
Expressions of type void have a single possible value. It describes
constructs that do not produce a result. For example, blocks which do not break
values have type void and void is the return type of functions and
builtins that do not return anything. Using a block as an expression, the void
value can be expressed with {}:
void is allowed at runtime as a function return type. All other uses of
void values must be comptime-known; see Comptime for more
information on comptime.
Numeric Types
These types describe numbers:- signed integers (
iNfor arbitrary bit widthN) - unsigned integers (
uNfor arbitrary bit widthN) - arbitrary precision integers (
comptime_int) - floating point numbers (
f16,f32,bf16,cb16,comptime_float)
Arbitrary-Width Integer Types
CSL supports integer types with any bit width from 0 to 16777215. These are specified usinguN for unsigned types and iN for signed types, where N
is the bit width:
comptime_int results at
compile time, which are then coerced to the target type. An error occurs if the
result cannot be represented in the target type:
Only integer types with bit widths of 16 or 32 are ABI-sized.
Non-ABI-sized integer types cannot be used in
export or extern
declarations or as task parameters, and certain hardware-specific operations,
such as DSD builtins, may require ABI-sized types. Non-ABI-sized types are
primarily intended for compact data structures such as packed structs and
unions.The comptime_int Type
Values of comptime_int type can hold arbitrarily large (or small) integers.
Integer literals have type comptime_int:
comptime_int:
comptime_int values happen at compile time, produce
another comptime_int value, and never underflow or overflow:
comptime_int and a value of
fixed-precision integer type cause the comptime_int value to be converted
to the fixed-precision type. An error is emitted upon overflow or underflow:
@as can be used to force literals to have a specific width, for
example @as(u16, 1) | 0xbeef.
All values of type comptime_int must be comptime-known, see
Comptime for more information on comptime.
The comptime_float Type
Values of comptime_float type can hold any IEEE double precision floating
point number. Float literals have type comptime_float:
comptime_float values happen at compile time and produce
another comptime_float value. If an operation performs division by zero or
generates a NaN value, an error is emitted.
Operations between a value of type comptime_float and a value of different
float type cause the comptime_float value to be converted to other float
type. An error is emitted if this is not possible.
All values of type comptime_float must be comptime-known, see
Comptime for more information on comptime.
FP16 Types
f16, cb16, and bf16 are 16-bit floating point (“FP16”) types of
different formats:
| Type | Description | Exponent | Mantissa |
|---|---|---|---|
f16 | IEEE half-precision | 5 bits | 10 bits |
cb16 | Cerebras float16 | 6 bits, customized bias | 9 bits |
bf16 | Brain float16 | 8 bits | 7 bits |
--fp16-format command line option,
with a default of f16. All values of the other FP16 types must be
comptime-known:
@fp16() builtin (see @fp16) facilitates
programming with respect to the selected FP16 format.
The type Type
In CSL, the type type can be used to describe values that are themselves
types:
type must be comptime-known, see
Comptime for more information on comptime.
Function Types
Values of function type contain the name of a function and may be used anywhere a function is expected. The type is written asfn(<arg types>) <return_type>.
Struct Types
There are two kinds of struct types in CSL: anonymous structs and named structs.The Anonymous Struct Types
Anonymous struct types are defined by an optional list of field names and a list of types. Two anonymous struct types are the same if they have the same list of field names (or both lack field names) and the same list of types. A value of an anonymous struct type with named fields is created with the syntax:.{.field1 = value1, .field2 = value2, ...}. A value of an anonymous
struct type with unnamed fields is created with the syntax:
.{value1, value2, ...}.
Anonymous struct types with nameless fields are also known as tuple types.
The elements of tuples may be accessed with the [] operator, as long as
the index is known at compile time.
The Named Struct Types
Named struct types are similar to anonymous struct types, except that two named struct types defined at different places in the source code are considered to be different types, even if their field names and types are the same. A named struct type is expressed with the formstruct { field1: type1, field2: type2, ... }. Once a named struct type has
been defined, a value of that type can be created by giving the name of the
type, followed by a field initializer list of the form
{ .field1 = value1, .field2 = value2, ... }.
struct expression).
type arguments, this can be used to define parameterized struct
types, whose field types can be customized by the user.
. syntax.
extern struct
By default, the memory layout of structs is not defined. Fields are guaranteed
to be ABI-aligned, but no guarantees are provided about the ordering of fields
or size of the struct. If a well-defined memory layout is required, a named
struct type can be qualified with extern. This gives the struct in-memory
layout matching the C ABI for the target, enabling extern struct types to be
used in export and extern declarations. All fields of extern struct types
must have an export-compatible type. See Storage Classes
for details.
packed struct
packed structs have a different kind of well-defined memory layout. All
packed structs have a backing integer. The type of this integer is implicitly
determined by the total bit count of fields, and the ABI of this integer is
exactly the ABI of the packed struct type. This enables ABI-sized
packed struct types to be used in export and extern declarations. See
Storage Classes for details.
Each field of a packed struct is interpreted as a logical sequence of bits,
arranged from least to most significant. The following field types are allowed,
with bit counts defined as follows:
- A field of fixed-width integer or float type uses as many bits as its width.
For example, a
u8will use 8 bits of the backing integer. - A
boolfield uses exactly 1 bit. - An
enumfield uses exactly the bit width of its underlying integer type. - A
packed structfield uses the bits of its backing integer. - A
packed unionfield uses the bits of its backing integer. - A field of pointer type uses as many bits as the target architecture’s word size.
packed struct field, since the field
may be unaligned:
Union Types
An untagged union type is similar to a named struct type, except that it represents a choice among the field types rather than a collection of field types. Only untagged union types are currently supported in CSL. An untagged union type is expressed with the formunion { field1: type1, field2: type2, ... }. Once a union type has been
defined, a value of that type can be created by giving the name of the type,
followed by a field initializer of the form { .field = value }.
extern union and
packed union.
Similarly to named struct types, two union types are considered equal if and
only if they have identical field names and types and they were both defined
at the same point in the program, i.e., by the same union expression.
. syntax. A
new active variant can only be established by assigning a new value to the
entire union object.
extern union
Similarly to an extern struct, a union type qualified with
extern has an in-memory layout matching the C ABI for the target, enabling
extern union types to be used in export and extern declarations. All
fields of extern union types must have an export-compatible type. See
Storage Classes for details.
packed union
Similarly to a packed struct, a union type qualified with
packed has a backing integer. All fields of a packed union must have the
same bit width, and the ABI of this integer is exactly the ABI of the
packed union type. This enables ABI-sized packed union types to be used in
export and extern declarations. See Storage Classes
for details.
The valid field types are the same as those that are valid for a
packed struct.
Enumeration Types
An enumeration type is a set of named elements, each of which is represented by a unique integer value:u16 in the
example above) and it can be any fixed-precision integer type (e.g. i16 or
u32).
Any element can be assigned a comptime-known integer value:
0 to red and the value 2
to blue. If white is instead assigned the value 4, then the compiler
will assign the value 0 to red and 1 to blue.
Enumeration type values can be cast to and from their underlying numeric values
using the @as() builtin, as the following assertions demonstrate:
==
and != operators.
Enumeration Type Equality
Two enumeration types are the same if and only if both of the following conditions are true:- they have the same structure, i.e., the same underlying integer type, and the same set of element values, each of which is assigned the same numeric value.
- their definitions originate at the same source code location.
Array Types
An array type is parameterized by an element type, describing a collection of elements of the base type. An array type whose element type isT can be written as [size]T.
The element type must not be another array type. Multidimensional
arrays are specified with a sequence of dimensions: [size1, size2, size3]T.
Pointer Types
A value of pointer type contains the memory address where a variable is located. Pointer types are described by an element type and an optionalconst
qualifier.
In CSL, pointers are only created by taking the address of a variable. This
provides the property that pointers always point to valid data when they are
created.
There are two kinds of pointers in CSL: pointers to a single element and
pointers to an unknown number of elements.
Pointers to a Single Element
A pointer to a single value of typeT is written as *T. For example:
- a pointer to a single
i16is written as*i16 - a pointer to a single array of ten integers is written as
*[10]i16.
&):
.* operator:
const qualified, indicating that this pointer may not
be used to modify the underlying memory:
ptr itself is mutable, but the memory it points to is
not.
Pointers to Unknown Number of Elements
A pointer to an unknown number of elements of typeT is written as
[*]T. For example, a pointer to an unknown number of f16 elements is
written as [*]f16.
Pointers to an unknown number of elements are created through coercion from
pointers to a single element of array type (e.g. *[2]i16):
[] must be used instead:
Pointers and Configuration Memory
It is illegal to dereference or use the access operator[] on pointers
occurring in the selected target’s configuration address range. An error is
emitted if the compiler is able to detect such an access. Configuration memory
should be accessed using the builtins @get_config and @set_config
instead (see @get_config,
@set_config).
The anyopaque Type
The anyopaque type represents an opaque type whose size and alignment are
unknown. It is primarily useful as the element type of a pointer (*anyopaque)
to create type-erased pointers that can point to values of any type.
The anyopaque type itself cannot be used directly as a value, as a function
parameter, as a function return type, or in container types (structs, unions,
arrays) because its size is not known. It can only be used behind a pointer.
Pointers to any type can be implicitly coerced to *anyopaque:
@ptrcast:
The comptime_string Type
Values of comptime_string type hold immutable strings that can be
manipulated at compile time. All values of type comptime_string must be
comptime-known. See Comptime for more information on
comptime.
std::string in C++, but unlike char * strings in C, strings in
CSL are not null-terminated. This means that the NUL character can occur
anywhere in a string. For example, the following @comptime_asserts will
succeed:
@strlen)
will not necessarily match the number of characters in the string. For
example, the @comptime_asserts in the following code will succeed:
The imported_module Type
TODO.
The direction Type
TODO.
Type Coercions
Numeric Coercions
CSL supports implicit numeric coercions that widen values to larger, compatible types. These coercions preserve all possible values from the source type.Integer Widening
Integer types can be implicitly coerced to wider integer types when the destination type can represent all values that the source type can represent:- Same signedness with wider width:
i8toi16toi32toi64, andu8tou16tou32tou64 - Unsigned to wider signed:
u8toi16,u16toi32,u32toi64
- Narrowing (loses precision): This applies to any coercion where the
destination integer type has a smaller bit width than the source integer
type, such as
i32toi16. - Signed to unsigned (unsigned types cannot represent negative values):
This applies to all coercions from signed to unsigned types, regardless of
bit width, such as
i8tou8ori32tou64.
Float Widening
Float types can be implicitly coerced to wider float types:- FP16 to f32:
f16tof32,bf16tof32,cb16tof32
- Narrowing:
f32tof16(loses precision). This applies to any coercion where the destination float type has a smaller bit width than the source float type. - Cross-format:
f16tobf16(different representations, not pure widening)
Comptime Coercions
Values ofcomptime_int and comptime_float can be coerced to compatible
fixed-precision types as long as the target type can represent the source
value. Specifically, comptime_int can be coerced to any integer type, and
comptime_float can be coerced to any floating point type:
Pointer Coercions
CSL supports implicit coercions between certain pointer types. The following pointer coercions are supported, whereT represents any specific element
type, such as f16 or i32, and N represents a specific array size.
Const qualification
*Tto*const T[*]Tto[*]const T*[N]Tto*const [N]T
Array pointer to many-item pointer
*[N]Tto[*]T*[N]Tto[*]const T*const [N]Tto[*]const T
Single-element pointer to single-element array pointer
*Tto*[1]T*Tto*const [1]T*const Tto*const [1]T
Struct Coercions
Anonymous structs may be coerced to other struct types. For a coercion to be valid:- The destination struct type must have the same field names as the source value, but the order of the field names does not need to match.
- Each source field value must be coercible to the corresponding destination field type.
Peer Type Resolution
Peer type resolution is used when CSL needs to find a common type for multiple expressions. CSL attempts to find a common type that all expressions can be coerced to. Peer type resolution occurs in the following contexts:- Conditional expressions (
if/else), when the if and else branches have different but compatible types - Switch expressions, when different cases return different but compatible types
- Block expressions, when multiple
breakstatements with values have different but compatible types - Binary operations between compatible types, such as addition, subtraction, comparison, etc.
Numeric coercions
All numeric coercions described in Numeric Coercions are supported in peer type resolution. For example,i16 can be widened to i32,
and f16 can be widened to f32.

