TIK Exprs

What Is a TIK Expr?

This section describes the expression (Expr) concept and related skills in TIK.

An Expr is a combination of values, TIK variables (Tensor, Scalar, and InputScalar), and operators. A value is considered as an Expr, and so is a variable. See the following examples.

# Variable
a
# Immediate
1
# Arithmetic Expr
b * 3 + 10
# Logical Expr
e <= f
# Complex Expr
# For example, iteration variables i and j in for_range.
(i * 256) + (j * 16) + 8 

In the TIK front-end Exprs, variables, immediates (Int, Float, String), and logical operators (And, Or, Not, Add, Sub, Mul, Div, Mod, FloorDiv, FloorMod, Min, Max, EQ, NE, LT, LE, GT and GE) contained in equations can all be regarded as Exprs.

When writing the front-end Expr of TIK, pay attention to the following key points.

Example 1

a_scalar = tik_instance.Scalar("int32", "a_scalar", init_value=0)
b_scalar = tik_instance.Scalar("int32", "b_scalar", init_value=0)
c_scalar = a_scalar + b_scalar
>>> print(type(a_scalar))
<class 'tbe.tik.api.tik_scalar.Scalar'>
>>> print(type(c_scalar))
<class 'tbe.tik.tik_lib.tik_expr.Expr'>

Two Scalar variables are defined: a_scalar and b_scalar, which are summed up to result c_scalar. However, c_scalar is an Expr, instead of a Scalar.

See the following rewriting.

Example 2

a_scalar = tik_instance.Scalar("int32", "a_scalar", init_value=0)
b_scalar = tik_instance.Scalar("int32", "b_scalar", init_value=0)
c_scalar = tik_instance.Scalar("int32", "c_scalar", init_value=a_scalar+b_scalar)
>>> print(type(a_scalar))
<class 'tbe.tik.api.tik_scalar.Scalar'>
>>> print(type(c_scalar))
<class 'tbe.tik.api.tik_scalar.Scalar'>

c_scalar becomes the Scalar type (in this case, a Scalar instance is constructed).

In Example 1, Expr instead of a Tensor or Scalar is returned. Expr is not compiled into CCEC. That is, no value is assigned to c_scalar.

In Example 2, the Scalar assignment statement is used to instantiate the Expr computation, and Expr is assigned to the new Scalar variable as an operand and compiled into CCEC.

The Expr computation is instantiated only when Expr is used as the operand of an assignment statement.

Example 3

In addition to assignment statements, you can also use the TIK set_as API for Scalar management to instantiate an Expr operand.

a_scalar = tik_instance.Scalar("int32", "a_scalar", init_value=0)
b_scalar = tik_instance.Scalar("int32", "b_scalar", init_value=0)
c_scalar = tik_instance.Scalar("int32", "c_scalar", init_value=0)
# 1. set_as can directly take Exprs.
c_scalar.set_as(a_scalar + b_scalar)

The rewriting in example 4 can achieve the same effect.

Example 4

a_scalar = tik_instance.Scalar("int32", "a_scalar", init_value=0)
b_scalar = tik_instance.Scalar("int32", "b_scalar", init_value=0)
c_scalar = tik_instance.Scalar("int32", "c_scalar", init_value=0)
# 2. set_as can also take Scalars.
c_expr = a_scalar + b_scalar
c_scalar.set_as(c_expr)

To better understand the difference between an Expr and an assignment statement, let's look at another example.

Example 5

a_scalar = tik_instance.Scalar("int32", "a_scalar", init_value=0)
b_scalar = tik_instance.Scalar("int32", "b_scalar", init_value=0)
c_expr = a_scalar + b_scalar
d_scalar = tik_instance.Scalar("int32", "d_scalar", init_value=c_expr)
a_scalar.set_as(a_scalar + 1)
e_scalar = tik_instance.Scalar("int32", "e_scalar", init_value=c_expr)

According to the TIK front-end Exprs, if you do not understand the concept of c_expr as an Expr and when it is instantiated, you may mistakenly consider that the values of d_scalar and e_scalar are the same. However, the different IRs are generated. Remember that the computation corresponding to an Expr is instantiated only when the Expr is used as the operand of an assignment statement. Therefore, in the actual assignment statement, c_expr is instantiated to a_scalar + b_scalar.

You can consider c_expr as an alias of a_scalar + b_scalar.

Wrap-up

TIK does not generate IR for an Expr during front-end processing. IR is generated only when the Expr is used as the operand of an assignment statement.

a_scalar = tik_instance.Scalar("int32", "a_scalar", init_value=0)         # IR generated
b_scalar = tik_instance.Scalar("int32", "b_scalar", init_value=0)         # IR generated
c_expr = a_scalar + b_scalar                                              # No IR generated
d_scalar = tik_instance.Scalar("int32", "d_scalar", init_value=c_expr)   # IR generated
a_scalar.set_as(a_scalar + 1)                                             # IR generated
e_scalar = tik_instance.Scalar("int32", "e_scalar", init_value=c_expr)    # IR generated

Exercise

Please describe the differences between the following two TIK front-end Exprs:

  1. Scalar
    model_point_repeat = tik_instance.Scalar("int16", init_value=model_point_num // VLENFP32)
    model_point_residual = tik_instance.Scalar("int16", init_value=model_point_num % VLENFP32)
  2. Expr
    model_point_repeat = init_value=model_point_num // VLENFP32
    model_point_residual = init_value=model_point_num % VLENFP32

[Key]

  1. The first is an assignment Expr. In the generated CCE, the reg_buf register is used to store the compute data of model_point_num // VLENFP32. In this way, the reg_buf register is used for every model_point_repeat call in the front-end Exprs of TIK. That is, the value that is called is stored in the scalar register.
  2. The second is an Expr. When the statement is executed, repeat and residual computations are not performed. Instead, the specific value of the Expr is instantiated and computed only when the Expr statement (such as an assignment statement or computation statement) is used, whose value depends on the value of each variable in the Expr. If the value of a variable in the Expr is changed during coding, the subsequent values will change accordingly, which may cause unexpected bugs.
  3. The former Expr uses the Scalar register in most cases, which ensures that the value used each time does not change (unless a new value is assigned to it). Therefore, in actual coding scenarios, if a variable needs to be used only once, for example, repeat is generally used as extent of the for_range statement, you can directly use the Expr to express the variable. If the variable needs to be used multiple times and modification may be involved in the process, use the Scalar to ensure the correctness of the value and avoid repeated computation.