diff --git a/include/NeuraDialect/CMakeLists.txt b/include/NeuraDialect/CMakeLists.txt index 1c9b30b5..b829e584 100644 --- a/include/NeuraDialect/CMakeLists.txt +++ b/include/NeuraDialect/CMakeLists.txt @@ -1,11 +1,3 @@ -# Set TableGen include paths -set(MLIR_TABLEGEN_INCLUDES - ${PROJECT_SOURCE_DIR}/include - ${PROJECT_SOURCE_DIR}/include/NeuraDialect - ${CMAKE_CURRENT_BINARY_DIR}/include/NeuraDialect - ${MLIR_MAIN_INCLUDE_DIR} - ${MLIR_INCLUDE_DIR}) - add_mlir_dialect(Neura neura) set(LLVM_TARGET_DEFINITIONS NeuraPasses.td) diff --git a/include/NeuraDialect/NeuraOps.td b/include/NeuraDialect/NeuraOps.td index 2c2a8758..25028b57 100644 --- a/include/NeuraDialect/NeuraOps.td +++ b/include/NeuraDialect/NeuraOps.td @@ -125,7 +125,7 @@ def Neura_LoadIndexedOp: Op:$base, Variadic:$indices, Optional:$predicate); + let arguments = (ins AnyType:$base, Variadic:$indices, Optional:$predicate); let results = (outs AnyType:$result); let assemblyFormat = "$base `[` $indices `:` type($indices) `]` type($base) ($predicate^ `:` type($predicate))? attr-dict `:` type($result)"; } @@ -139,7 +139,7 @@ def Neura_StoreIndexedOp: Op:$base, Variadic:$indices, Optional:$predicate); + let arguments = (ins AnyType:$value, AnyType:$base, Variadic:$indices, Optional:$predicate); let results = (outs); let assemblyFormat = "$value `to` $base `[` $indices `:` type($indices) `]` type($base) ($predicate^ `:` type($predicate))? attr-dict `:` type($value)"; } diff --git a/lib/Conversion/CMakeLists.txt b/lib/Conversion/CMakeLists.txt index ee851744..98f5dac2 100644 --- a/lib/Conversion/CMakeLists.txt +++ b/lib/Conversion/CMakeLists.txt @@ -5,22 +5,6 @@ add_subdirectory(LlvmToNeura) add_subdirectory(MemRefToNeura) add_subdirectory(BuiltinToNeura) -# add_mlir_library( -# MLIRNeuraConversion - -# DEPENDS -# MLIRNeuraTransformsIncGen - -# LINK_LIBS PUBLIC -# MLIRIR -# MLIRPass -# MLIRSupport -# MLIRTransforms -# MLIRNeura -# MLIRNeuraArithToNeuraPass -# MLIRNeuraLlvmToNeuraPass -# ${dialect_libs} -# ) add_library(MLIRConversion INTERFACE) add_dependencies(MLIRConversion MLIRConversionIncGen) diff --git a/lib/NeuraDialect/CMakeLists.txt b/lib/NeuraDialect/CMakeLists.txt index 6ed04ae7..d843b0e3 100644 --- a/lib/NeuraDialect/CMakeLists.txt +++ b/lib/NeuraDialect/CMakeLists.txt @@ -1,19 +1,3 @@ -# Set include paths for TableGen -set(MLIR_TABLEGEN_INCLUDES - "-I${PROJECT_SOURCE_DIR}/include" - "-I${PROJECT_SOURCE_DIR}/include/NeuraDialect" - "-I${CMAKE_CURRENT_BINARY_DIR}/include/NeuraDialect") - -# Generate TableGen files -set(LLVM_TARGET_DEFINITIONS ${PROJECT_SOURCE_DIR}/include/NeuraDialect/Neura.td) -mlir_tablegen(Neura.h.inc -gen-op-decls ${MLIR_TABLEGEN_INCLUDES}) -mlir_tablegen(Neura.cpp.inc -gen-op-defs ${MLIR_TABLEGEN_INCLUDES}) -mlir_tablegen(NeuraDialect.h.inc -gen-dialect-decls ${MLIR_TABLEGEN_INCLUDES}) -mlir_tablegen(NeuraDialect.cpp.inc -gen-dialect-defs ${MLIR_TABLEGEN_INCLUDES}) -mlir_tablegen(NeuraTypes.h.inc -gen-typedef-decls ${MLIR_TABLEGEN_INCLUDES}) -mlir_tablegen(NeuraTypes.cpp.inc -gen-typedef-defs ${MLIR_TABLEGEN_INCLUDES}) -add_public_tablegen_target(MLIRNeuraDialectIncGen) - # Add the dialect library add_mlir_dialect_library(MLIRNeura Neura.cpp @@ -24,7 +8,6 @@ add_mlir_dialect_library(MLIRNeura ${PROJECT_SOURCE_DIR}/include/NeuraDialect DEPENDS - MLIRNeuraDialectIncGen MLIRNeuraTransformsIncGen MLIRConversionIncGen diff --git a/lib/NeuraDialect/Transforms/LeveragePredicatedValuePass.cpp b/lib/NeuraDialect/Transforms/LeveragePredicatedValuePass.cpp index e894c2d0..48038f77 100644 --- a/lib/NeuraDialect/Transforms/LeveragePredicatedValuePass.cpp +++ b/lib/NeuraDialect/Transforms/LeveragePredicatedValuePass.cpp @@ -6,6 +6,7 @@ #include "mlir/IR/PatternMatch.h" #include "mlir/Pass/Pass.h" #include "mlir/Transforms/GreedyPatternRewriteDriver.h" +#include "llvm/Support/raw_ostream.h" using namespace mlir; @@ -38,6 +39,7 @@ struct LeveragePredicatedValuePass if (block == &block->getParent()->front()) { return; } + for (BlockArgument arg : block->getArguments()) { Type origType = arg.getType(); diff --git a/lib/NeuraDialect/Transforms/TransformCtrlToDataFlowPass.cpp b/lib/NeuraDialect/Transforms/TransformCtrlToDataFlowPass.cpp index 095aedec..599398d6 100644 --- a/lib/NeuraDialect/Transforms/TransformCtrlToDataFlowPass.cpp +++ b/lib/NeuraDialect/Transforms/TransformCtrlToDataFlowPass.cpp @@ -1,11 +1,19 @@ #include "Common/AcceleratorAttrs.h" #include "NeuraDialect/NeuraDialect.h" #include "NeuraDialect/NeuraOps.h" -#include "NeuraDialect/NeuraTypes.h" #include "NeuraDialect/NeuraPasses.h" +#include "NeuraDialect/NeuraTypes.h" +#include "mlir/Dialect/Func/IR/FuncOps.h" +#include "mlir/IR/Block.h" +#include "mlir/IR/Dominance.h" +#include "mlir/IR/Location.h" #include "mlir/IR/PatternMatch.h" +#include "mlir/IR/Value.h" #include "mlir/Pass/Pass.h" -#include "mlir/Dialect/Func/IR/FuncOps.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/raw_ostream.h" using namespace mlir; @@ -32,7 +40,7 @@ void GrantPredicateInEntryBlock(Block *entry_block, OpBuilder &builder) { // Case 1: Operand of a branch/cond_br → grant_once if (isa(user)) { - used_in_branch = true; + used_in_branch = true; } // Case 2: Used directly in other blocks → grant_always @@ -56,7 +64,8 @@ void GrantPredicateInEntryBlock(Block *entry_block, OpBuilder &builder) { continue; builder.setInsertionPointAfter(def_op); - auto granted = builder.create(def_op->getLoc(), val.getType(), val); + auto granted = builder.create(def_op->getLoc(), + val.getType(), val); // Replaces uses in branch ops. for (OpOperand &use : llvm::make_early_inc_range(val.getUses())) { @@ -74,7 +83,8 @@ void GrantPredicateInEntryBlock(Block *entry_block, OpBuilder &builder) { continue; builder.setInsertionPointAfter(def_op); - auto granted = builder.create(def_op->getLoc(), val.getType(), val); + auto granted = builder.create(def_op->getLoc(), + val.getType(), val); // Replaces direct external uses (not in entry block, not in branch ops). for (OpOperand &use : llvm::make_early_inc_range(val.getUses())) { @@ -88,8 +98,9 @@ void GrantPredicateInEntryBlock(Block *entry_block, OpBuilder &builder) { } // Returns blocks in post-order traversal order. -void getBlocksInPostOrder(Block *startBlock, SmallVectorImpl &postOrder, - DenseSet &visited) { +void getBlocksInPostOrder(Block *startBlock, + SmallVectorImpl &postOrder, + DenseSet &visited) { if (!visited.insert(startBlock).second) return; @@ -103,199 +114,244 @@ void getBlocksInPostOrder(Block *startBlock, SmallVectorImpl &postOrder // Creates phi nodes for all live-in values in the given block. void createPhiNodesForBlock( - Block *block, OpBuilder &builder, - SmallVectorImpl> &deferred_ctrl_movs) { + Block *block, Block *entry_block, OpBuilder &builder, + SmallVectorImpl> + &deferred_ctrl_movs) { if (block->hasNoPredecessors()) { // Skips phi insertion for entry block. return; } + bool has_block_args = false; // Collects all live-in values. - std::vector live_ins; + SmallVector live_ins; for (Operation &op : *block) { for (Value operand : op.getOperands()) { // Identifies operands defined in other blocks. if (operand.getDefiningOp() && operand.getDefiningOp()->getBlock() != block) { - live_ins.push_back(operand); - continue; + if (!llvm::is_contained(live_ins, operand)) { + live_ins.push_back(operand); + continue; + } } - // Collects all block arguments. - if (auto blockArg = llvm::dyn_cast(operand)) { - live_ins.push_back(operand); + + // Collects block arguments as live-ins. + if (auto arg = dyn_cast(operand)) { + if (!llvm::is_contained(live_ins, arg) && arg.getOwner() == block) { + has_block_args = true; + live_ins.push_back(arg); + continue; + } } } } builder.setInsertionPointToStart(block); - for (Value live_in : live_ins) { - // Creates predicated type for phi node. - Type live_in_type = live_in.getType(); - Type predicated_type = isa(live_in_type) - ? live_in_type - : neura::PredicatedValue::get(builder.getContext(), live_in_type, builder.getI1Type()); - - // Uses the location from the first operation in the block or block's parent operation. - Location loc = block->empty() ? - block->getParent()->getLoc() : - block->front().getLoc(); - SmallVector phi_operands; - llvm::SmallDenseSet just_created_consumer_ops; - BlockArgument arg = dyn_cast(live_in); - // TODO: Following logic needs to be refactored. - for (Block *pred : block->getPredecessors()) { - Value incoming; - Value branch_pred; - Operation *term = pred->getTerminator(); - // If it's a branch or cond_br, get the value passed into this block argument - if (auto br = dyn_cast(term)) { - auto args = br.getArgs(); - if (arg) { - unsigned arg_index = arg.getArgNumber(); - assert(arg_index < args.size()); - incoming = args[arg_index]; - } else if (live_in.getDefiningOp()->getBlock() == pred) { - // Handles the case where live_in is not a block argument. - incoming = live_in; - } else { - // If live_in is not a block argument and not defined in the block, skips. - continue; - } - } else if (auto condBr = dyn_cast(term)) { - Value cond = condBr.getCondition(); - branch_pred = cond; // by default - OpBuilder pred_builder(condBr); - Location pred_loc = condBr.getLoc(); - - if (condBr.getTrueDest() == block) { - if (arg) { - auto trueArgs = condBr.getTrueArgs(); - unsigned arg_index = arg.getArgNumber(); - assert(arg_index < trueArgs.size()); - incoming = trueArgs[arg_index]; - } else if (live_in.getDefiningOp()->getBlock() == pred) { - // Handles the case where live_in is not a block argument. - incoming = live_in; + // Uses the location from the first operation in the block or block's parent + // operation. + Location loc = + block->empty() ? block->getParent()->getLoc() : block->front().getLoc(); + if (has_block_args) { + for (Value live_in : live_ins) { + // Creates predicated type for phi node. + Type live_in_type = live_in.getType(); + Type predicated_type = + isa(live_in_type) + ? live_in_type + : neura::PredicatedValue::get(builder.getContext(), live_in_type, + builder.getI1Type()); + + BlockArgument block_arg = dyn_cast(live_in); + bool is_block_arg = block_arg && block_arg.getOwner() == block; + + if (is_block_arg) { + SmallVector phi_operands; + llvm::SmallDenseSet just_created_consumer_ops; + for (Block *pred : block->getPredecessors()) { + Value incoming_in_pred; + Operation *term = pred->getTerminator(); + if (neura::Br br = dyn_cast(term)) { + auto pred_br_args = br.getArgs(); + unsigned arg_index = block_arg.getArgNumber(); + assert(arg_index < pred_br_args.size() && "Invalid arg index"); + incoming_in_pred = pred_br_args[arg_index]; + } else if (neura::CondBr cond_br = dyn_cast(term)) { + Value cond = cond_br.getCondition(); + OpBuilder pred_builder(cond_br); + Location pred_loc = cond_br.getLoc(); + + if (cond_br.getTrueDest() == block) { + auto pred_true_args = cond_br.getTrueArgs(); + unsigned arg_index = block_arg.getArgNumber(); + assert(arg_index < pred_true_args.size() && "Invalid arg index"); + incoming_in_pred = pred_true_args[arg_index]; + + // Applies grant_predicate. + incoming_in_pred = pred_builder.create( + pred_loc, incoming_in_pred.getType(), incoming_in_pred, cond); + just_created_consumer_ops.insert( + incoming_in_pred.getDefiningOp()); + } else if (cond_br.getFalseDest() == block) { + auto pred_false_args = cond_br.getFalseArgs(); + unsigned arg_index = block_arg.getArgNumber(); + assert(arg_index < pred_false_args.size() && "Invalid arg index"); + incoming_in_pred = pred_false_args[arg_index]; + + // Negates cond for false edge. + Value not_cond = pred_builder.create( + pred_loc, cond.getType(), cond); + // Applies grant_predicate. + incoming_in_pred = pred_builder.create( + pred_loc, incoming_in_pred.getType(), incoming_in_pred, + not_cond); + just_created_consumer_ops.insert( + incoming_in_pred.getDefiningOp()); + } } else { - // If live_in is not a block argument and not defined in the block, skips. + llvm::errs() << "[ctrl2data] Unknown branch terminator in block: " + << *pred << "\n"; continue; } - // Applies grant_predicate. - incoming = pred_builder.create( - pred_loc, incoming.getType(), incoming, cond); - just_created_consumer_ops.insert(incoming.getDefiningOp()); - // Keep branch_pred = cond - } else if (condBr.getFalseDest() == block) { - if (arg) { - auto falseArgs = condBr.getFalseArgs(); - unsigned arg_index = arg.getArgNumber(); - assert(arg_index < falseArgs.size()); - incoming = falseArgs[arg_index]; - } else if (live_in.getDefiningOp()->getBlock() == pred) { - // Handles the case where live_in is not a block argument. - incoming = live_in; + + DominanceInfo dom_info(block->getParentOp()); + if (incoming_in_pred.getDefiningOp() && + dom_info.dominates( + block, incoming_in_pred.getDefiningOp()->getBlock())) { + builder.setInsertionPointToStart(block); + Value placeholder = builder.create( + loc, incoming_in_pred.getType()); + phi_operands.push_back(placeholder); + // Defers the backward ctrl move operation to be inserted after + // phi operands are defined. Inserted: (real_defined_value, + // just_created_reserve, branch_pred, current_block). + deferred_ctrl_movs.emplace_back(incoming_in_pred, placeholder, + nullptr, block); } else { - // If live_in is not a block argument and not defined in the block, skips. - continue; + // No backward dependency found, just add the incoming value. + phi_operands.push_back(incoming_in_pred); } - // Negates cond for false edge. - branch_pred = pred_builder.create(pred_loc, cond.getType(), cond); - // Applies grant_predicate. - incoming = pred_builder.create( - pred_loc, incoming.getType(), incoming, branch_pred); - just_created_consumer_ops.insert(incoming.getDefiningOp()); - } else { - llvm::errs() << "cond_br does not target block:\n" << *block << "\n"; - assert(false); } - } else { - llvm::errs() << "Unknown branch terminator in block: " << *pred << "\n"; - continue; - } - // If the incoming value is defined in the same block, inserts a `neura.reserve` - // and defer a backward ctrl move. - if (incoming.getDefiningOp() && incoming.getDefiningOp()->getBlock() == block) { - builder.setInsertionPointToStart(block); - auto placeholder = builder.create(loc, incoming.getType()); - phi_operands.push_back(placeholder.getResult()); - // Defers the backward ctrl move operation to be inserted after all phi operands - // are defined. Inserted: - // (real_defined_value, just_created_reserve, branch_pred, current_block). - deferred_ctrl_movs.emplace_back( - incoming, placeholder.getResult(), branch_pred, block); - } else { - phi_operands.push_back(incoming); - } - // If live_in is not a block argument, we don't need to check for uniqueness. - if (!arg) { - continue; + // Puts all operands into a set to ensure uniqueness. Specifically, + // following case is handled: + // --------------------------------------------------------- + // ^bb1: + // "neura.br"(%a)[^bb3] : (!neura.data) -> () + // + // ^bb2: + // "neura.br"(%a)[^bb3] : (!neura.data) -> () + // + // ^bb3(%x: !neura.data): + // ... + // --------------------------------------------------------- + // In above case, %a is used in both branches of the control flow, so + // we don't need a phi node, but we still need to replace its uses + // with the result of the phi node. This ensures that we only create a + // phi node if there are multiple unique operands. + SmallVector unique_operands(phi_operands.begin(), + phi_operands.end()); + if (unique_operands.size() > 1) { + auto phi_op = + builder.create(loc, predicated_type, phi_operands); + SmallVector uses; + for (OpOperand &use : live_in.getUses()) { + if (use.getOwner() != phi_op) { + uses.push_back(&use); + } + } + for (OpOperand *use : uses) { + use->set(phi_op.getResult()); + } + } else if (unique_operands.size() == 1) { + // No phi needed, but still replace + Value single = unique_operands.front(); + SmallVector uses; + for (OpOperand &use : live_in.getUses()) { + // Skips uses that were just created by the grant_predicate. + if (!just_created_consumer_ops.contains(use.getOwner())) { + uses.push_back(&use); + } + } + for (OpOperand *use : uses) { + use->set(single); + } + continue; // No need to create a phi node. + } } } - assert(!phi_operands.empty()); - - // Puts all operands into a set to ensure uniqueness. Specifically, following - // case is handled: - // --------------------------------------------------------- - // ^bb1: - // "neura.br"(%a)[^bb3] : (!neura.data) -> () - // - // ^bb2: - // "neura.br"(%a)[^bb3] : (!neura.data) -> () - // - // ^bb3(%x: !neura.data): - // ... - // --------------------------------------------------------- - // In above case, %a is used in both branches of the control flow, so we - // don't need a phi node, but we still need to replace its uses with the - // result of the phi node. - // This ensures that we only create a phi node if there are multiple unique - // operands. - llvm::SmallDenseSet unique_operands(phi_operands.begin(), phi_operands.end()); - - if (unique_operands.size() == 1) { - // No phi needed, but still replace - Value single = *unique_operands.begin(); - SmallVector uses; - for (OpOperand &use : live_in.getUses()) { - // Skip uses that were just created by the grant_predicate. - if (!just_created_consumer_ops.contains(use.getOwner())) { - uses.push_back(&use); + } else { + if (block->hasOneUse() && block->getSinglePredecessor()) { + Block *pred_block = block->getSinglePredecessor(); + Operation *pred_term = pred_block->getTerminator(); + Value cond; + if (auto pred_cond_br = dyn_cast(pred_term)) { + if (pred_cond_br.getTrueDest() == block) { + cond = pred_cond_br.getCondition(); + } else if (pred_cond_br.getFalseDest() == block) { + OpBuilder pred_builder(pred_cond_br); + Location pred_loc = pred_cond_br.getLoc(); + cond = pred_builder.create( + pred_loc, pred_cond_br.getCondition().getType(), + pred_cond_br.getCondition()); } - } - for (OpOperand *use : uses) { - use->set(single); - } - // No need to proceed further to create a phi node, as we have a single unique operand. - continue; - } - // Creates the phi node with dynamic number of operands. - auto phi_op = builder.create(loc, predicated_type, phi_operands); + SmallVector> ops_to_process; + for (Operation &op : *block) { + if (isa(op)) { + continue; // Skips branch ops + } + + for (Value result : op.getResults()) { + if (!isa(result.getType())) + continue; + ops_to_process.emplace_back(&op, result); + } + } - // Saves users to be replaced *after* phi is constructed. - SmallVector uses_to_be_replaced; - for (OpOperand &use : live_in.getUses()) { - if (use.getOwner() != phi_op) { - uses_to_be_replaced.push_back(&use); + for (auto [op, result] : ops_to_process) { + builder.setInsertionPointAfter(op); + auto predicated = builder.create( + loc, result.getType(), result, cond); + for (OpOperand &use : llvm::make_early_inc_range(result.getUses())) { + if (use.getOwner() != predicated.getOperation()) { + // Replaces use with the predicated value. + use.set(predicated.getResult()); + } + } + } + } else { + llvm::errs() + << "[ctrl2data] Block has a single predecessor, but it's not a " + "cond_br: " + << *pred_term << "\n"; + llvm::errs() + << "[ctrl2data] Unsupported case, skipping phi node creation.\n"; + return; } - } - // Replaces live-in uses with the phi result. - for (OpOperand *use : uses_to_be_replaced) { - use->set(phi_op.getResult()); + } else { + llvm::errs() + << "[ctrl2data] Block has no block arguments and is not a single " + "predecessor block, skipping phi node creation.\n"; + llvm::errs() + << "[ctrl2data] Unsupported case, skipping phi node creation.\n"; + return; } } } namespace { -struct TransformCtrlToDataFlowPass +struct TransformCtrlToDataFlowPass : public PassWrapper> { MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TransformCtrlToDataFlowPass) - StringRef getArgument() const override { return "transform-ctrl-to-data-flow"; } + StringRef getArgument() const override { + return "transform-ctrl-to-data-flow"; + } StringRef getDescription() const override { - return "Transforms control flow into data flow using predicated execution"; + return "Transforms control flow into data flow using predicated " + "execution"; } void getDependentDialects(DialectRegistry ®istry) const override { @@ -308,13 +364,13 @@ struct TransformCtrlToDataFlowPass // Declares a vector to hold deferred backward ctrl move operations. // This is useful when a live-in value is defined within the same block. // The tuple contains: - // - real value (the one that is defined in the same block, after the placeholder) + // - real value (the one that is defined in the same block, after the + // placeholder) // - placeholder value (the one that will be used in the phi node) // - branch predicate (if any, for cond_br) // - block where the backward ctrl move should be inserted SmallVector, 4> deferred_ctrl_movs; module.walk([&](func::FuncOp func) { - OpBuilder builder(func.getContext()); GrantPredicateInEntryBlock(&func.getBody().front(), builder); @@ -326,7 +382,8 @@ struct TransformCtrlToDataFlowPass // Process blocks bottom-up for (Block *block : postOrder) { // Creates phi nodes for live-ins. - createPhiNodesForBlock(block, builder, deferred_ctrl_movs); + createPhiNodesForBlock(block, &func.getBody().front(), builder, + deferred_ctrl_movs); } // Flattens blocks into the entry block. @@ -346,7 +403,8 @@ struct TransformCtrlToDataFlowPass } } - // Moves all operations from blocks to the entry block before the terminator. + // Moves all operations from blocks to the entry block before the + // terminator. for (Block *block : blocks_to_flatten) { auto &ops = block->getOperations(); while (!ops.empty()) { @@ -369,23 +427,23 @@ struct TransformCtrlToDataFlowPass // Inserts the deferred backward ctrl move operations after phi operands // are defined. - for (auto &[real_dependent, placeholder, branch_pred, block] : deferred_ctrl_movs) { + for (auto &[real_dependent, placeholder, branch_pred, block] : + deferred_ctrl_movs) { Operation *def_op = real_dependent.getDefiningOp(); assert(def_op && "Backward ctrl move's source must be an op result"); - // Find the correct insertion point: after both real_dependent and branch_pred + // Finds the correct insertion point: after both real_dependent and + // branch_pred. Operation *insert_after = def_op; - if (Operation *pred_def = branch_pred.getDefiningOp()) { - if (insert_after->isBeforeInBlock(pred_def)) - insert_after = pred_def; - } - OpBuilder mov_builder(insert_after->getBlock(), ++Block::iterator(insert_after)); + OpBuilder mov_builder(insert_after->getBlock(), + ++Block::iterator(insert_after)); Location insert_loc = insert_after->getLoc(); Value guarded_val = real_dependent; - mov_builder.create(insert_loc, guarded_val, placeholder); + mov_builder.create(insert_loc, guarded_val, + placeholder); } } }; diff --git a/test/affine2neura/bert/bert_node0/bert_node0.mlir b/test/affine2neura/bert/bert_node0/bert_node0.mlir index ba82071e..9983fdb2 100644 --- a/test/affine2neura/bert/bert_node0/bert_node0.mlir +++ b/test/affine2neura/bert/bert_node0/bert_node0.mlir @@ -35,3 +35,6 @@ module attributes {} { // CHECK-NEXT: neura.br %12 : i64 to ^bb1 // CHECK-NEXT: ^bb3: // pred: ^bb1 // CHECK-NEXT: "neura.return"() : () -> () + + + diff --git a/test/affine2neura/bert/bert_node1/bert_node1.mlir b/test/affine2neura/bert/bert_node1/bert_node1.mlir index f79959a2..6c8cdb3c 100644 --- a/test/affine2neura/bert/bert_node1/bert_node1.mlir +++ b/test/affine2neura/bert/bert_node1/bert_node1.mlir @@ -1,5 +1,6 @@ // RUN: mlir-opt %s --lower-affine --convert-scf-to-cf --convert-cf-to-llvm -o %t-llvm.mlir // RUN: mlir-neura-opt %t-llvm.mlir --assign-accelerator --lower-arith-to-neura --lower-memref-to-neura --lower-builtin-to-neura --lower-llvm-to-neura | FileCheck %s +// RUN: mlir-neura-opt %t-llvm.mlir --assign-accelerator --lower-arith-to-neura --lower-memref-to-neura --lower-builtin-to-neura --lower-llvm-to-neura --leverage-predicated-value --transform-ctrl-to-data-flow | FileCheck %s -check-prefix=CTRL2DATA module attributes {} { func.func @_Z10bert_node1PA1_A1_A1_A1_A128_bPA1_A128_S1_(%arg0: memref, %arg1: memref) attributes {} { affine.for %arg2 = 0 to 128 { @@ -42,3 +43,41 @@ module attributes {} { // CHECK-NEXT: ^bb6: // pred: ^bb1 // CHECK-NEXT: "neura.return"() : () -> () // CHECK-NEXT: } + + +// CTRL2DATA: func.func @_Z10bert_node1PA1_A1_A1_A1_A128_bPA1_A128_S1_(%arg0: memref, %arg1: memref) attributes {accelerator = "neura"} { +// CTRL2DATA-NEXT: %0 = "neura.constant"() <{value = 1 : index}> : () -> !neura.data +// CTRL2DATA-NEXT: %1 = "neura.grant_always"(%0) : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %2 = "neura.constant"() <{value = 128 : index}> : () -> !neura.data +// CTRL2DATA-NEXT: %3 = "neura.grant_always"(%2) : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %4 = "neura.constant"() <{value = 0 : index}> : () -> !neura.data +// CTRL2DATA-NEXT: %5 = "neura.grant_always"(%4) : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %6 = "neura.cast"(%4) <{cast_type = "index_to_int"}> : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %7 = "neura.grant_once"(%6) : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %8 = neura.reserve : !neura.data +// CTRL2DATA-NEXT: %9 = "neura.phi"(%7, %8) : (!neura.data, !neura.data) -> !neura.data +// CTRL2DATA-NEXT: %10 = "neura.cast"(%9) <{cast_type = "int_to_index"}> : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %11 = "neura.icmp"(%10, %3) <{cmpType = "slt"}> : (!neura.data, !neura.data) -> !neura.data +// CTRL2DATA-NEXT: %12 = "neura.not"(%11) : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %13 = "neura.cast"(%5) <{cast_type = "index_to_int"}> : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %14 = neura.grant_predicate %13, %11 : !neura.data, !neura.data -> !neura.data +// CTRL2DATA-NEXT: %15 = neura.reserve : !neura.data +// CTRL2DATA-NEXT: %16 = "neura.phi"(%14, %15) : (!neura.data, !neura.data) -> !neura.data +// CTRL2DATA-NEXT: %17 = "neura.cast"(%16) <{cast_type = "int_to_index"}> : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %18 = "neura.icmp"(%17, %3) <{cmpType = "slt"}> : (!neura.data, !neura.data) -> !neura.data +// CTRL2DATA-NEXT: %19 = "neura.not"(%18) : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %20 = neura.load_indexed %arg0[%5, %5, %5, %5, %5, %17 : !neura.data, !neura.data, !neura.data, !neura.data, !neura.data, !neura.data] memref : !neura.data +// CTRL2DATA-NEXT: %21 = neura.grant_predicate %20, %18 : !neura.data, !neura.data -> !neura.data +// CTRL2DATA-NEXT: neura.store_indexed %21 to %arg1[%5, %5, %10, %5, %5, %17 : !neura.data, !neura.data, !neura.data, !neura.data, !neura.data, !neura.data] memref : !neura.data +// CTRL2DATA-NEXT: %22 = "neura.add"(%17, %1) : (!neura.data, !neura.data) -> !neura.data +// CTRL2DATA-NEXT: %23 = neura.grant_predicate %22, %18 : !neura.data, !neura.data -> !neura.data +// CTRL2DATA-NEXT: %24 = "neura.cast"(%23) <{cast_type = "index_to_int"}> : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %25 = neura.grant_predicate %24, %18 : !neura.data, !neura.data -> !neura.data +// CTRL2DATA-NEXT: neura.ctrl_mov %25 -> %15 : !neura.data !neura.data +// CTRL2DATA-NEXT: %26 = "neura.add"(%10, %1) : (!neura.data, !neura.data) -> !neura.data +// CTRL2DATA-NEXT: %27 = neura.grant_predicate %26, %19 : !neura.data, !neura.data -> !neura.data +// CTRL2DATA-NEXT: %28 = "neura.cast"(%27) <{cast_type = "index_to_int"}> : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %29 = neura.grant_predicate %28, %19 : !neura.data, !neura.data -> !neura.data +// CTRL2DATA-NEXT: neura.ctrl_mov %29 -> %8 : !neura.data !neura.data +// CTRL2DATA-NEXT: "neura.return"() : () -> () +// CTRL2DATA-NEXT: } \ No newline at end of file diff --git a/test/affine2neura/bert/bert_node28/bert_node28.mlir b/test/affine2neura/bert/bert_node28/bert_node28.mlir index e93de764..b97a85ce 100644 --- a/test/affine2neura/bert/bert_node28/bert_node28.mlir +++ b/test/affine2neura/bert/bert_node28/bert_node28.mlir @@ -1,5 +1,6 @@ // RUN: mlir-opt %s --lower-affine --convert-scf-to-cf --convert-cf-to-llvm -o %t-llvm.mlir // RUN: mlir-neura-opt %t-llvm.mlir --assign-accelerator --lower-arith-to-neura --lower-memref-to-neura --lower-builtin-to-neura --lower-llvm-to-neura | FileCheck %s +// RUN: mlir-neura-opt %t-llvm.mlir --assign-accelerator --lower-arith-to-neura --lower-memref-to-neura --lower-builtin-to-neura --lower-llvm-to-neura --leverage-predicated-value --transform-ctrl-to-data-flow | FileCheck %s -check-prefix=CTRL2DATA module attributes {} { func.func @_Z11bert_node28PA128_A768_KfPA768_S0_PA128_A768_f(%arg0: memref, %arg1: memref, %arg2: memref) attributes {} { affine.for %arg3 = 0 to 128 { @@ -62,3 +63,63 @@ module attributes {} { // CHECK-NEXT: neura.br %26 : i64 to ^bb1 // CHECK-NEXT: ^bb9: // pred: ^bb1 // CHECK-NEXT: "neura.return"() : () -> () + + +// CTRL2DATA: func.func @_Z11bert_node28PA128_A768_KfPA768_S0_PA128_A768_f(%arg0: memref, %arg1: memref, %arg2: memref) attributes {accelerator = "neura"} { +// CTRL2DATA-NEXT: %0 = "neura.constant"() <{value = 768 : index}> : () -> !neura.data +// CTRL2DATA-NEXT: %1 = "neura.grant_always"(%0) : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %2 = "neura.constant"() <{value = 1 : index}> : () -> !neura.data +// CTRL2DATA-NEXT: %3 = "neura.grant_always"(%2) : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %4 = "neura.constant"() <{value = 128 : index}> : () -> !neura.data +// CTRL2DATA-NEXT: %5 = "neura.grant_always"(%4) : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %6 = "neura.constant"() <{value = 0 : index}> : () -> !neura.data +// CTRL2DATA-NEXT: %7 = "neura.grant_always"(%6) : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %8 = "neura.cast"(%6) <{cast_type = "index_to_int"}> : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %9 = "neura.grant_once"(%8) : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %10 = neura.reserve : !neura.data +// CTRL2DATA-NEXT: %11 = "neura.phi"(%9, %10) : (!neura.data, !neura.data) -> !neura.data +// CTRL2DATA-NEXT: %12 = "neura.cast"(%11) <{cast_type = "int_to_index"}> : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %13 = "neura.icmp"(%12, %5) <{cmpType = "slt"}> : (!neura.data, !neura.data) -> !neura.data +// CTRL2DATA-NEXT: %14 = "neura.not"(%13) : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %15 = "neura.cast"(%7) <{cast_type = "index_to_int"}> : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %16 = neura.grant_predicate %15, %13 : !neura.data, !neura.data -> !neura.data +// CTRL2DATA-NEXT: %17 = neura.reserve : !neura.data +// CTRL2DATA-NEXT: %18 = "neura.phi"(%16, %17) : (!neura.data, !neura.data) -> !neura.data +// CTRL2DATA-NEXT: %19 = "neura.cast"(%18) <{cast_type = "int_to_index"}> : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %20 = "neura.icmp"(%19, %1) <{cmpType = "slt"}> : (!neura.data, !neura.data) -> !neura.data +// CTRL2DATA-NEXT: %21 = "neura.not"(%20) : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %22 = "neura.cast"(%7) <{cast_type = "index_to_int"}> : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %23 = neura.grant_predicate %22, %20 : !neura.data, !neura.data -> !neura.data +// CTRL2DATA-NEXT: %24 = neura.reserve : !neura.data +// CTRL2DATA-NEXT: %25 = "neura.phi"(%23, %24) : (!neura.data, !neura.data) -> !neura.data +// CTRL2DATA-NEXT: %26 = "neura.cast"(%25) <{cast_type = "int_to_index"}> : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %27 = "neura.icmp"(%26, %1) <{cmpType = "slt"}> : (!neura.data, !neura.data) -> !neura.data +// CTRL2DATA-NEXT: %28 = "neura.not"(%27) : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %29 = neura.load_indexed %arg0[%7, %12, %26 : !neura.data, !neura.data, !neura.data] memref : !neura.data +// CTRL2DATA-NEXT: %30 = neura.grant_predicate %29, %27 : !neura.data, !neura.data -> !neura.data +// CTRL2DATA-NEXT: %31 = neura.load_indexed %arg1[%7, %26, %19 : !neura.data, !neura.data, !neura.data] memref : !neura.data +// CTRL2DATA-NEXT: %32 = neura.grant_predicate %31, %27 : !neura.data, !neura.data -> !neura.data +// CTRL2DATA-NEXT: %33 = neura.load_indexed %arg2[%7, %12, %19 : !neura.data, !neura.data, !neura.data] memref : !neura.data +// CTRL2DATA-NEXT: %34 = neura.grant_predicate %33, %27 : !neura.data, !neura.data -> !neura.data +// CTRL2DATA-NEXT: %35 = "neura.fmul"(%30, %32) : (!neura.data, !neura.data) -> !neura.data +// CTRL2DATA-NEXT: %36 = neura.grant_predicate %35, %27 : !neura.data, !neura.data -> !neura.data +// CTRL2DATA-NEXT: %37 = "neura.fadd"(%34, %36) : (!neura.data, !neura.data) -> !neura.data +// CTRL2DATA-NEXT: %38 = neura.grant_predicate %37, %27 : !neura.data, !neura.data -> !neura.data +// CTRL2DATA-NEXT: neura.store_indexed %38 to %arg2[%7, %12, %19 : !neura.data, !neura.data, !neura.data] memref : !neura.data +// CTRL2DATA-NEXT: %39 = "neura.add"(%26, %3) : (!neura.data, !neura.data) -> !neura.data +// CTRL2DATA-NEXT: %40 = neura.grant_predicate %39, %27 : !neura.data, !neura.data -> !neura.data +// CTRL2DATA-NEXT: %41 = "neura.cast"(%40) <{cast_type = "index_to_int"}> : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %42 = neura.grant_predicate %41, %27 : !neura.data, !neura.data -> !neura.data +// CTRL2DATA-NEXT: neura.ctrl_mov %42 -> %24 : !neura.data !neura.data +// CTRL2DATA-NEXT: %43 = "neura.add"(%19, %3) : (!neura.data, !neura.data) -> !neura.data +// CTRL2DATA-NEXT: %44 = neura.grant_predicate %43, %28 : !neura.data, !neura.data -> !neura.data +// CTRL2DATA-NEXT: %45 = "neura.cast"(%44) <{cast_type = "index_to_int"}> : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %46 = neura.grant_predicate %45, %28 : !neura.data, !neura.data -> !neura.data +// CTRL2DATA-NEXT: neura.ctrl_mov %46 -> %17 : !neura.data !neura.data +// CTRL2DATA-NEXT: %47 = "neura.add"(%12, %3) : (!neura.data, !neura.data) -> !neura.data +// CTRL2DATA-NEXT: %48 = neura.grant_predicate %47, %21 : !neura.data, !neura.data -> !neura.data +// CTRL2DATA-NEXT: %49 = "neura.cast"(%48) <{cast_type = "index_to_int"}> : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %50 = neura.grant_predicate %49, %21 : !neura.data, !neura.data -> !neura.data +// CTRL2DATA-NEXT: neura.ctrl_mov %50 -> %10 : !neura.data !neura.data +// CTRL2DATA-NEXT: "neura.return"() : () -> () +// CTRL2DATA-NEXT: } diff --git a/test/neura/ctrl/branch_with_and_without_arg.mlir b/test/neura/ctrl/branch_with_and_without_arg.mlir index 04bc1751..08745ed7 100644 --- a/test/neura/ctrl/branch_with_and_without_arg.mlir +++ b/test/neura/ctrl/branch_with_and_without_arg.mlir @@ -49,24 +49,23 @@ func.func @test(%in: i64) -> f32 { // CHECK-NEXT: } // CTRL2DATA: func.func @test(%arg0: i64) -> f32 attributes {accelerator = "neura"} { -// CTRL2DATA-NEXT: %0 = "neura.constant"() <{predicate = true, value = 0 : i64}> : () -> !neura.data -// CTRL2DATA-NEXT: %1 = "neura.constant"() <{predicate = true, value = 1.000000e+00 : f32}> : () -> !neura.data -// CTRL2DATA-NEXT: %2 = "neura.grant_once"(%1) : (!neura.data) -> !neura.data -// CTRL2DATA-NEXT: %3 = "neura.constant"() <{predicate = true, value = 2.000000e+00 : f32}> : () -> !neura.data -// CTRL2DATA-NEXT: %4 = "neura.grant_always"(%3) : (!neura.data) -> !neura.data -// CTRL2DATA-NEXT: %5 = "neura.grant_once"(%3) : (!neura.data) -> !neura.data -// CTRL2DATA-NEXT: %6 = "neura.constant"() <{predicate = true, value = 3.000000e+00 : f32}> : () -> !neura.data -// CTRL2DATA-NEXT: %7 = "neura.grant_once"(%6) : (!neura.data) -> !neura.data -// CTRL2DATA-NEXT: %8 = "neura.icmp"(%arg0, %0) <{cmpType = "eq"}> : (i64, !neura.data) -> !neura.data -// CTRL2DATA-NEXT: %9 = "neura.grant_once"(%8) : (!neura.data) -> !neura.data -// CTRL2DATA-NEXT: %10 = neura.grant_predicate %7, %9 : !neura.data, !neura.data -> !neura.data -// CTRL2DATA-NEXT: %11 = neura.grant_predicate %4, %9 : !neura.data, !neura.data -> !neura.data -// CTRL2DATA-NEXT: %12 = "neura.not"(%9) : (!neura.data) -> !neura.data -// CTRL2DATA-NEXT: %13 = neura.grant_predicate %2, %12 : !neura.data, !neura.data -> !neura.data -// CTRL2DATA-NEXT: %14 = "neura.not"(%9) : (!neura.data) -> !neura.data -// CTRL2DATA-NEXT: %15 = neura.grant_predicate %5, %14 : !neura.data, !neura.data -> !neura.data -// CTRL2DATA-NEXT: %16 = "neura.fadd"(%13, %15) : (!neura.data, !neura.data) -> !neura.data -// CTRL2DATA-NEXT: %17 = "neura.fmul"(%10, %11) : (!neura.data, !neura.data) -> !neura.data -// CTRL2DATA-NEXT: %18 = "neura.phi"(%16, %17) : (!neura.data, !neura.data) -> !neura.data -// CTRL2DATA-NEXT: "neura.return"(%18) : (!neura.data) -> () -// CTRL2DATA-NEXT: } +// CTRL2DATA-NEXT: %0 = "neura.constant"() <{predicate = true, value = 0 : i64}> : () -> !neura.data +// CTRL2DATA-NEXT: %1 = "neura.constant"() <{predicate = true, value = 1.000000e+00 : f32}> : () -> !neura.data +// CTRL2DATA-NEXT: %2 = "neura.grant_once"(%1) : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %3 = "neura.constant"() <{predicate = true, value = 2.000000e+00 : f32}> : () -> !neura.data +// CTRL2DATA-NEXT: %4 = "neura.grant_always"(%3) : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %5 = "neura.grant_once"(%3) : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %6 = "neura.constant"() <{predicate = true, value = 3.000000e+00 : f32}> : () -> !neura.data +// CTRL2DATA-NEXT: %7 = "neura.grant_once"(%6) : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %8 = "neura.icmp"(%arg0, %0) <{cmpType = "eq"}> : (i64, !neura.data) -> !neura.data +// CTRL2DATA-NEXT: %9 = "neura.grant_once"(%8) : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %10 = neura.grant_predicate %7, %9 : !neura.data, !neura.data -> !neura.data +// CTRL2DATA-NEXT: %11 = "neura.not"(%9) : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %12 = neura.grant_predicate %2, %11 : !neura.data, !neura.data -> !neura.data +// CTRL2DATA-NEXT: %13 = "neura.not"(%9) : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %14 = neura.grant_predicate %5, %13 : !neura.data, !neura.data -> !neura.data +// CTRL2DATA-NEXT: %15 = "neura.fadd"(%12, %14) : (!neura.data, !neura.data) -> !neura.data +// CTRL2DATA-NEXT: %16 = "neura.fmul"(%10, %4) : (!neura.data, !neura.data) -> !neura.data +// CTRL2DATA-NEXT: %17 = "neura.phi"(%15, %16) : (!neura.data, !neura.data) -> !neura.data +// CTRL2DATA-NEXT: "neura.return"(%17) : (!neura.data) -> () +// CTRL2DATA-NEXT: } \ No newline at end of file diff --git a/test/neura/ctrl/branch_without_arg.mlir b/test/neura/ctrl/branch_without_arg.mlir index 131753d4..9c30056a 100644 --- a/test/neura/ctrl/branch_without_arg.mlir +++ b/test/neura/ctrl/branch_without_arg.mlir @@ -51,25 +51,23 @@ func.func @test(%in: i64) -> f32 { // CHECK-NEXT: } // CTRL2DATA: func.func @test(%arg0: i64) -> f32 attributes {accelerator = "neura"} { -// CTRL2DATA-NEXT: %0 = "neura.constant"() <{predicate = true, value = 0 : i64}> : () -> !neura.data -// CTRL2DATA-NEXT: %1 = "neura.constant"() <{predicate = true, value = 1.000000e+00 : f32}> : () -> !neura.data -// CTRL2DATA-NEXT: %2 = "neura.grant_always"(%1) : (!neura.data) -> !neura.data -// CTRL2DATA-NEXT: %3 = "neura.constant"() <{predicate = true, value = 2.000000e+00 : f32}> : () -> !neura.data -// CTRL2DATA-NEXT: %4 = "neura.grant_always"(%3) : (!neura.data) -> !neura.data -// CTRL2DATA-NEXT: %5 = "neura.constant"() <{predicate = true, value = 3.000000e+00 : f32}> : () -> !neura.data -// CTRL2DATA-NEXT: %6 = "neura.grant_once"(%5) : (!neura.data) -> !neura.data -// CTRL2DATA-NEXT: %7 = "neura.constant"() <{predicate = true, value = 4.000000e+00 : f32}> : () -> !neura.data -// CTRL2DATA-NEXT: %8 = "neura.grant_once"(%7) : (!neura.data) -> !neura.data -// CTRL2DATA-NEXT: %9 = "neura.icmp"(%arg0, %0) <{cmpType = "eq"}> : (i64, !neura.data) -> !neura.data -// CTRL2DATA-NEXT: %10 = "neura.grant_once"(%9) : (!neura.data) -> !neura.data -// CTRL2DATA-NEXT: %11 = neura.grant_predicate %6, %10 : !neura.data, !neura.data -> !neura.data -// CTRL2DATA-NEXT: %12 = neura.grant_predicate %8, %10 : !neura.data, !neura.data -> !neura.data -// CTRL2DATA-NEXT: %13 = "neura.not"(%10) : (!neura.data) -> !neura.data -// CTRL2DATA-NEXT: %14 = neura.grant_predicate %2, %13 : !neura.data, !neura.data -> !neura.data -// CTRL2DATA-NEXT: %15 = "neura.not"(%10) : (!neura.data) -> !neura.data -// CTRL2DATA-NEXT: %16 = neura.grant_predicate %4, %15 : !neura.data, !neura.data -> !neura.data -// CTRL2DATA-NEXT: %17 = "neura.fadd"(%14, %16) : (!neura.data, !neura.data) -> !neura.data -// CTRL2DATA-NEXT: %18 = "neura.fmul"(%11, %12) : (!neura.data, !neura.data) -> !neura.data -// CTRL2DATA-NEXT: %19 = "neura.phi"(%17, %18) : (!neura.data, !neura.data) -> !neura.data -// CTRL2DATA-NEXT: "neura.return"(%19) : (!neura.data) -> () -// CTRL2DATA-NEXT: } +// CTRL2DATA-NEXT: %0 = "neura.constant"() <{predicate = true, value = 0 : i64}> : () -> !neura.data +// CTRL2DATA-NEXT: %1 = "neura.constant"() <{predicate = true, value = 1.000000e+00 : f32}> : () -> !neura.data +// CTRL2DATA-NEXT: %2 = "neura.grant_always"(%1) : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %3 = "neura.constant"() <{predicate = true, value = 2.000000e+00 : f32}> : () -> !neura.data +// CTRL2DATA-NEXT: %4 = "neura.grant_always"(%3) : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %5 = "neura.constant"() <{predicate = true, value = 3.000000e+00 : f32}> : () -> !neura.data +// CTRL2DATA-NEXT: %6 = "neura.grant_once"(%5) : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %7 = "neura.constant"() <{predicate = true, value = 4.000000e+00 : f32}> : () -> !neura.data +// CTRL2DATA-NEXT: %8 = "neura.grant_once"(%7) : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %9 = "neura.icmp"(%arg0, %0) <{cmpType = "eq"}> : (i64, !neura.data) -> !neura.data +// CTRL2DATA-NEXT: %10 = "neura.grant_once"(%9) : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %11 = neura.grant_predicate %6, %10 : !neura.data, !neura.data -> !neura.data +// CTRL2DATA-NEXT: %12 = neura.grant_predicate %8, %10 : !neura.data, !neura.data -> !neura.data +// CTRL2DATA-NEXT: %13 = "neura.not"(%10) : (!neura.data) -> !neura.data +// CTRL2DATA-NEXT: %14 = "neura.fadd"(%2, %4) : (!neura.data, !neura.data) -> !neura.data +// CTRL2DATA-NEXT: %15 = neura.grant_predicate %14, %13 : !neura.data, !neura.data -> !neura.data +// CTRL2DATA-NEXT: %16 = "neura.fmul"(%11, %12) : (!neura.data, !neura.data) -> !neura.data +// CTRL2DATA-NEXT: %17 = "neura.phi"(%15, %16) : (!neura.data, !neura.data) -> !neura.data +// CTRL2DATA-NEXT: "neura.return"(%17) : (!neura.data) -> () +// CTRL2DATA-NEXT: } \ No newline at end of file