• No results found

nC Syntax Tree Transformations

Chapter 7 — NSC Implementation

7.2. nC Compilation and Transformation Steps

7.2.3. nC Syntax Tree Transformations

Following the transformations performed upon the nC data structures, there are several possible local transformations at the syntax tree level that not only optimise the behavioural level described in nC, but also sinq)lify the synthesis of a hardware structure. In both cases, the result is a more compact circuit synthesised from the specified behaviour described in nC.

Nodes defined in the syntax tree are first checked against the use of some special cases. For instance, if the user specifies that the activation function is accomplished through a lookup table, then the correspondent variable is mapped onto a ROM structure, in which values are obtained by the user’s activation function definition. Similarly, a built-in function call is automatically transformed into its appropriate code, and may or may not be compiled. For instance, a call to the function lookuptbl is not compiled, but simply transformed into an array reference. Conversely, a call to the built-in function dp results in compilation of this function.

Chapter 7__________________________NSC Implementation________________________________ 129

The transformations consist in visiting every node and applying a set of heuristic rules that try to simplify the mapping of nC into the hardware structure that implements it. The set of heuristics are defined below:

• If a RAM type is added to a constant (which results from a pointer reference, indexed by a constant in nC, such as p[1]), then the whole forest is simply transformed in a register node as shown in Figure 7.3.a. According to the constant and to the tag defined by this parameter, an appropriate name (which has been defined previously) is assigned to the register.

• If a ROM type is added to a register (which results from a pointer reference, indexed by a variable in nC, such as lookuptbl(p[1]), then the whole forest is simply transformed in the ROM node (used as operand) indexed by the register, as shown in Figure 7.3.b. In this case, the register is simply used to address the ROM memory, and the add operation is eliminated.

• If a RAM type operation is added to a register (which results from an array indexed by a variable in nC, such as p[i]), then the whole forest is simply transformed in the RAM node indexed by the register, similar to the previous transformation rule and as shown in Figure 7.3.d.

• Another transformation strategy looks for the nC construct such as p[i+1], which is parsed as a partial tree as shown in Figure 7.3.C and replaced by a simple RAM node addressed by the variable i. This is an immediate consequence of the way extended parameters in nC are arranged, that is, as pairs or group of data (i.e., num_of_ext_parm = 2; see for example Figure 4.5). The exact RAM name is obtained again through the tag mechanism employed in all nC data structure.

• A more complex transformation strategy looks for the nC statement for and checks whether a control variable has been defined. If so, it checks what kind of statement has been defined and carries out an analysis on the whole loop, so that a/o r statement like:

f o r ( i = 3 ; i < ( 2 * s i z e ) + 3 ; i += 2 )

is transformed in an equivalent loop such as:

f o r ( 1 = 0 ; 1 < s i z e ; i += 1 )

which is necessary to comply with the two previous transformation steps. In other words, the original loop performs calculation upon a parajist structure (see Figure 4.5), in which the head of the list is the fourth element (i = 3) and data are

130 NSC Implementation Chapter 7

processed two-by-two (I += 2). Since these structure has been transformed by the above mechanisms, this loop must be adjusted accordingly, resulting in the second loop above. nC: p[1] (a) nC: lookuptbl([p{1]) (b) nC. p[i+1] (c) nC: p[i] / (d)

Figure 7.3 — Transforming Memory References into Registers

The success of the above high level transformations in every nC program can be guaranteed due to the rigid way (which is defined by the s y s t e m data structure) that the

algorithm (and application) designer must follow to correctly implement a particular neural network application in nC.

Along with the above optimisations, during the parsing of the syntax tree level some software-like optimisations are performed, such as, constant folding, and global transformations.

Constant folding is done at compile time by making local and global transformations. Local transformations include the replacement of constant expressions by its evaluated result. For example, the statement r.=5*2 is replaced by the value 10, while statements like y 4-0 and y*l are simply replaced by y. Global transformations involve the analysis of the data flow. In the above examples, every time x appears in the program, its reference is replace by the pre-calculated value 10, as long as x is not assigned elsewhere between the first and the last assignment of x.

Finally, in-line subroutine expansion is performed, which comprises replacement of function calls by their code. This transformation creates more opportunities for hardware

Chapter 7____________________ NSC Implementation ___ 131

optimisations, since operations and storage elements can be merged, which also permits the exploitation of parallelism.

In summary, the first part of the NSC's front-end is devoted to the development of several transformation rules, which are closely related to the intrinsic nC syntax and semantic definition. Without all these transformations described above, the hardware synthesis tools would tend to create a complex hardware structure, particularly because of the way nC rules are defined and data is manipulated (i.e., as array elements).

The second part of the NSC's front-end involves the transformation of the nC

syntax tree into a graph-based structure.