Expression syntax in ACT is similar to expressions in the C language.

  • Integer expressions: operators that are supported include +, -, *, /, and % for integer arithmetic operations, and &, |, and ~ for bit-wise logical operations between integers.
  • Boolean expressions can be constructed from Boolean variables, the constants true and false, and the Boolean operators &, |, and ~ denoting the and, or, and negation operations respectively. (This is a departure from C, where and/or operations between conditions use && and ||.)
  • Numerical expressions can be compared using <, < =, >, >=, =, and != for the operators less than, less than or equal to, greater than, greater than or equal to, equal to, and not equal to respectively.
  • The query expression (e ? e1 : e2) behaves like the C operator. The result is e1 if e is true, and e2 otherwise.
  • Logical shift operators are « (left shift), » (logical right shift), and the arithmetic right shift operator »>.
  • Bit operations: For a variable x, the value x{b..a} extracts bits b through a (both included, with b at least a). Both b and a must be constants (or computed by parameters, i.e. constants after expansion). The syntax x{a} is syntactic sugar for x{a..a}, and extracts one bit from x.
  • Concatenation: Given a set of expressions, {e1,e2,e3,…,eN} concatenates the bits of the expressions to form a wide result.

Expressions can also include function calls, with the usual function call syntax. More details on how functions are defined is below. Expressions can also include type-conversion operators:

  • int(x): x must be a Boolean expression. int(x) will be 0 if the expression is false, or 1 otherwise.
  • int(x,w): x must be an integer expression, and w must be evaluate to an integer constant after expansion (i.e. it can only be an integer expression that includes parameters). This changes the bit-width of the integer to be w. If the width is reduced, the high order bits are truncated; if the bit-width is increased, the integer is zero extended.
  • bool(x): x must be an integer expression. This returns false if the integer is zero, and true otherwise.

Parameters and constant expressions

Parameter expressions are used to compute parameter values (pint/pbool) and are evaluated at expansion time. These expressions are signed integers, and use 64-bit integer arithmetic. All constants are simplified at expansion time using the same 64-bit integer arithmetic as parameters.

Expressions in CHP

The same expression syntax is also used in the chp and dataflow sub-languages. Once again, constant expressions are simplified as above. However, expressions can also include variables that are determined at run-time rather than expansion time (i.e. when the circuit is executing the specified computation.) In this case, we need rules to determine the bit-width of an expression. The rules are as follows:

  • Each variable has the bit-width specified by its type.
  • A constant uses the minimum number of bits needed to represent it. Note that a negative constant is assumed to be a two's complement value, an its bit-width is determined in the same way.
  • For unary operators, the bit-width of the result is the same as the bit-width of the argument
  • For binary operators and ternary operators where the result is an integer, let left be the bit-width of the left-hand side of the operator, and right be the bit-width of the right hand side. There are six categories of result bit-widths:
    1. max(left,right) ; the smaller operand is zero-extended as needed.
      • bitwise AND &
      • bitwise OR |
      • bitwise XOR ^
      • Query expressions where the result is an integer. In this case left and right are the bit-widths of the two options in the query expression, since the first part of the query expression is Boolean.
    2. 1+max(left,right)
      • addition +
      • subtraction -
    3. left+right
      • multiplication *
    4. left
      • division /
      • logical right shift »
      • arithmetic right shift »>
    5. right
      • mod %
    6. left + 2^right - 1
      • left shift «
  • For concatenation, the bit-width is the sum of all the components. For the bitfield extraction, the bitwidth is determined by the number of bits extracted.


ACT provides support for user-defined functions. These functions can be used to make your design more understandable. The syntax of a function is illustrated by the following example:

function f (pint x) : pint
  chp {
     self := x + 1

The function keyword is used to define a function. Here, function f is defined, and it takes one parameter (x of type pint), and has a return type pint (indicated by : pint).

The CHP language is used to implement the body of a function. The special variable self can be used in the body of the CHP language, and its value on termination of the CHP program indicates the return value.

Additional parameters that might be helpful as auxilliary variables can be defined within the body of the function in the usual way.

function sumint (pint x) : pint
  pint i;
  chp {
     i := 0;
     self := 0;
    *[ i < x -> 
         self := self + i;
         i := i + 1

There are two flavors of functions:

  • Functions where all the arguments and return type are parameter types
  • Functions where all the arguments and return types are non-parameter data types

The first kind of function is typically used when constructing the circuit, and its value can be statically computed during the circuit construction phase. The second kind of function is viewed as CHP, and can be implemented either by inlining the function or through some other approach (e.g. shared, partially shared, etc).

For example, the following function that takes an int<8> argument can be called from the CHP sub-language:

/* look at the MSB to determine if this is a negative 2's complement integer */
function isnegative (int<8> x) : bool
  chp {
    self := bool(x{7})