Skip to content

Commit

Permalink
Swapped section-2 and section-3 (Xilinx#1177)
Browse files Browse the repository at this point in the history
  • Loading branch information
jackl-xilinx authored and fifield committed Apr 12, 2024
1 parent 71527ed commit b49c78f
Show file tree
Hide file tree
Showing 10 changed files with 71 additions and 41 deletions.
2 changes: 1 addition & 1 deletion programming_guide/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

# <ins>MLIR-AIE Programming Guide</ins>

MLIR-AIE is an MLIR-based representation for AI Engine design. It provides a foundation from which complex and performant AI Engine designs can be defined and is supported by simulation and hardware impelemenation infrastructure. To better understand how AI Engine designs are defined at the MLIR level, it is recommended that you spend some time going through the [tutorial course](../tutorials/). However, this programming guide is intended to lead you through a higher level abstraction (python) of the underlying MLIR-AIE framework and provide design examples and programming tips to allow users to build designs directly. Keep in mind also that MLIR-AIE is a foundational layer in a AI Engine software development framework and while this guide provides a programmer's view for using AI Engines, it also serves as a lower layer for higher abstraction MLIR layers such as [MLIR-AIR](https://github.com/Xilinx/mlir-air).
MLIR-AIE is an MLIR-based representation for AI Engine design. It provides a foundation from which complex and performant AI Engine designs can be defined and is supported by simulation and hardware impelemenation infrastructure. To better understand how AI Engine designs are defined at the MLIR level, it is recommended that you spend some time going through the [MLIR tutorial](../tutorials/) material. However, this programming guide is intended to lead you through a higher level abstraction (python) of the underlying MLIR-AIE framework and provide design examples and programming tips to allow users to build designs directly. Keep in mind also that MLIR-AIE is a foundational layer in a AI Engine software development framework and while this guide provides a programmer's view for using AI Engines, it also serves as a lower layer for higher abstraction MLIR layers such as [MLIR-AIR](https://github.com/Xilinx/mlir-air).

## Outline
<details><summary><a href="./section-1">Section 1 - Basic AI Engine building blocks (tiles and buffers)</a></summary>
Expand Down
30 changes: 30 additions & 0 deletions programming_guide/section-1/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,36 @@

# <ins>Section 1 - Basic AI Engine building blocks (tiles and buffers)</ins>

When we program for AI Engines, our MLIR-AIE framework serves as the entry point to declare and configure the structural building blocks of the entire AI Engine array. Details for these building blocks, along with the general architecture of AI Engines are breifly described in the top page of [MLIR tutorials](../tutorials) materials. Read through that synopsis first before continuing here.

In this programming guide, we will be utilizing the python bindings of MLIR-AIE components to describe our system and the tile level. Later on, when we focus in on kernel programming, we will programming in C/C++. Let's first look at a basic python source file for a MLIR-AIE design.

```
from aie.dialects.aie import * # primary mlir-aie dialect definitions
from aie.extras.context import mlir_mod_ctx # mlir ctx wrapper
# My program definition
def mlir_aie_design():
# ctx wrapper - needed to convert python to mlir
with mlir_mod_ctx() as ctx:
# device declaration - here using aie2 device xcvc1902
@device(AIEDevice.xcvc1902)
def device_body():
# Tile declarations
ComputeTile = tile(1, 4)
# Buffer declarations
ComputeBuffer = buffer(ComputeTile, (8,), T.i32(), name = "a14")
# print the mlir conversion
print(ctx.module)
# Call my program
mlir_aie_design()
```

* Introduce AI Engine building blocks with references to Tutorial material
* Give example of python binded MLIR source for defining tiles and buffers

Expand Down
31 changes: 26 additions & 5 deletions programming_guide/section-2/README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,35 @@
<!---//===- README.md --------------------------*- Markdown -*-===//
<!---//===- README.md ---------------------------------------*- Markdown -*-===//
//
// This file is licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// Copyright (C) 2022, Advanced Micro Devices, Inc.
// Copyright (C) 2024, Advanced Micro Devices, Inc.
//
//===----------------------------------------------------------------------===//-->

# <ins>Section 2- My First Program</ins>
# <ins>Section 2 - Data Movement (Object FIFOs)</ins>

* Introduce example of first simple program (Bias Add)
* Illustrate how built-in simulation of single core design
In this section of the programming guide, we introduce the Object FIFO high-level communication primitive used to describe the data movement within the AIE array. At the end of this guide you will:
1. have a high-level understanding of the communication primitive API,
2. have learned how to initialize and access an Object FIFO through meaningful design examples,
3. understand the design decisions which led to current limitations and/or restrictions in the Object FIFO design,
4. know where to find more in-depth material of the Object FIFO implementation and lower-level lowering.

To understand the need for a data movement abstraction we must first understand the hardware architecture with which we are working. The AIE array is a spatial compute architecture with explicit data movement requirements. Each compute unit of the array works on data that is stored within its L1 memory module and that data needs to be explicitly moved there as part of the AIE's array global data movement configuration. This configuration involves several specialized hardware resources which handle the data movement over the entire array in such a way that data arrives at its destination without loss. The Object FIFO provides users with a way to specify the data movement in a more human comprehensible and accessible manner without sacrificing some of the more advanced control possibilities which the hardware provides.

*Note: For more in-depth, low-level material on Object FIFO programming in MLIR please see the MLIR-AIE [tutorials](/mlir-aie/tutorials/).*

This guide is split into three sections, where each section builds on top of the previous ones:

<details><summary><a href="./section-2a">Section 2a - Introduction</a></summary>

</details>
<details><summary><a href="./section-2b">Section 2b - Key Object FIFO Patterns</a></summary>

</details>
<details><summary><a href="./section-2c">Section 2c - Data Layout Transformations</a></summary>

</details>
<details><summary><a href="./section-2d">Section 2d - Programming for multiple cores</a></summary>
</details>
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class object_fifo:
```
such that other actors may acquire it in the future. The acquire and release operations both take an additional port attribute which can be either "Produce" or "Consume". The use of this attribute is ... (TODO).

## <ins>Tutorial 3 Lab </ins>
## <ins>Tutorial 2 Lab </ins>

1. Read through the [/objectfifo_ver/aie.mlir](aie.mlir) design. In which tile and its local memory will the objectfifo lowering generate the buffer and its lock? <img src="../../images/answer1.jpg" title="On even rows tiles have local memories to their left, so the shared memory is that of tile (2,4). That is where the lowering will generate the shared buffer and lock." height=25>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
//
//===----------------------------------------------------------------------===//-->

# <ins>Section 3a - Introduction</ins>
# <ins>Section 2a - Introduction</ins>

### Initializing an Object FIFO

Expand All @@ -28,9 +28,9 @@ class object_fifo:
dimensionsFromStreamPerConsumer=None,
)
```
We will now go over each of the inputs, what they represents and why they are required by the abstraction. We will first focus on the mandatory inputs and in a later section of the guide on the default valued ones (see Data Layout Transformations in [section-3c](../section-3c/README.md#data-layout-transformations)).
We will now go over each of the inputs, what they represents and why they are required by the abstraction. We will first focus on the mandatory inputs and in a later section of the guide on the default valued ones (see Data Layout Transformations in [section-2c](../section-2c/README.md#data-layout-transformations)).

First of all, an Object FIFO has a unique `name`. It functions as an ordered buffer that has `depth`-many objects of specified `datatype`. Currently, all objects in an Object FIFO have to be of the same datatype. The datatype is a tensor-like attribute where the size of the tensor and the type of the individual elements are specified at the same time (i.e. `<16xi32>`). The `depth` can be either an integer or an array of integers. The latter is used to support a specific dependency that can arise when working with multiple Object FIFOs and it is further explained in the Key Object FIFO Patterns [section](../section-3b/README.md#broadcast).
First of all, an Object FIFO has a unique `name`. It functions as an ordered buffer that has `depth`-many objects of specified `datatype`. Currently, all objects in an Object FIFO have to be of the same datatype. The datatype is a tensor-like attribute where the size of the tensor and the type of the individual elements are specified at the same time (i.e. `<16xi32>`). The `depth` can be either an integer or an array of integers. The latter is used to support a specific dependency that can arise when working with multiple Object FIFOs and it is further explained in the Key Object FIFO Patterns [section](../section-2b/README.md#broadcast).

An Object FIFO is created between a producer or source tile and a consumer or destination tile. Below, you can see an example of an Object FIFO created between producer tile A and consumer tile B:
```
Expand All @@ -40,7 +40,7 @@ of0 = object_fifo("objfifo0", A, B, 3, T.memref(256, T.i32()))
```
The created Object FIFO is stored in the `0f0` variable and is named `objfifo0`. It has a depth of `3` objects of datatype `<256xi32>`.

As you will see in the Key Object FIFO Patterns [section](../section-3b/README.md#key-object-fifo-patterns), an Object FIFO can have multiple consumer tiles, which describes a broadcast connection from the source tile to all of the consumer tiles. As such, the `consumerTiles` input can be either a single tile or an array of tiles. This is not the case for the `producerTile` input as currently the Object FIFO does not support multiple producers.
As you will see in the Key Object FIFO Patterns [section](../section-2b/README.md#key-object-fifo-patterns), an Object FIFO can have multiple consumer tiles, which describes a broadcast connection from the source tile to all of the consumer tiles. As such, the `consumerTiles` input can be either a single tile or an array of tiles. This is not the case for the `producerTile` input as currently the Object FIFO does not support multiple producers.

### Accessing the objects of an Object FIFO

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
//
//===----------------------------------------------------------------------===//-->

# <ins>Section 3b - Key Object FIFO Patterns</ins>
# <ins>Section 2b - Key Object FIFO Patterns</ins>

The Object FIFO primitive supports several data movement patterns through its inputs and its member functions. We will now describe each of the currently supported patterns and provide links to more in-depth practical code examples that showcase each of them.

Expand All @@ -18,7 +18,7 @@ The Object FIFO primitive supports several data movement patterns through its in

### Broadcast

As was explained in the Introduction [section](../section-3a/README.md#initializing-an-object-fifo) section, the `consumerTiles` input can be either a single tile or an array of tiles. When the input is specified as an array of tiles, this creates a broadcast communication from a single producer tile to multiple consumer tiles. The data from the producer tile's memory module is sent to each of the consumer tiles' memory modules via the AXI stream interconnect, which handles the back-pressure from consumers with different execution times. The AXI stream is also where the data is copied at a low-level before being sent to each of the consumers.
As was explained in the Introduction [section](../section-2a/README.md#initializing-an-object-fifo) section, the `consumerTiles` input can be either a single tile or an array of tiles. When the input is specified as an array of tiles, this creates a broadcast communication from a single producer tile to multiple consumer tiles. The data from the producer tile's memory module is sent to each of the consumer tiles' memory modules via the AXI stream interconnect, which handles the back-pressure from consumers with different execution times. The AXI stream is also where the data is copied at a low-level before being sent to each of the consumers.

For more low-level details regarding how the objects in the Object FIFO are transferred via the AXI stream through the DMAs of the producer and consumer tiles please see the MLIR-AIE tutorials [tutorials](/mlir-aie/tutorials/tutorial-7/).

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
//
//===----------------------------------------------------------------------===//-->

# <ins>Section 3c - Data Layout Transformations</ins>
# <ins>Section 2c - Data Layout Transformations</ins>

* dimensionsToStream, dimensionsFromStreamPerConsumer

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
//
//===----------------------------------------------------------------------===//-->

# <ins>Section 3d - Programming for multiple cores</ins>
# <ins>Section 2d - Programming for multiple cores</ins>

* explain how to go from code written for a single core to code written like in the visual pipelines, with for loops over multiple cores accessing several objfifos

Expand Down
31 changes: 5 additions & 26 deletions programming_guide/section-3/README.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,14 @@
<!---//===- README.md ---------------------------------------*- Markdown -*-===//
<!---//===- README.md --------------------------*- Markdown -*-===//
//
// This file is licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// Copyright (C) 2024, Advanced Micro Devices, Inc.
// Copyright (C) 2022, Advanced Micro Devices, Inc.
//
//===----------------------------------------------------------------------===//-->

# <ins>Section 3 - Data Movement (Object FIFOs)</ins>
# <ins>Section 3 - My First Program</ins>

In this section of the programming guide, we introduce the Object FIFO high-level communication primitive used to describe the data movement within the AIE array. At the end of this guide you will:
1. have a high-level understanding of the communication primitive API,
2. have learned how to initialize and access an Object FIFO through meaningful design examples,
3. understand the design decisions which led to current limitations and/or restrictions in the Object FIFO design,
4. know where to find more in-depth material of the Object FIFO implementation and lower-level lowering.

To understand the need for a data movement abstraction we must first understand the hardware architecture with which we are working. The AIE array is a spatial compute architecture with explicit data movement requirements. Each compute unit of the array works on data that is stored within its L1 memory module and that data needs to be explicitly moved there as part of the AIE's array global data movement configuration. This configuration involves several specialized hardware resources which handle the data movement over the entire array in such a way that data arrives at its destination without loss. The Object FIFO provides users with a way to specify the data movement in a more human comprehensible and accessible manner without sacrificing some of the more advanced control possibilities which the hardware provides.

*Note: For more in-depth, low-level material on Object FIFO programming in MLIR please see the MLIR-AIE [tutorials](/mlir-aie/tutorials/).*

This guide is split into three sections, where each section builds on top of the previous ones:

<details><summary><a href="./section-3a">Section 3a - Introduction</a></summary>

</details>
<details><summary><a href="./section-3b">Section 3b - Key Object FIFO Patterns</a></summary>

</details>
<details><summary><a href="./section-3c">Section 3c - Data Layout Transformations</a></summary>

</details>
<details><summary><a href="./section-3d">Section 3d - Programming for multiple cores</a></summary>
</details>
* Introduce example of first simple program (Bias Add)
* Illustrate how built-in simulation of single core design

0 comments on commit b49c78f

Please sign in to comment.