From 2491ae3854b4a2eb05a33b8fd04e07130fb7affd Mon Sep 17 00:00:00 2001 From: Zeinab Pourgheisari Date: Sat, 27 Sep 2025 21:38:56 +0200 Subject: [PATCH 1/6] Identify phi --- .../FTD/Figures/if_loop_add_CFG.png | Bin 0 -> 25599 bytes .../FTD/GSAAnalysis.md | 101 ++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 docs/DeveloperGuide/DynamaticFeaturesAndOptimizations/FTD/Figures/if_loop_add_CFG.png create mode 100644 docs/DeveloperGuide/DynamaticFeaturesAndOptimizations/FTD/GSAAnalysis.md diff --git a/docs/DeveloperGuide/DynamaticFeaturesAndOptimizations/FTD/Figures/if_loop_add_CFG.png b/docs/DeveloperGuide/DynamaticFeaturesAndOptimizations/FTD/Figures/if_loop_add_CFG.png new file mode 100644 index 0000000000000000000000000000000000000000..24a2810011cb8ea0af514994f1d6146fa105ffd0 GIT binary patch literal 25599 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 literal 0 HcmV?d00001 diff --git a/docs/DeveloperGuide/DynamaticFeaturesAndOptimizations/FTD/GSAAnalysis.md b/docs/DeveloperGuide/DynamaticFeaturesAndOptimizations/FTD/GSAAnalysis.md new file mode 100644 index 0000000000..bc0d43c8db --- /dev/null +++ b/docs/DeveloperGuide/DynamaticFeaturesAndOptimizations/FTD/GSAAnalysis.md @@ -0,0 +1,101 @@ +# GSA Analysis +## Introduction +In Static Single Assignment (SSA) form, every variable is assigned exactly once, and ϕ (phi) functions are introduced to merge values coming from different control flow paths. While SSA is powerful, it does not explicitly encode the control-flow decisions that determine which value is actually chosen at runtime. + +**Gated Single Assignment (GSA)** was introduced as an extension of SSA to make these control-flow decisions explicit. Instead of a single generic ϕ merge, GSA introduces specialized gates: +- The **μ (mu) gate** appears at loop headers. It chooses between an initial value coming from outside the loop and a value produced inside the loop. The decision is driven by the loop’s condition: if the loop is starting, the initial value is used; if the loop is iterating, the loop value is used. +- The **γ (gamma) gate** replaces a ϕ at control-flow merges. It selects between a true value and a false value depending on a condition signal (like at the end of an if–else). In hardware, this becomes a multiplexer. + +For Dynamatic’s **Fast Token Delivery (FTD)** algorithm, having the program represented in GSA form is required. The MLIR cf dialect already provides ϕ-gates in SSA form, but these must be translated into their GSA equivalents. During this translation, every block argument(pottential ϕ) in the control-flow is rewritten as either a μ or a γ gate. + +### Example +Consider the following control-flow graph and its corresponding `cf_dyn_transformed.mlir` code. +- bb1 and bb3 both receive arguments from multiple predecessors. Implicit ϕ-gates are therefore placed in these blocks. + +- The first argument of bb1 (%0) chooses between the initial value %c0 from bb0 and the loop-carried value %8 from bb3. This corresponds to a μ function. + +- The second argument of bb1 (%1) is also updated inside the loop, so it too becomes a μ function. + +- The argument of bb3 (%7) comes from two mutually exclusive control-flow paths (bb1 or bb2). This corresponds to a γ function. + +![CFG](./Figures/if_loop_add_CFG.png) + +``` +module { + func.func @if_loop_add(%arg0: memref<1000xf32> {handshake.arg_name = "a"}, %arg1: memref<1000xf32> {handshake.arg_name = "b"}) -> f32 { + %c0 = arith.constant {handshake.name = "constant2"} 0 : index + %cst = arith.constant {handshake.name = "constant3"} 0.000000e+00 : f32 + cf.br ^bb1(%c0, %cst : index, f32) {handshake.name = "br0"} + ^bb1(%0: index, %1: f32): // 2 preds: ^bb0, ^bb3 + %cst_0 = arith.constant {handshake.name = "constant4"} 0.000000e+00 : f32 + %2 = memref.load %arg0[%0] {handshake.mem_interface = #handshake.mem_interface, handshake.name = "load2"} : memref<1000xf32> + %3 = memref.load %arg1[%0] {handshake.mem_interface = #handshake.mem_interface, handshake.name = "load3"} : memref<1000xf32> + %4 = arith.subf %2, %3 {handshake.name = "subf0"} : f32 + %5 = arith.cmpf oge, %4, %cst_0 {handshake.name = "cmpf0"} : f32 + cf.cond_br %5, ^bb2, ^bb3(%1 : f32) {handshake.name = "cond_br0"} + ^bb2: // pred: ^bb1 + %6 = arith.addf %1, %4 {handshake.name = "addf0"} : f32 + cf.br ^bb3(%6 : f32) {handshake.name = "br1"} + ^bb3(%7: f32): // 2 preds: ^bb1, ^bb2 + %c1000 = arith.constant {handshake.name = "constant5"} 1000 : index + %c1 = arith.constant {handshake.name = "constant6"} 1 : index + %8 = arith.addi %0, %c1 {handshake.name = "addi0"} : index + %9 = arith.cmpi ult, %8, %c1000 {handshake.name = "cmpi0"} : index + cf.cond_br %9, ^bb1(%8, %7 : index, f32), ^bb4 {handshake.name = "cond_br1"} + ^bb4: // pred: ^bb3 + return {handshake.name = "return0"} %7 : f32 + } +} +``` +### Translation Process +The conversion from SSA to GSA is done in three main steps: + +1. Identify implicit ϕ gates introduced by SSA form. + +2. Convert ϕ gates into μ gates + +3. Convert remaining ϕ gates into γ gates. + +## Identify Implicit ϕ Gates +In the `convertSSAToGSA` function, the first step is to convert all block arguments in the IR into ϕ gates, carefully extracting information about their producers and senders. Later, these ϕ gates are transformed into either γ or μ gates. In this section, we focus on the details of this first step. + +Note: If there is only one block in the region being checked, nothing needs to be done since there is no possibility of multiple assignments. + +In pseudo-code, the process looks like this: +``` +For each block in the region: + For each argument of the block: + → treat this argument as a potential ϕ. + + For each predecessor of the block: + Identify the branch terminator that jumps into the block. + Extract the value passed to the argument. + + If the value is a block argument and its parent block has predecessors(so its parent is not bb0): + → this value is itself the output of another ϕ. + Record it as a “missing phi” to be connected later. + Else: + → the value is a plain input and can be added directly. + + In both cases, check if the value is already recorded: + - `isBlockArgAlreadyPresent` checks block arguments. + - `isValueAlreadyPresent` checks plain SSA values. + + If the value is new: + - Wrap it in a `gateInput` structure. + - If it is a missing phi: + * Add it to `phisToConnect` (records phis that need reconnection later). + * Add it to `operandsMissPhi` (helps `isBlockArgAlreadyPresent` detect duplicates). + - Add the predecessor block to the `senders` list of this gate input. + - Add the gate input to `gateInputList` (the global list of all gate inputs). + - Add the gate input to `operands` (the inputs of the current ϕ). + + After all predecessors are processed: + If `operands` is not empty (the ϕ has at least one input): + → create the ϕ gate and associate it with the block. +``` +After all ϕ gates are created, the final step is to connect the missing inputs recorded in phisToConnect. + +## Convert ϕ Gates into μ Gates + +## Convert ϕ Gates into γ Gates \ No newline at end of file From 1b2f32a839da3a5736885af3e87125284e8cb85c Mon Sep 17 00:00:00 2001 From: Zeinab Pourgheisari Date: Sat, 27 Sep 2025 22:46:51 +0200 Subject: [PATCH 2/6] convert phi to mu --- .../FTD/Figures/gemm_CFG.png | Bin 0 -> 38761 bytes .../FTD/GSAAnalysis.md | 55 +++++++++++++++++- 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 docs/DeveloperGuide/DynamaticFeaturesAndOptimizations/FTD/Figures/gemm_CFG.png diff --git a/docs/DeveloperGuide/DynamaticFeaturesAndOptimizations/FTD/Figures/gemm_CFG.png b/docs/DeveloperGuide/DynamaticFeaturesAndOptimizations/FTD/Figures/gemm_CFG.png new file mode 100644 index 0000000000000000000000000000000000000000..8cae0423a771a3e4a14d5f65e4cb3a909125bbcf GIT binary patch literal 38761 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 jO8gHxXxT@m)pju2J^6`A; Date: Thu, 2 Oct 2025 19:20:21 +0200 Subject: [PATCH 3/6] convert to gamma --- .../FTD/GSAAnalysis.md | 122 +++++++++++++++++- 1 file changed, 121 insertions(+), 1 deletion(-) diff --git a/docs/DeveloperGuide/DynamaticFeaturesAndOptimizations/FTD/GSAAnalysis.md b/docs/DeveloperGuide/DynamaticFeaturesAndOptimizations/FTD/GSAAnalysis.md index 8f6f476536..773a61e713 100644 --- a/docs/DeveloperGuide/DynamaticFeaturesAndOptimizations/FTD/GSAAnalysis.md +++ b/docs/DeveloperGuide/DynamaticFeaturesAndOptimizations/FTD/GSAAnalysis.md @@ -151,4 +151,124 @@ Therefore, the condition of a μ gate is defined as the **negation of the loop e #### Note: The `getLoopExitCondition` function computes the overall exit condition by OR-ing the conditions of all loop exiting blocks. This function relies on `getBlockLoopExitCondition`, which computes the exit condition for a single block. -## Convert ϕ Gates into γ Gates \ No newline at end of file + +## Convert ϕ Gates into γ Gates + +All remaining ϕ gates (i.e., those not turned into μ gates) must be converted into γ gates. +However, a single γ gate is only a **two-input multiplexer**, while a ϕ can have multiple inputs. +To handle this, we build a tree of γ gates, each driven by a simple condition. +The following steps describe the process. + +### Input Ordering +The inputs of a ϕ are sorted based on the dominance relationship between their originating basic blocks. + +- If block Bi dominates block Bj, then the input from Bi is placed before Bj. + +- This ordering does not affect the semantics of the ϕ (ϕ is order-less), but it simplifies later analysis. + +### Step 2. Find Common Dominator + +Find **the nearest common dominator** among all input blocks of the ϕ. +This block acts as the root for path exploration. + +### Step 3. Path Identification + +For each input operand: + +- Find all paths from the common dominator to the ϕ’s block that **pass through the operand’s block** but **avoid later operand blocks**. + +- Paths are explored using a modified DFS that: + + - finds all possible paths between two blocks, + + - avoids certain “blocked” nodes, + + - and allows a block to be revisited only if it is both the start and end (for loop cases). + +**Operands from the same block:** + +If one block produces multiple values (operands) for the same ϕ, the DFS initially gives them identical paths. + +To disambiguate, we filter the paths by the sender block (the block immediately before the ϕ in the path). +Only paths whose sender matches the operand’s recorded sender are kept. + +### Step 4. Boolean Conditions + +For each operand, compute a Boolean expression representing when that operand is chosen: + +- The condition of a path = AND of all branch conditions along that path. + +- The condition of an operand = OR of the conditions of all valid paths. + +- The resulting Boolean expressions are minimized. + +All Boolean conditions (cofactors) are collected and sorted by the index of their originating block. + +### Step 5. Build the γ Tree + +The `expandGammaTree` function takes a ϕ gate (with its inputs and Boolean conditions) and recursively builds a binary tree of γ gates. +Each γ is a two-input MUX driven by one simple Boolean condition. + +The process works as follows: + +**1. Pick a cofactor (condition):** + +The function starts from the queue of cofactors (Boolean conditions associated with blocks). Since they are ordered by block index, the first cofactor we take is guaranteed to be common to all input expressions (because the blocks associated with it dominate the others). This ensures that splitting on this cofactor applies consistently across all inputs. + +**2. Split expressions by condition:** + +For each input expression (operand + condition): + +- Restrict the Boolean expression once assuming the cofactor = `true`. + +- Restrict it again assuming the cofactor = `false`. + +- Add the non-zero result(s) to either `conditionsTrueExpressions` or `conditionsFalseExpressions`. + +**3. Build γ inputs:** + +Now we decide what should feed the true and false inputs of the γ gate being built: + +- If a side has **more than one expression**, this means multiple operands could be selected under that branch of the condition. To resolve this, we recursively call `expandGammaTree` on that subset. The resulting γ gate from the recursion becomes the input of the current γ. + +- If a side has `exactly one expression`, its operand is directly assigned as the input of the current γ. + +- If a side has `no expressions`, it means this branch of the condition is never taken. In that case, an empty (null) input is created. + +**4. Create the γ gate:** + +A new γ is generated: + +- Its inputs are the “true” and “false” operands from the step above. + +- Its condition is the cofactor currently being expanded. + +- Internally, its output is temporarily set to the original ϕ’s result (only the root γ of the tree will preserve this). + +**5. Placement rule:** + +Normally, new γ gates are placed in the **same block as the original ϕ**. + +However, there is one special case: when the ϕ was introduced during `convertPhiToMu` to resolve multiple loop-carried inputs. These temporary ϕs (marked with muGenerated) cannot have their γ replacements placed in the loop header. + +**Why is this a problem?** + +When we later run direct path analysis for control dependencies, the control signal that drives such a γ is generated inside the loop body. +If we place the γ in the loop header: + +- The γ would appear before its control signal producer. + +- In the direct path search from the function entry (bb0) to the γ, we would never encounter the block that generates the control signal. + + +**The fix:** + +For γs created from these muGenerated phis, we instead place them **in the same block as their condition producer**. + +### Step 6. Reconnect Uses + +Once a ϕ is replaced by its γ tree: + +- All gates that previously used the ϕ’s output are updated to use the root γ gate instead. + + From f3dad300a7bbf86ed84fb9b09be33554c44ddc39 Mon Sep 17 00:00:00 2001 From: Zeinab Pourgheisari Date: Thu, 2 Oct 2025 19:46:03 +0200 Subject: [PATCH 4/6] isAlreadyPresent --- .../FTD/GSAAnalysis.md | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/docs/DeveloperGuide/DynamaticFeaturesAndOptimizations/FTD/GSAAnalysis.md b/docs/DeveloperGuide/DynamaticFeaturesAndOptimizations/FTD/GSAAnalysis.md index 773a61e713..8ea6170cb2 100644 --- a/docs/DeveloperGuide/DynamaticFeaturesAndOptimizations/FTD/GSAAnalysis.md +++ b/docs/DeveloperGuide/DynamaticFeaturesAndOptimizations/FTD/GSAAnalysis.md @@ -100,12 +100,28 @@ After all ϕ gates are created, the final step is to connect the missing inputs The input of a ϕ gate can itself be another ϕ. This happens when the input comes from a block argument of another block (excluding bb0). In this case, the ϕ input cannot be connected immediately. Instead, it is marked as missing and the necessary information is stored. After all ϕ gates are extracted, these missing inputs are revisited and the connections are reconstructed. ### `isBlockArgAlreadyPresent` and `isValueAlreadyPresent` -These helper functions prevent duplicate inputs from being recorded. -// TODO: explain their implementation details later. +These two helper functions avoid recording duplicate inputs for a ϕ. -### Why can a value appear multiple times? -// TODo +- `isValueAlreadyPresent` + + This one is straightforward: it directly checks if the same SSA value is already in the operand list (`operands`). + + If found, we don’t add it again; instead, we just update its sender list to record that this value can also arrive from the current predecessor (`pred`). + +- `isBlockArgAlreadyPresent` + + Block arguments are trickier, because at this stage we may not have the actual value to compare. + + Instead, two block arguments are considered duplicates if: + + - they originate from the same argument position of the same block, and + + - they target the same argument position of the same block. + + If these conditions hold, we treat them as the same missing ϕ input. As with values, we don’t add a new entry; instead, we **update the sender list** of the existing one to include the current predecessor. + +In both cases, the key idea is: a duplicate input means the same logical operand is reachable through multiple control-flow edges, so we reuse the operand and just record the extra senders. ## Convert ϕ Gates into μ Gates From d17d4ca5995fad74006c631c0f94e0229ef41fdb Mon Sep 17 00:00:00 2001 From: Zeinab Pourgheisari Date: Fri, 24 Oct 2025 23:02:27 +0200 Subject: [PATCH 5/6] Edit1 --- .../FTD/GSAAnalysis.md | 45 +++++++++++-------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/docs/DeveloperGuide/DynamaticFeaturesAndOptimizations/FTD/GSAAnalysis.md b/docs/DeveloperGuide/DynamaticFeaturesAndOptimizations/FTD/GSAAnalysis.md index 8ea6170cb2..cfddb8bcb2 100644 --- a/docs/DeveloperGuide/DynamaticFeaturesAndOptimizations/FTD/GSAAnalysis.md +++ b/docs/DeveloperGuide/DynamaticFeaturesAndOptimizations/FTD/GSAAnalysis.md @@ -1,22 +1,22 @@ # GSA Analysis ## Introduction -In Static Single Assignment (SSA) form, every variable is assigned exactly once, and ϕ (phi) functions are introduced to merge values coming from different control flow paths. While SSA is powerful, it does not explicitly encode the control-flow decisions that determine which value is actually chosen at runtime. +In Static Single Assignment (SSA) form, every variable is assigned exactly once, and ϕ (phi) functions are introduced to merge values coming from different control flow paths. While SSA is powerful, it does not explicitly encode the control flow decisions that determine which value is actually chosen at runtime. -**Gated Single Assignment (GSA)** was introduced as an extension of SSA to make these control-flow decisions explicit. Instead of a single generic ϕ merge, GSA introduces specialized gates: -- The **μ (mu) gate** appears at loop headers. It chooses between an initial value coming from outside the loop and a value produced inside the loop. The decision is driven by the loop’s condition: if the loop is starting, the initial value is used; if the loop is iterating, the loop value is used. -- The **γ (gamma) gate** replaces a ϕ at control-flow merges. It selects between a true value and a false value depending on a condition signal (like at the end of an if–else). In hardware, this becomes a multiplexer. +**Gated Single Assignment (GSA)** was introduced as an extension of SSA to make these control flow decisions explicit. Instead of a single generic ϕ merge, GSA introduces specialized gates: +- The **μ (mu) gate** appears at loop headers. It chooses between an initial value coming from outside the loop and a value produced inside the loop. The decision is driven by the loop’s condition: if the loop is starting, the initial value is used; if the loop is iterating, the loop value is used. In hardware, it is translated into a multiplexer, and its condition is driven through an INIT. +- The **γ (gamma) gate** appears at the confluence point of an if–else structure. It selects between a true value and a false value depending on a condition signal. In hardware, this maps to a multiplexer controlled by the block’s branching condition. -For Dynamatic’s **Fast Token Delivery (FTD)** algorithm, having the program represented in GSA form is required. The MLIR cf dialect already provides ϕ-gates in SSA form, but these must be translated into their GSA equivalents. During this translation, every block argument(pottential ϕ) in the control-flow is rewritten as either a μ or a γ gate. +For Dynamatic’s **Fast Token Delivery (FTD)** algorithm, having the program represented in GSA form is required. The MLIR cf dialect already provides ϕ-gates in SSA form, but these must be translated into their GSA equivalents. During this translation, every block argument (i.e., potential ϕ) in the control flow is rewritten as either a μ or a γ gate. ### Example -Consider the following control-flow graph and its corresponding `cf_dyn_transformed.mlir` code. +Consider the following control flow graph and its corresponding `cf_dyn_transformed.mlir` code. - bb1 and bb3 both receive arguments from multiple predecessors. Implicit ϕ-gates are therefore placed in these blocks. - The first argument of bb1 (%0) chooses between the initial value %c0 from bb0 and the loop-carried value %8 from bb3. This corresponds to a μ function. - The second argument of bb1 (%1) is also updated inside the loop, so it too becomes a μ function. -- The argument of bb3 (%7) comes from two mutually exclusive control-flow paths (bb1 or bb2). This corresponds to a γ function. +- The argument of bb3 (%7) comes from two mutually exclusive control flow paths (bb1 or bb2). This corresponds to a γ function. ![if_loop_add_CFG](./Figures/if_loop_add_CFG.png) @@ -94,7 +94,11 @@ For each block in the region: If `operands` is not empty (the ϕ has at least one input): → create the ϕ gate and associate it with the block. ``` -After all ϕ gates are created, the final step is to connect the missing inputs recorded in phisToConnect. +After all ϕ gates are created (i.e., all block arguments have been explored), we are guaranteed that every ϕ producing inputs for a missing ϕ has now been generated. + +At this stage, all missing ϕs have been recorded, and their corresponding source ϕs exist.Therefore, the final step is to reconnect these missing ϕs to their proper sources. + +The definition of a “missing ϕ” is explained next. ### What is a “missing phi”? The input of a ϕ gate can itself be another ϕ. This happens when the input comes from a block argument of another block (excluding bb0). In this case, the ϕ input cannot be connected immediately. Instead, it is marked as missing and the necessary information is stored. After all ϕ gates are extracted, these missing inputs are revisited and the connections are reconstructed. @@ -121,7 +125,7 @@ These two helper functions avoid recording duplicate inputs for a ϕ. If these conditions hold, we treat them as the same missing ϕ input. As with values, we don’t add a new entry; instead, we **update the sender list** of the existing one to include the current predecessor. -In both cases, the key idea is: a duplicate input means the same logical operand is reachable through multiple control-flow edges, so we reuse the operand and just record the extra senders. +In both cases, the key idea is: a duplicate input means the same logical operand is reachable through multiple control flow edges, so we reuse the operand and just record the extra senders. ## Convert ϕ Gates into μ Gates @@ -168,6 +172,8 @@ Therefore, the condition of a μ gate is defined as the **negation of the loop e #### Note: The `getLoopExitCondition` function computes the overall exit condition by OR-ing the conditions of all loop exiting blocks. This function relies on `getBlockLoopExitCondition`, which computes the exit condition for a single block. +This OR-ing occurs between operations that produce different token counts; therefore, it is implemented in the **FTDConversion** pass using **Shannon’s expansion**. + ## Convert ϕ Gates into γ Gates All remaining ϕ gates (i.e., those not turned into μ gates) must be converted into γ gates. @@ -175,7 +181,7 @@ However, a single γ gate is only a **two-input multiplexer**, while a ϕ can ha To handle this, we build a tree of γ gates, each driven by a simple condition. The following steps describe the process. -### Input Ordering +### Step 1. Input Ordering The inputs of a ϕ are sorted based on the dominance relationship between their originating basic blocks. - If block Bi dominates block Bj, then the input from Bi is placed before Bj. @@ -185,7 +191,8 @@ The inputs of a ϕ are sorted based on the dominance relationship between their ### Step 2. Find Common Dominator Find **the nearest common dominator** among all input blocks of the ϕ. -This block acts as the root for path exploration. + +This block will be used as the root for path exploration in the next step. ### Step 3. Path Identification @@ -193,11 +200,11 @@ For each input operand: - Find all paths from the common dominator to the ϕ’s block that **pass through the operand’s block** but **avoid later operand blocks**. -- Paths are explored using a modified DFS that: +- Paths are explored using a modified DFS function that: - finds all possible paths between two blocks, - - avoids certain “blocked” nodes, + - avoids certain blocks, - and allows a block to be revisited only if it is both the start and end (for loop cases). @@ -229,7 +236,7 @@ The process works as follows: **1. Pick a cofactor (condition):** -The function starts from the queue of cofactors (Boolean conditions associated with blocks). Since they are ordered by block index, the first cofactor we take is guaranteed to be common to all input expressions (because the blocks associated with it dominate the others). This ensures that splitting on this cofactor applies consistently across all inputs. +The function starts from the queue of cofactors (i.e., the Boolean conditions collected and sorted in the previous step). Since they are ordered by block index, the first cofactor we take is guaranteed to be common to all input expressions (because the blocks associated with it dominate the others). This ensures that splitting on this cofactor applies consistently across all inputs. **2. Split expressions by condition:** @@ -245,11 +252,13 @@ For each input expression (operand + condition): Now we decide what should feed the true and false inputs of the γ gate being built: -- If a side has **more than one expression**, this means multiple operands could be selected under that branch of the condition. To resolve this, we recursively call `expandGammaTree` on that subset. The resulting γ gate from the recursion becomes the input of the current γ. +- For each condition outcome (`conditionsTrueExpressions` or `conditionsFalseExpressions`), check how many expressions it contains. + +- If it contains **more than one expression**, this means multiple operands could be selected under that branch of the condition. To resolve this, we recursively call `expandGammaTree` on that subset. The resulting γ gate from the recursion becomes the input of the current γ. -- If a side has `exactly one expression`, its operand is directly assigned as the input of the current γ. +- If it contains `exactly one expression`, its operand is directly assigned as the input of the current γ. -- If a side has `no expressions`, it means this branch of the condition is never taken. In that case, an empty (null) input is created. +- If it contains `no expressions`, that outcome of the condition is never taken, and an empty input is created. **4. Create the γ gate:** @@ -259,7 +268,7 @@ A new γ is generated: - Its condition is the cofactor currently being expanded. -- Internally, its output is temporarily set to the original ϕ’s result (only the root γ of the tree will preserve this). +- Internally, its output is temporarily set to the original ϕ’s result. If the γ is not the root, this output will later become a “true” or “false” input of another γ, and the connection is updated when that parent γ is created. **5. Placement rule:** From 04f825f17d07b44a6da8dbf538fc604641cb38b5 Mon Sep 17 00:00:00 2001 From: Zeinab Pourgheisari Date: Mon, 27 Oct 2025 20:50:24 +0100 Subject: [PATCH 6/6] Edit + Example --- .../FTD/Figures/iterative_sqrt_CFG.png | Bin 0 -> 38118 bytes .../FTD/Figures/loop_multiply_CFG.png | Bin 0 -> 21135 bytes .../FTD/GSAAnalysis.md | 294 +++++++++++++++++- 3 files changed, 284 insertions(+), 10 deletions(-) create mode 100644 docs/DeveloperGuide/DynamaticFeaturesAndOptimizations/FTD/Figures/iterative_sqrt_CFG.png create mode 100644 docs/DeveloperGuide/DynamaticFeaturesAndOptimizations/FTD/Figures/loop_multiply_CFG.png diff --git a/docs/DeveloperGuide/DynamaticFeaturesAndOptimizations/FTD/Figures/iterative_sqrt_CFG.png b/docs/DeveloperGuide/DynamaticFeaturesAndOptimizations/FTD/Figures/iterative_sqrt_CFG.png new file mode 100644 index 0000000000000000000000000000000000000000..bc00f3e3694f9131a92777b7760600464548daf7 GIT binary patch literal 38118 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 KJU(P~{r>?U-f9T| literal 0 HcmV?d00001 diff --git a/docs/DeveloperGuide/DynamaticFeaturesAndOptimizations/FTD/Figures/loop_multiply_CFG.png b/docs/DeveloperGuide/DynamaticFeaturesAndOptimizations/FTD/Figures/loop_multiply_CFG.png new file mode 100644 index 0000000000000000000000000000000000000000..588c347cc0d86d73e1e3bb4b512c7ce2caa07aa2 GIT binary patch literal 21135 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 X)?_}U{1 operands; // Inputs of this gate + GateType gsaGateFunction; // Type: PhiGate, GammaGate, or MuGate + Block *conditionBlock; // Block driving the gate’s condition + boolean::BoolExpression *condition; // Boolean condition of the gate + std::vector cofactorList; // Condition cofactors + Block *gateBlock; // Block where the gate is located + bool muGenerated; // True if generated from MU expansion + unsigned index; // Unique gate index + bool isRoot; // True if it’s a root gate +}; +``` +##### Additional Details on Fields: +`conditionBlock` + +This field identifies the block whose terminator provides the control predicate for the gate. + +- For γ gates, it is the producer block of the condition that determines which input the γ selects. + +- For μ gates, it refers to the producer of the unique loop exit condition (the condition that decides when the loop terminates). + +- For ϕ gates and μ gates with multiple exits, this field is nullptr, as no single condition block drives their creation. + + +`condition` + +A Boolean expression representing the logical condition associated with the gate. + +- For γ gates, it corresponds directly to the predicate that decides which branch or input is selected. + +- For μ gates, it is the negation of the loop exit condition, expressing the continuation of the loop. + +- For ϕ gates, it is initialized to a constant `BoolZero()` (a neutral condition), since ϕ gates only merge data and are not controlled by predicates. + +`cofactorList` + +A list of string identifiers corresponding to condition cofactors. + +These are useful when decomposing complex Boolean expressions into simpler components. + +`gateBlock` + +The block where this gate is logically placed. + +In most cases, `gateBlock` coincides with the block containing the gate’s output value (`result`). + +However, for γ gates generated during μ expansion, the gate is placed in the same block as its `conditionBlock`, following the placement rules described in [this section](#5-placement-rule). +This ensures that the γ is evaluated under the same control context as its condition. + +`muGenerated` + +A flag that indicates whether this gate was created during the `convertPhiToMu` phase, specifically to resolve multiple loop-input cases. + +This flag later determines where the corresponding γ gates should be placed, as their `gateBlock` is adjusted according to the μ placement logic (see [Placement Rule section](#5-placement-rule) for details). + +`isRoot` + +Specifies whether the gate is the root of its gate tree. + +- All μ gates are considered roots. + +- Only the base γ in a γ-tree is marked as root. + +- ϕ gates do not require root tracking; the field is +initialized as false for them. + +#### GateInput Structure + +A `GateInput` represents a single input to a gate. +Each input can be: + +- a `Value` which is result of an operation, + +- output of another `Gate`, or + +- empty (if not yet connected, e.g., a missing ϕ). + +It also keeps track of all the **sender blocks** (i.e., CFG predecessors that forward this input to the gate). + +This distinction between producers and senders is crucial: + +- The producer is where the value (or gate result) is originally defined. + +- The sender is the block whose terminator forwards that value to the gate. For control dependent analysis (like γ construction), predicates must be computed with respect to the sender blocks (check "[Operands from the same block](#operands-from-the-same-block)" for more information). + +Structure Summary: +``` +struct GateInput { + std::variant input; // The actual input: IR value, gate, or empty. + std::unordered_set senders; // CFG blocks forwarding this input. +}; +``` + +--- + +With the `Gate` and `GateInput` structures defined, we can now outline how implicit ϕ gates are identified. + +This process scans each block in the region, examines its block arguments, and creates corresponding ϕ gates by linking them to their incoming values and sender blocks. Note: If there is only one block in the region being checked, nothing needs to be done since there is no possibility of multiple assignments. @@ -81,7 +201,7 @@ For each block in the region: - `isBlockArgAlreadyPresent` checks block arguments. - `isValueAlreadyPresent` checks plain SSA values. - If the value is new: + If the value is new (i.e., the corresponding isAlreadyPresent check returns false): - Wrap it in a `gateInput` structure. - If it is a missing phi: * Add it to `phisToConnect` (records phis that need reconnection later). @@ -169,6 +289,17 @@ The μ gate outputs its initial value during the first iteration of the loop. On Therefore, the condition of a μ gate is defined as the **negation of the loop exit condition**. +In the later stages in FTD implementation, the μ gate is replaced by a MUX. +Its condition comes from an INIT, implemented as a merge between a constant and the loop’s iterating condition (i.e., the negation of the loop exit condition mentioned above). + +This design ensures that: + +- During the first iteration of the first execution, the constant drives the selection, causing the initial value to be used. + +- In subsequent loop iterations, the iterating condition (the negated loop exit) selects the loop-carried value. + +- When the loop terminates and is later re-entered, the loop exit condition itself guarantees that the initial input is selected again (no constant is needed in later executions). + #### Note: The `getLoopExitCondition` function computes the overall exit condition by OR-ing the conditions of all loop exiting blocks. This function relies on `getBlockLoopExitCondition`, which computes the exit condition for a single block. @@ -198,9 +329,9 @@ This block will be used as the root for path exploration in the next step. For each input operand: -- Find all paths from the common dominator to the ϕ’s block that **pass through the operand’s block** but **avoid later operand blocks**. +- Find all paths from the common dominator to the ϕ’s block that **pass through the operand’s block** but **avoid later operand blocks** that come later in the dominance order. -- Paths are explored using a modified DFS function that: +- Paths are explored through the `findAllPaths` function, which calls `dfsAllPaths` to: - finds all possible paths between two blocks, @@ -208,10 +339,55 @@ For each input operand: - and allows a block to be revisited only if it is both the start and end (for loop cases). -**Operands from the same block:** +#### Operands from the same block: If one block produces multiple values (operands) for the same ϕ, the DFS initially gives them identical paths. +For example, in the cf_dyn_transformed.mlir snippet below, which corresponds to the shown CFG: + +``` +module { + func.func @iterative_sqrt(%arg0: i32 {handshake.arg_name = "n"}) -> i32 { + ... + cf.br ^bb1(%arg0, %c0_i32, %true : i32, i32, i1) {handshake.name = "br0"} + ^bb1(%0: i32, %1: i32, %2: i1): // 4 preds: ^bb0, ^bb2, ^bb4, ^bb5 + ... + cf.cond_br %4, ^bb2(%0, %1 : i32, i32), ^bb6 {handshake.name = "cond_br0"} + ^bb2(%5: i32, %6: i32): // pred: ^bb1 + ... + %8 = arith.shrsi %7, %c1_i32 {handshake.name = "shrsi0"} : i32 + ... + cf.cond_br %14, ^bb1(%8, %6, %15 : i32, i32, i1), ^bb3 {handshake.name = "cond_br1"} + ^bb3: // pred: ^bb2 + ... + cf.cond_br %16, ^bb4, ^bb5 {handshake.name = "cond_br2"} + ^bb4: // pred: ^bb3 + ... + cf.br ^bb1(%5, %17, %15 : i32, i32, i1) {handshake.name = "br1"} + ^bb5: // pred: ^bb3 + ... + %18 = arith.addi %8, %c-1_i32 {handshake.name = "addi2"} : i32 + cf.br ^bb1(%18, %6, %15 : i32, i32, i1) {handshake.name = "br7"} + ^bb6: // pred: ^bb1 + return {handshake.name = "return0"} %0 : i32 + } +} + +``` +![iterative_sqrt_CFG](./Figures/iterative_sqrt_CFG.png) + +Blocks `bb0`, `bb2`, `bb4`, and `bb5` send values to argument 0 of bb1. +Notice that both `bb4` and `bb2` send values produced in `bb2` (`%5` and `%8` respectively). + +When exploring paths, the DFS detects two possible routes from the producer `bb2` to the consumer `bb1`: +`{bb2, bb1}` and `{bb2, bb3, bb4, bb1}`. + +However: + +The sender of `%8` is `bb2`, so only `{bb2, bb1}` is a valid path. + +The sender of `%5` is `bb4`, so only `{bb2, bb3, bb4, bb1}` is valid. + To disambiguate, we filter the paths by the sender block (the block immediately before the ϕ in the path). Only paths whose sender matches the operand’s recorded sender are kept. @@ -234,11 +410,11 @@ Each γ is a two-input MUX driven by one simple Boolean condition. The process works as follows: -**1. Pick a cofactor (condition):** +#### 1. Pick a cofactor (condition): The function starts from the queue of cofactors (i.e., the Boolean conditions collected and sorted in the previous step). Since they are ordered by block index, the first cofactor we take is guaranteed to be common to all input expressions (because the blocks associated with it dominate the others). This ensures that splitting on this cofactor applies consistently across all inputs. -**2. Split expressions by condition:** +#### 2. Split expressions by condition: For each input expression (operand + condition): @@ -248,7 +424,7 @@ For each input expression (operand + condition): - Add the non-zero result(s) to either `conditionsTrueExpressions` or `conditionsFalseExpressions`. -**3. Build γ inputs:** +#### 3. Build γ inputs: Now we decide what should feed the true and false inputs of the γ gate being built: @@ -260,7 +436,7 @@ Now we decide what should feed the true and false inputs of the γ gate being bu - If it contains `no expressions`, that outcome of the condition is never taken, and an empty input is created. -**4. Create the γ gate:** +#### 4. Create the γ gate: A new γ is generated: @@ -270,7 +446,7 @@ A new γ is generated: - Internally, its output is temporarily set to the original ϕ’s result. If the γ is not the root, this output will later become a “true” or “false” input of another γ, and the connection is updated when that parent γ is created. -**5. Placement rule:** +#### 5. Placement rule: Normally, new γ gates are placed in the **same block as the original ϕ**. @@ -296,4 +472,102 @@ Once a ϕ is replaced by its γ tree: - All gates that previously used the ϕ’s output are updated to use the root γ gate instead. +--- +### Example: + +To illustrate the conversion of a ϕ gate into a tree of γ gates, consider the following reduced MLIR function: +``` +module { + func.func @example(%arg0: memref<8xi32> {handshake.arg_name = "a"}) -> i32 { + ... + %c0_i32 = arith.constant {handshake.name = "constant2"} 0 : i32 + cf.cond_br %2, ^bb1, ^bb3(%c0_i32, %c2_i32 : i32, i32) {handshake.name = "cond_br0"} + + ^bb1: // pred: ^bb0 + ... + %c0_i32_0 = arith.constant {handshake.name = "constant10"} 0 : i32 + cf.cond_br %4, ^bb3(%c0_i32_0, %5 : i32, i32), ^bb2 {handshake.name = "cond_br1"} + + ^bb2: // pred: ^bb1 + ... + %9 = arith.select %8, %c5_i32_2, %c0_i32_3 {handshake.name = "select1"} : i32 + cf.br ^bb3(%9, %5 : i32, i32) {handshake.name = "br3"} + + ^bb3(%10: i32, %11: i32): // 3 preds: ^bb0, ^bb1, ^bb2 + %12 = arith.addi %11, %10 {handshake.name = "addi0"} : i32 + return {handshake.name = "return0"} %12 : i32 + } +} +``` +The corresponding control flow graph is shown below: + +![gamma_example](./Figures/loop_multiply_CFG.png) + +We will convert the ϕ in block bb3 (which merges values coming from bb0, bb1, and bb2) into an equivalent γ tree. + +### Step 1. Input Ordering + +The inputs from `bb0`, `bb1`, and `bb2` (namely `%c0_i32`, `%c0_i32_0`, and `%9`) are referred to as **x₀**, **x₁**, and **x₂**, respectively. +After dominance-based ordering, we have: +`x₀ (bb0)`, `x₁ (bb1)`, `x₂ (bb2)`. + + +### Step 2. Find Common Dominator + +The nearest common dominator of all three input blocks is **bb0**. + + + +### Step 3. Path Identification + +For each input, all valid paths from the common dominator (`bb0`) to the ϕ’s block (`bb3`) are identified, while avoiding blocks corresponding to **later operand producers**: + +- **x₀:** `{bb0, bb3}` *(must not pass through `bb1` or `bb2`, which produce later operands)* +- **x₁:** `{bb0, bb1, bb3}` *(must not pass through `bb2`, the later operand producer)* +- **x₂:** `{bb0, bb1, bb2, bb3}` + +Next, we filter paths by the **sender block** (the block immediately before the ϕ) to ensure correct operand assignment: + +- `%c0_i32` (x₀) sender: `bb0` → path `{bb0, bb3}` +- `%c0_i32_0` (x₁) sender: `bb1` → path `{bb0, bb1, bb3}` +- `%9` (x₂) sender: `bb2` → path `{bb0, bb1, bb2, bb3}` + + +### Step 4. Boolean Conditions + +Compute a Boolean expression for each operand: + +- **x₀:** `!c0` +- **x₁:** `c0 & c1` +- **x₂:** `c0 & !c1` + +These expressions indicate under which conditions each input is selected. + + +### Step 5. Build the γ Tree + +1. **Pick the first cofactor (c0):** + - Both x₁ and x₂ remain non-zero when `c0 = true` → more than one expression → recursive `expandGammaTree` call needed. + +2. **Second cofactor (c1) inside recursion:** + - x₁: non-zero for `c1 = true` → true input + - x₂: non-zero for `c1 = false` → false input + + Resulting γ gate: `γ(c1, x2, x1)` + - Condition: c1 + - True input: x1 + - False input: x2 + +3. **Top-level γ gate:** `γ(c0, x0, γ(c1, x2, x1))` + - Condition: c0 + - True input: γ(c1, x2, x1) (from recursion) + - False input: x0 + +This γ gate becomes the **root** of the tree. + + + +### Step 6. Connect Uses + +All uses of the original ϕ are updated to use the root γ gate instead.