diff --git a/lib/NeuraDialect/Transforms/MapToAcceleratorPass.cpp b/lib/NeuraDialect/Transforms/MapToAcceleratorPass.cpp index 7e11d696..6f8f65e6 100644 --- a/lib/NeuraDialect/Transforms/MapToAcceleratorPass.cpp +++ b/lib/NeuraDialect/Transforms/MapToAcceleratorPass.cpp @@ -40,6 +40,11 @@ struct MapToAcceleratorPass MapToAcceleratorPass() = default; MapToAcceleratorPass(const MapToAcceleratorPass &pass) : PassWrapper>(pass) {} + Option sortStrategy{ + *this, "sort-strategy", + llvm::cl::desc("Strategy for sorting operations before mapping. " + "Options: topological, mixed (default)."), + llvm::cl::init("mixed")}; Option mappingStrategy{ *this, "mapping-strategy", llvm::cl::desc("Mapping strategy to use for mapping operations to the " @@ -63,46 +68,47 @@ struct MapToAcceleratorPass void runOnOperation() override { ModuleOp module = getOperation(); std::unique_ptr mapping_strategy; - StringRef mapping_strategy_stringRef(mappingStrategy.getValue()); - StringRef backtrack_config_stringRef(backtrackConfig.getValue()); - StringRef mapping_mode_stringRef(mappingMode.getValue()); - bool is_spatial_only = (mapping_mode_stringRef == "spatial-only"); - if (is_spatial_only || mapping_mode_stringRef == "spatial-temporal" || - mapping_mode_stringRef.empty()) { - if (mapping_mode_stringRef.empty()) { - mapping_mode_stringRef = "spatial-temporal"; + StringRef mapping_strategy_string_ref(mappingStrategy.getValue()); + StringRef backtrack_config_string_ref(backtrackConfig.getValue()); + StringRef mapping_mode_string_ref(mappingMode.getValue()); + StringRef sort_strategy_string_ref(sortStrategy.getValue()); + bool is_spatial_only = (mapping_mode_string_ref == "spatial-only"); + if (is_spatial_only || mapping_mode_string_ref == "spatial-temporal" || + mapping_mode_string_ref.empty()) { + if (mapping_mode_string_ref.empty()) { + mapping_mode_string_ref = "spatial-temporal"; } llvm::errs() << "[MapToAcceleratorPass] Using Mapping Mode: " - << mapping_mode_stringRef << "\n"; + << mapping_mode_string_ref << "\n"; } else { llvm::errs() << "[MapToAcceleratorPass] Unsupported mapping mode: " - << mapping_mode_stringRef << "\n"; + << mapping_mode_string_ref << "\n"; return; } - if (mapping_strategy_stringRef == "heuristic" || - mapping_strategy_stringRef.empty()) { - mapping_strategy_stringRef = "heuristic"; + if (mapping_strategy_string_ref == "heuristic" || + mapping_strategy_string_ref.empty()) { + mapping_strategy_string_ref = "heuristic"; - if (backtrack_config_stringRef == "simple") { + if (backtrack_config_string_ref == "simple") { mapping_strategy = std::make_unique(1, 1); - } else if (backtrack_config_stringRef == "greedy") { + } else if (backtrack_config_string_ref == "greedy") { mapping_strategy = std::make_unique(INT_MAX, 1); - } else if (backtrack_config_stringRef == "exhaustive") { + } else if (backtrack_config_string_ref == "exhaustive") { mapping_strategy = std::make_unique(INT_MAX, INT_MAX); - } else if (backtrack_config_stringRef == "customized") { + } else if (backtrack_config_string_ref == "customized") { mapping_strategy = std::make_unique(5, 3); - } else if (backtrack_config_stringRef.starts_with("customized=")) { + } else if (backtrack_config_string_ref.starts_with("customized=")) { // Used for custom backtrack parameters. // Example: "customized=5,3" means max_loc=5, max_depth=3 // Extracts the parameters after "customized=". - StringRef paramsRef = - backtrack_config_stringRef.substr(strlen("customized=")); - size_t comma_pos = paramsRef.find(','); + StringRef params_ref = + backtrack_config_string_ref.substr(strlen("customized=")); + size_t comma_pos = params_ref.find(','); if (comma_pos != StringRef::npos) { - StringRef max_loc_str = paramsRef.substr(0, comma_pos); - StringRef max_depth_str = paramsRef.substr(comma_pos + 1); + StringRef max_loc_str = params_ref.substr(0, comma_pos); + StringRef max_depth_str = params_ref.substr(comma_pos + 1); int max_loc, max_depth; if (!max_loc_str.getAsInteger(10, max_loc) && @@ -116,19 +122,19 @@ struct MapToAcceleratorPass } else { llvm::errs() << "[MapToAcceleratorPass] Illegal customized " "parameters format: " - << backtrack_config_stringRef << "\n"; + << backtrack_config_string_ref << "\n"; return; } } else { llvm::errs() << "[MapToAcceleratorPass] Illegal customized parameters format: " - << backtrack_config_stringRef << "\n"; + << backtrack_config_string_ref << "\n"; return; } } } else { llvm::errs() << "[MapToAcceleratorPass] Unsupported mapping strategy: " - << mapping_strategy_stringRef << "\n"; + << mapping_strategy_string_ref << "\n"; return; } @@ -147,10 +153,10 @@ struct MapToAcceleratorPass // If steering mode, enforce spatial-only mapping. if (is_steering_mode) { - if (mapping_mode_stringRef != "spatial-only") { + if (mapping_mode_string_ref != "spatial-only") { func.emitError() << "Steering IR mode requires spatial-only mapping, " << "but got mapping mode: " - << mapping_mode_stringRef; + << mapping_mode_string_ref; signalPassFailure(); return; } @@ -206,30 +212,41 @@ struct MapToAcceleratorPass llvm::outs() << "[MapToAcceleratorPass] Topologically sorted op: " << *op << "\n"; } - std::vector> level_buckets = - getOpsInAlapLevels(topologically_sorted_ops, critical_ops); - for (int level = 0; level < static_cast(level_buckets.size()); - ++level) { - llvm::outs() << "[MapToAcceleratorPass] ALAP Bucket Level " << level - << ": " << level_buckets[level].size() << " ops\n"; - for (Operation *op : level_buckets[level]) { - llvm::outs() << " " << *op << "\n"; + + // Two sorting strategies: pure topological order, or mixed ALAP + topo. + std::vector> sorted_ops_with_levels; + if (sort_strategy_string_ref == "topological") { + for (Operation *op : topologically_sorted_ops) { + sorted_ops_with_levels.push_back({op, 0}); // Level 0 for all ops } + } else if (sort_strategy_string_ref == "mixed") { + std::vector> level_buckets = + getOpsInAlapLevels(topologically_sorted_ops, critical_ops); + for (int level = 0; level < static_cast(level_buckets.size()); + ++level) { + llvm::outs() << "[MapToAcceleratorPass] ALAP Bucket Level " << level + << ": " << level_buckets[level].size() << " ops\n"; + for (Operation *op : level_buckets[level]) { + llvm::outs() << " " << *op << "\n"; + } + } + sorted_ops_with_levels = flatten_level_buckets(level_buckets); + for (const auto &[op, level] : sorted_ops_with_levels) { + llvm::outs() << "[MapToAcceleratorPass] ALAP sorted op: " << *op + << " (ALAP level: " << level << ")\n"; + } + } else { + llvm::errs() << "[MapToAcceleratorPass] Unsupported sort strategy: " + << sort_strategy_string_ref << "\n"; + return; } - std::vector> sorted_ops_with_alap_levels = - flatten_level_buckets(level_buckets); - for (const auto &[op, level] : sorted_ops_with_alap_levels) { - llvm::outs() << "[MapToAcceleratorPass] ALAP sorted op: " << *op - << " (ALAP level: " << level << ")\n"; - } - // assert(false); for (int ii = possibleMinII; ii <= maxII; ++ii) { llvm::errs() << "[MapToAcceleratorPass] Start mapping with target II of " << ii << "\n"; // Creates a mapping state for the current II. MappingState mapping_state(architecture, ii, is_spatial_only); - if (mapping_strategy->map(sorted_ops_with_alap_levels, critical_ops, + if (mapping_strategy->map(sorted_ops_with_levels, critical_ops, architecture, mapping_state)) { // success llvm::errs() << "[MapToAcceleratorPass] Successfully mapped function " @@ -247,10 +264,11 @@ struct MapToAcceleratorPass NamedAttribute(StringAttr::get(ctx, "y_tiles"), IntegerAttr::get(IntegerType::get(ctx, 32), architecture.getHeight())), - NamedAttribute(StringAttr::get(ctx, "mapping_strategy"), - StringAttr::get(ctx, mapping_strategy_stringRef)), + NamedAttribute( + StringAttr::get(ctx, "mapping_strategy"), + StringAttr::get(ctx, mapping_strategy_string_ref)), NamedAttribute(StringAttr::get(ctx, "mapping_mode"), - StringAttr::get(ctx, mapping_mode_stringRef)), + StringAttr::get(ctx, mapping_mode_string_ref)), NamedAttribute(StringAttr::get(ctx, "compiled_ii"), IntegerAttr::get(IntegerType::get(ctx, 32), ii)), NamedAttribute( diff --git a/test/neura/steer_ctrl/loop_with_return_value.mlir b/test/neura/steer_ctrl/loop_with_return_value.mlir index f191a43b..903e6987 100644 --- a/test/neura/steer_ctrl/loop_with_return_value.mlir +++ b/test/neura/steer_ctrl/loop_with_return_value.mlir @@ -25,9 +25,9 @@ // RUN: --transform-ctrl-to-data-flow \ // RUN: --transform-to-steer-control \ // RUN: --remove-predicated-type \ -// RUN: --insert-data-mov -// RU: --map-to-accelerator="mapping-strategy=heuristic mapping-mode=spatial-only backtrack-config=customized" -// RU: | FileCheck %s -check-prefix=MAPPING +// RUN: --insert-data-mov \ +// RUN: --map-to-accelerator="mapping-strategy=heuristic mapping-mode=spatial-only backtrack-config=customized sort-strategy=topological" \ +// RUN: | FileCheck %s -check-prefix=MAPPING module { func.func @simple_add_loop() -> i64 { @@ -66,36 +66,36 @@ module { // CHECK-NEXT: "neura.return"(%12) : (i64) -> () // CHECK-NEXT: } -// MAPPING: func.func @simple_add_loop() -> i64 attributes {accelerator = "neura", dataflow_mode = "steering", mapping_info = {compiled_ii = 4 : i32, mapping_mode = "spatial-only", mapping_strategy = "heuristic", rec_mii = 2 : i32, res_mii = 1 : i32, x_tiles = 4 : i32, y_tiles = 4 : i32}} { +// MAPPING: func.func @simple_add_loop() -> i64 attributes {accelerator = "neura", dataflow_mode = "steering", mapping_info = {compiled_ii = 5 : i32, mapping_mode = "spatial-only", mapping_strategy = "heuristic", rec_mii = 2 : i32, res_mii = 1 : i32, x_tiles = 4 : i32, y_tiles = 4 : i32}} { // MAPPING-NEXT: %0 = neura.reserve : i64 // MAPPING-NEXT: %1 = neura.reserve : i64 // MAPPING-NEXT: %2 = neura.reserve : i1 -// MAPPING-NEXT: %3 = "neura.constant"() <{value = 16 : i64}> {mapping_locs = [{id = 0 : i32, resource = "tile", time_step = 0 : i32, x = 0 : i32, y = 0 : i32}]} : () -> i64 -// MAPPING-NEXT: %4 = "neura.constant"() <{value = 1 : i64}> {mapping_locs = [{id = 11 : i32, resource = "tile", time_step = 1 : i32, x = 3 : i32, y = 2 : i32}]} : () -> i64 -// MAPPING-NEXT: %5 = "neura.constant"() <{value = 1 : i64}> {mapping_locs = [{id = 5 : i32, resource = "tile", time_step = 1 : i32, x = 1 : i32, y = 1 : i32}]} : () -> i64 -// MAPPING-NEXT: %6 = "neura.constant"() <{value = 0 : i64}> {mapping_locs = [{id = 13 : i32, resource = "tile", time_step = 0 : i32, x = 1 : i32, y = 3 : i32}]} : () -> i64 -// MAPPING-NEXT: %7 = "neura.data_mov"(%4) {mapping_locs = [{id = 35 : i32, resource = "link", time_step = 1 : i32}]} : (i64) -> i64 -// MAPPING-NEXT: %8 = neura.invariant %7, %2 {mapping_locs = [{id = 10 : i32, resource = "tile", time_step = 2 : i32, x = 2 : i32, y = 2 : i32}]} : i64, i1 -> i64 -// MAPPING-NEXT: %9 = "neura.data_mov"(%3) {mapping_locs = [{id = 0 : i32, resource = "link", time_step = 0 : i32}]} : (i64) -> i64 -// MAPPING-NEXT: %10 = neura.invariant %9, %2 {mapping_locs = [{id = 1 : i32, resource = "tile", time_step = 1 : i32, x = 1 : i32, y = 0 : i32}]} : i64, i1 -> i64 -// MAPPING-NEXT: %11 = "neura.data_mov"(%5) {mapping_locs = [{id = 14 : i32, resource = "link", time_step = 1 : i32}]} : (i64) -> i64 -// MAPPING-NEXT: %12 = neura.carry %11, %2, %0 {mapping_locs = [{id = 6 : i32, resource = "tile", time_step = 2 : i32, x = 2 : i32, y = 1 : i32}]} : i64, i1, i64 -> i64 -// MAPPING-NEXT: %13 = "neura.data_mov"(%6) {mapping_locs = [{id = 42 : i32, resource = "link", time_step = 0 : i32}]} : (i64) -> i64 -// MAPPING-NEXT: %14 = neura.carry %13, %2, %1 {mapping_locs = [{id = 9 : i32, resource = "tile", time_step = 1 : i32, x = 1 : i32, y = 2 : i32}]} : i64, i1, i64 -> i64 -// MAPPING-NEXT: %15 = "neura.data_mov"(%14) {mapping_locs = [{id = 27 : i32, resource = "link", time_step = 1 : i32}, {id = 25 : i32, resource = "link", time_step = 2 : i32}]} : (i64) -> i64 -// MAPPING-NEXT: %16 = "neura.data_mov"(%10) {mapping_locs = [{id = 2 : i32, resource = "link", time_step = 1 : i32}, {id = 1 : i32, resource = "link", time_step = 2 : i32}]} : (i64) -> i64 -// MAPPING-NEXT: %17 = "neura.icmp"(%15, %16) <{cmpType = "slt"}> {mapping_locs = [{id = 4 : i32, resource = "tile", time_step = 3 : i32, x = 0 : i32, y = 1 : i32}]} : (i64, i64) -> i1 -// MAPPING-NEXT: neura.ctrl_mov %17 -> %2 {mapping_locs = [{id = 10 : i32, resource = "link", time_step = 3 : i32}, {id = 16 : i32, resource = "link", time_step = 4 : i32}, {id = 28 : i32, resource = "link", time_step = 5 : i32}]} : i1 i1 -// MAPPING-NEXT: %18 = "neura.data_mov"(%17) {mapping_locs = [{id = 12 : i32, resource = "link", time_step = 3 : i32}]} : (i1) -> i1 -// MAPPING-NEXT: %19 = "neura.not"(%18) {mapping_locs = [{id = 8 : i32, resource = "tile", time_step = 4 : i32, x = 0 : i32, y = 2 : i32}]} : (i1) -> i1 -// MAPPING-NEXT: %20 = "neura.data_mov"(%12) {mapping_locs = [{id = 19 : i32, resource = "link", time_step = 2 : i32}, {id = 64 : i32, resource = "register", time_step = 3 : i32}, {id = 64 : i32, resource = "register", time_step = 4 : i32}]} : (i64) -> i64 -// MAPPING-NEXT: %21 = "neura.data_mov"(%12) {mapping_locs = [{id = 17 : i32, resource = "link", time_step = 2 : i32}, {id = 15 : i32, resource = "link", time_step = 3 : i32}, {id = 3 : i32, resource = "link", time_step = 4 : i32}]} : (i64) -> i64 -// MAPPING-NEXT: %22 = "neura.add"(%20, %21) {mapping_locs = [{id = 2 : i32, resource = "tile", time_step = 5 : i32, x = 2 : i32, y = 0 : i32}]} : (i64, i64) -> i64 -// MAPPING-NEXT: neura.ctrl_mov %22 -> %0 {mapping_locs = [{id = 7 : i32, resource = "link", time_step = 5 : i32}]} : i64 i64 -// MAPPING-NEXT: %23 = "neura.data_mov"(%14) {mapping_locs = [{id = 30 : i32, resource = "link", time_step = 1 : i32}, {id = 41 : i32, resource = "link", time_step = 2 : i32}]} : (i64) -> i64 -// MAPPING-NEXT: %24 = "neura.data_mov"(%8) {mapping_locs = [{id = 34 : i32, resource = "link", time_step = 2 : i32}]} : (i64) -> i64 -// MAPPING-NEXT: %25 = "neura.add"(%23, %24) {mapping_locs = [{id = 14 : i32, resource = "tile", time_step = 3 : i32, x = 2 : i32, y = 3 : i32}]} : (i64, i64) -> i64 -// MAPPING-NEXT: neura.ctrl_mov %25 -> %1 {mapping_locs = [{id = 45 : i32, resource = "link", time_step = 3 : i32}, {id = 31 : i32, resource = "link", time_step = 4 : i32}]} : i64 i64 -// MAPPING-NEXT: %26 = "neura.data_mov"(%12) {mapping_locs = [{id = 18 : i32, resource = "link", time_step = 2 : i32}]} : (i64) -> i64 -// MAPPING-NEXT: "neura.return"(%26) {mapping_locs = [{id = 7 : i32, resource = "tile", time_step = 3 : i32, x = 3 : i32, y = 1 : i32}]} : (i64) -> () -// MAPPING-NEXT: } \ No newline at end of file +// MAPPING-NEXT: %3 = "neura.constant"() <{value = 16 : i64}> {mapping_locs = [{id = 11 : i32, resource = "tile", time_step = 0 : i32, x = 3 : i32, y = 2 : i32}]} : () -> i64 +// MAPPING-NEXT: %4 = "neura.constant"() <{value = 1 : i64}> {mapping_locs = [{id = 12 : i32, resource = "tile", time_step = 0 : i32, x = 0 : i32, y = 3 : i32}]} : () -> i64 +// MAPPING-NEXT: %5 = "neura.constant"() <{value = 1 : i64}> {mapping_locs = [{id = 0 : i32, resource = "tile", time_step = 0 : i32, x = 0 : i32, y = 0 : i32}]} : () -> i64 +// MAPPING-NEXT: %6 = "neura.constant"() <{value = 0 : i64}> {mapping_locs = [{id = 14 : i32, resource = "tile", time_step = 0 : i32, x = 2 : i32, y = 3 : i32}]} : () -> i64 +// MAPPING-NEXT: %7 = "neura.data_mov"(%4) {mapping_locs = [{id = 38 : i32, resource = "link", time_step = 0 : i32}]} : (i64) -> i64 +// MAPPING-NEXT: %8 = neura.invariant %7, %2 {mapping_locs = [{id = 13 : i32, resource = "tile", time_step = 1 : i32, x = 1 : i32, y = 3 : i32}]} : i64, i1 -> i64 +// MAPPING-NEXT: %9 = "neura.data_mov"(%3) {mapping_locs = [{id = 35 : i32, resource = "link", time_step = 0 : i32}]} : (i64) -> i64 +// MAPPING-NEXT: %10 = neura.invariant %9, %2 {mapping_locs = [{id = 10 : i32, resource = "tile", time_step = 1 : i32, x = 2 : i32, y = 2 : i32}]} : i64, i1 -> i64 +// MAPPING-NEXT: %11 = "neura.data_mov"(%5) {mapping_locs = [{id = 0 : i32, resource = "link", time_step = 0 : i32}]} : (i64) -> i64 +// MAPPING-NEXT: %12 = neura.carry %11, %2, %0 {mapping_locs = [{id = 1 : i32, resource = "tile", time_step = 1 : i32, x = 1 : i32, y = 0 : i32}]} : i64, i1, i64 -> i64 +// MAPPING-NEXT: %13 = "neura.data_mov"(%6) {mapping_locs = [{id = 45 : i32, resource = "link", time_step = 0 : i32}, {id = 33 : i32, resource = "link", time_step = 1 : i32}]} : (i64) -> i64 +// MAPPING-NEXT: %14 = neura.carry %13, %2, %1 {mapping_locs = [{id = 6 : i32, resource = "tile", time_step = 2 : i32, x = 2 : i32, y = 1 : i32}]} : i64, i1, i64 -> i64 +// MAPPING-NEXT: %15 = "neura.data_mov"(%14) {mapping_locs = [{id = 17 : i32, resource = "link", time_step = 2 : i32}, {id = 16 : i32, resource = "link", time_step = 3 : i32}]} : (i64) -> i64 +// MAPPING-NEXT: %16 = "neura.data_mov"(%10) {mapping_locs = [{id = 31 : i32, resource = "link", time_step = 1 : i32}, {id = 288 : i32, resource = "register", time_step = 2 : i32}, {id = 288 : i32, resource = "register", time_step = 3 : i32}]} : (i64) -> i64 +// MAPPING-NEXT: %17 = "neura.icmp"(%15, %16) <{cmpType = "slt"}> {mapping_locs = [{id = 9 : i32, resource = "tile", time_step = 4 : i32, x = 1 : i32, y = 2 : i32}]} : (i64, i64) -> i1 +// MAPPING-NEXT: neura.ctrl_mov %17 -> %2 {mapping_locs = [{id = 30 : i32, resource = "link", time_step = 4 : i32}, {id = 416 : i32, resource = "register", time_step = 5 : i32}]} : i1 i1 +// MAPPING-NEXT: %18 = "neura.data_mov"(%12) {mapping_locs = [{id = 3 : i32, resource = "link", time_step = 1 : i32}, {id = 64 : i32, resource = "register", time_step = 2 : i32}, {id = 64 : i32, resource = "register", time_step = 3 : i32}, {id = 64 : i32, resource = "register", time_step = 4 : i32}, {id = 64 : i32, resource = "register", time_step = 5 : i32}, {id = 64 : i32, resource = "register", time_step = 6 : i32}]} : (i64) -> i64 +// MAPPING-NEXT: %19 = "neura.data_mov"(%17) {mapping_locs = [{id = 29 : i32, resource = "link", time_step = 4 : i32}, {id = 14 : i32, resource = "link", time_step = 5 : i32}, {id = 19 : i32, resource = "link", time_step = 6 : i32}]} : (i1) -> i1 +// MAPPING-NEXT: %20 = neura.false_steer %18, %19 {mapping_locs = [{id = 2 : i32, resource = "tile", time_step = 7 : i32, x = 2 : i32, y = 0 : i32}]} : i64, i1 -> i64 +// MAPPING-NEXT: %21 = "neura.data_mov"(%12) {mapping_locs = [{id = 4 : i32, resource = "link", time_step = 1 : i32}, {id = 160 : i32, resource = "register", time_step = 2 : i32}, {id = 160 : i32, resource = "register", time_step = 3 : i32}]} : (i64) -> i64 +// MAPPING-NEXT: %22 = "neura.data_mov"(%12) {mapping_locs = [{id = 2 : i32, resource = "link", time_step = 1 : i32}, {id = 1 : i32, resource = "link", time_step = 2 : i32}, {id = 10 : i32, resource = "link", time_step = 3 : i32}]} : (i64) -> i64 +// MAPPING-NEXT: %23 = "neura.add"(%21, %22) {mapping_locs = [{id = 5 : i32, resource = "tile", time_step = 4 : i32, x = 1 : i32, y = 1 : i32}]} : (i64, i64) -> i64 +// MAPPING-NEXT: neura.ctrl_mov %23 -> %0 {mapping_locs = [{id = 15 : i32, resource = "link", time_step = 4 : i32}, {id = 32 : i32, resource = "register", time_step = 5 : i32}]} : i64 i64 +// MAPPING-NEXT: %24 = "neura.data_mov"(%14) {mapping_locs = [{id = 18 : i32, resource = "link", time_step = 2 : i32}, {id = 224 : i32, resource = "register", time_step = 3 : i32}, {id = 224 : i32, resource = "register", time_step = 4 : i32}]} : (i64) -> i64 +// MAPPING-NEXT: %25 = "neura.data_mov"(%8) {mapping_locs = [{id = 41 : i32, resource = "link", time_step = 1 : i32}, {id = 44 : i32, resource = "link", time_step = 2 : i32}, {id = 47 : i32, resource = "link", time_step = 3 : i32}, {id = 36 : i32, resource = "link", time_step = 4 : i32}]} : (i64) -> i64 +// MAPPING-NEXT: %26 = "neura.add"(%24, %25) {mapping_locs = [{id = 7 : i32, resource = "tile", time_step = 5 : i32, x = 3 : i32, y = 1 : i32}]} : (i64, i64) -> i64 +// MAPPING-NEXT: neura.ctrl_mov %26 -> %1 {mapping_locs = [{id = 21 : i32, resource = "link", time_step = 5 : i32}, {id = 192 : i32, resource = "register", time_step = 6 : i32}]} : i64 i64 +// MAPPING-NEXT: %27 = "neura.data_mov"(%20) {mapping_locs = [{id = 6 : i32, resource = "link", time_step = 7 : i32}]} : (i64) -> i64 +// MAPPING-NEXT: "neura.return"(%27) {mapping_locs = [{id = 3 : i32, resource = "tile", time_step = 8 : i32, x = 3 : i32, y = 0 : i32}]} : (i64) -> ()