diff --git a/include/NeuraDialect/NeuraOps.td b/include/NeuraDialect/NeuraOps.td index 37cf555a..c044769a 100644 --- a/include/NeuraDialect/NeuraOps.td +++ b/include/NeuraDialect/NeuraOps.td @@ -43,12 +43,26 @@ def Neura_MulOp : Op { def Neura_DivOp : Op { let summary = "Integer division operation"; - let arguments = (ins AnyType:$lhs, AnyType:$rhs, Optional:$predicate); + let arguments = (ins AnyType:$lhs, Optional:$rhs); let results = (outs AnyType:$result); // let assemblyFormat = "$lhs `,` $rhs `,` $predicate attr-dict `:` type($result)"; let traits = [SameOperandsAndResultElementType]; } +def Neura_RemOp : Op{ + let summary = "Integer remainder operation"; + let description = [{ + Performs an integer remainder operation, computing the result of + a % b, where % is the remainder operator. + + Example: + %result = neura.rem %a, %b : i32 + }]; + let arguments = (ins AnyType:$lhs, Optional:$rhs); + let results = (outs AnyType:$result); + let traits = [SameOperandsAndResultElementType]; +} + // Defines a floating-point addition operation. def Neura_FAddOp : Op { let summary = "Floating addition operation"; @@ -63,8 +77,8 @@ def Neura_FAddOp : Op { def Neura_FSubOp: Op { let summary = "Floating substraction operation"; let opName = "fsub"; - let arguments = (ins AnyFloat:$lhs, AnyFloat:$rhs, Optional:$predicate); - let results = (outs AnyFloat:$result); + let arguments = (ins AnyType:$lhs, Optional:$rhs); + let results = (outs AnyType:$result); // let assemblyFormat = "$lhs `,` $rhs attr-dict `:` type($result)"; let traits = [SameOperandsAndResultElementType]; } @@ -222,9 +236,9 @@ def Neura_AllocaOp : Op { %ptr = neura.alloca %size : !neura.data -> !llvm.ptr }]; - let arguments = (ins AnyType:$size); + let arguments = (ins Optional:$size); let results = (outs AnyType:$result); - let assemblyFormat = "$size attr-dict `:` type($size) `->` type($result)"; + let assemblyFormat = "($size^ `:` type($size))? attr-dict `->` type($result)"; } // Defines a sign extension operation. @@ -259,6 +273,20 @@ def Neura_ZExtOp : Op { let assemblyFormat = "$value attr-dict `:` type($value) `->` type($result)"; } +// Defines a logical shift left operation. +def Neura_ShlOp : Op { + let summary = "Logical shift left operation"; + let description = [{ + Performs a logical left shift on an integer value. + Similar to llvm.shl, but works with predicated values. + + Example: + %shifted = neura.shl %value, %shiftAmount : !neura.data -> !neura.data + }]; + let arguments = (ins AnyType:$value, Optional:$shiftAmount); + let results = (outs AnyType:$result); +} + // ---------------------------------------------------- // Defines vector operations. diff --git a/lib/Conversion/ArithToNeura/ArithToNeuraPass.cpp b/lib/Conversion/ArithToNeura/ArithToNeuraPass.cpp index cb8cc039..bdc0160f 100644 --- a/lib/Conversion/ArithToNeura/ArithToNeuraPass.cpp +++ b/lib/Conversion/ArithToNeura/ArithToNeuraPass.cpp @@ -98,8 +98,7 @@ struct ArithSubFToNeuraFSub : public OpRewritePattern { Type result_type = op.getType(); // Optional predicate: default to null. - rewriter.replaceOpWithNewOp(op, result_type, lhs, rhs, - nullptr); + rewriter.replaceOpWithNewOp(op, result_type, lhs, rhs); return success(); } }; @@ -144,8 +143,7 @@ struct ArithDivSIToNeuraDiv : public OpRewritePattern { Type result_type = op.getType(); // Converts arith DivSIOp to Neura DivOp. // Optional predicate: default to null. - rewriter.replaceOpWithNewOp(op, result_type, lhs, rhs, - nullptr); + rewriter.replaceOpWithNewOp(op, result_type, lhs, rhs); return success(); } }; @@ -176,8 +174,7 @@ struct ArithRemSIToNeuraOp : public OpRewritePattern { Location loc = op.getLoc(); // Converts arith RemSIOp to basic Neura Op. // Optional predicate: default to null. - Value div = - rewriter.create(loc, result_type, lhs, rhs, nullptr); + Value div = rewriter.create(loc, result_type, lhs, rhs); Value mul = rewriter.create(loc, result_type, rhs, div); Value rem = rewriter.create(loc, result_type, lhs, mul); diff --git a/lib/Conversion/LlvmToNeura/LlvmToNeuraPass.cpp b/lib/Conversion/LlvmToNeura/LlvmToNeuraPass.cpp index 955413d6..79c501ef 100644 --- a/lib/Conversion/LlvmToNeura/LlvmToNeuraPass.cpp +++ b/lib/Conversion/LlvmToNeura/LlvmToNeuraPass.cpp @@ -73,8 +73,7 @@ struct LlvmFSubToNeuraFSub : public OpRewritePattern { } // Sets optional predicate: default to 'none'. - rewriter.replaceOpWithNewOp(op, result_type, lhs, rhs, - Value()); + rewriter.replaceOpWithNewOp(op, result_type, lhs, rhs); return success(); } }; @@ -109,6 +108,35 @@ struct LlvmFMulToNeuraFMul : public OpRewritePattern { } }; +struct LlvmSDivToNeuraDiv : public OpRewritePattern { + using OpRewritePattern::OpRewritePattern; + + LogicalResult matchAndRewrite(LLVM::SDivOp op, + PatternRewriter &rewriter) const override { + Value lhs = op.getLhs(); + Value rhs = op.getRhs(); + Type resultType = op.getType(); + + rewriter.replaceOpWithNewOp(op, resultType, lhs, rhs); + return success(); + } +}; + +struct LlvmSRemToNeuraRem : public OpRewritePattern { + using OpRewritePattern::OpRewritePattern; + + LogicalResult matchAndRewrite(LLVM::SRemOp op, + PatternRewriter &rewriter) const override { + Value lhs = op.getLhs(); + Value rhs = op.getRhs(); + Type resultType = op.getType(); + + // Create neura.rem operation to replace llvm.srem + rewriter.replaceOpWithNewOp(op, resultType, lhs, rhs); + return success(); + } +}; + struct LlvmVFMulToNeuraVFMul : public OpRewritePattern { using OpRewritePattern::OpRewritePattern; @@ -311,11 +339,11 @@ struct LlvmAllocaToNeuraAlloca : public OpRewritePattern { PatternRewriter &rewriter) const override { Value size = op.getArraySize(); Type resultType = op.getType(); - + // Converts the size to neura.data if it's not already. // Assumes the size is already in the right format. // Handles type conversion here. - + rewriter.replaceOpWithNewOp(op, resultType, size); return success(); } @@ -328,7 +356,7 @@ struct LlvmSExtToNeuraSExt : public OpRewritePattern { PatternRewriter &rewriter) const override { Value input = op.getArg(); Type resultType = op.getType(); - + rewriter.replaceOpWithNewOp(op, resultType, input); return success(); } @@ -341,7 +369,7 @@ struct LlvmZExtToNeuraZExt : public OpRewritePattern { PatternRewriter &rewriter) const override { Value input = op.getArg(); Type resultType = op.getType(); - + rewriter.replaceOpWithNewOp(op, resultType, input); return success(); } @@ -355,19 +383,32 @@ struct LlvmMulToNeuraMul : public OpRewritePattern { Value lhs = op.getLhs(); Value rhs = op.getRhs(); Type resultType = op.getType(); - + rewriter.replaceOpWithNewOp(op, resultType, lhs, rhs); return success(); } }; +struct LlvmShlToNeuraShl : public OpRewritePattern { + using OpRewritePattern::OpRewritePattern; + + LogicalResult matchAndRewrite(LLVM::ShlOp op, + PatternRewriter &rewriter) const override { + Value lhs = op.getLhs(); + Value rhs = op.getRhs(); + Type resultType = op.getType(); + + rewriter.replaceOpWithNewOp(op, resultType, lhs, rhs); + return success(); + } +}; + struct LlvmFuncToNeuraFunc : public OpRewritePattern { using OpRewritePattern::OpRewritePattern; LogicalResult matchAndRewrite(LLVM::LLVMFuncOp op, PatternRewriter &rewriter) const override { - auto target = op->getAttrOfType(mlir::accel::kAcceleratorAttr); if (!target || target.getValue() != mlir::accel::kNeuraTarget) { return failure(); @@ -375,16 +416,15 @@ struct LlvmFuncToNeuraFunc : public OpRewritePattern { // Converts LLVMFunctionType to FunctionType. auto llvmFuncType = op.getFunctionType(); - auto funcType = rewriter.getFunctionType( - llvmFuncType.getParams(), - llvmFuncType.getReturnType() - ); + auto funcType = rewriter.getFunctionType(llvmFuncType.getParams(), + llvmFuncType.getReturnType()); - // Creates the new func.func operation using OperationState to have full control. + // Creates the new func.func operation using OperationState to have full + // control. OperationState state(op.getLoc(), func::FuncOp::getOperationName()); state.addAttribute("sym_name", rewriter.getStringAttr(op.getName())); state.addAttribute("function_type", TypeAttr::get(funcType)); - + // Copies ALL attributes from the original llvm.func exactly as they are. // Skips function type and name attributes as they are handled separately. SmallVector attrs; @@ -395,15 +435,16 @@ struct LlvmFuncToNeuraFunc : public OpRewritePattern { attrs.push_back(attr); } state.addAttributes(attrs); - + // Adds the function body region. state.addRegion(); - + auto newFunc = cast(rewriter.create(state)); // Moves the function body. - rewriter.inlineRegionBefore(op.getBody(), newFunc.getBody(), newFunc.getBody().end()); - + rewriter.inlineRegionBefore(op.getBody(), newFunc.getBody(), + newFunc.getBody().end()); + // Replaces the old function. rewriter.replaceOp(op, newFunc); return success(); @@ -435,12 +476,11 @@ struct LlvmCallToFuncCall : public OpRewritePattern { // Gets the result types from the function signature. auto resultTypes = funcOp.getFunctionType().getResults(); - + // Converts the call to func.call. auto newCall = rewriter.create( - op.getLoc(), resultTypes, callee.value(), op.getArgOperands() - ); - + op.getLoc(), resultTypes, callee.value(), op.getArgOperands()); + // Replaces the old call with the new one. // Handles both cases: calls with results and calls without results. if (op.getNumResults() == 0) { @@ -448,7 +488,7 @@ struct LlvmCallToFuncCall : public OpRewritePattern { } else { rewriter.replaceOp(op, newCall->getResults()); } - + return success(); } }; @@ -494,6 +534,9 @@ struct LowerLlvmToNeuraPass patterns.add(&getContext()); patterns.add(&getContext()); patterns.add(&getContext()); + patterns.add(&getContext()); + patterns.add(&getContext()); + patterns.add(&getContext()); FrozenRewritePatternSet frozen(std::move(patterns)); diff --git a/lib/Conversion/MemRefToNeura/MemRefToNeuraPass.cpp b/lib/Conversion/MemRefToNeura/MemRefToNeuraPass.cpp index 50004896..b039a525 100644 --- a/lib/Conversion/MemRefToNeura/MemRefToNeuraPass.cpp +++ b/lib/Conversion/MemRefToNeura/MemRefToNeuraPass.cpp @@ -8,6 +8,7 @@ #include "mlir/IR/PatternMatch.h" #include "mlir/Pass/Pass.h" #include "mlir/Transforms/GreedyPatternRewriteDriver.h" +#include "llvm/Support/LogicalResult.h" using namespace mlir; using namespace mlir::neura; @@ -46,6 +47,30 @@ struct MemRefStoreLowering : public OpRewritePattern { } }; +struct MemRefAllocaToNeuraAlloca : public OpRewritePattern { + using OpRewritePattern::OpRewritePattern; + + LogicalResult matchAndRewrite(memref::AllocaOp alloca_op, + PatternRewriter &rewriter) const override { + // Gets the result type. + Type result_type = alloca_op.getType(); + + // Checks if we have dynamic dimensions. + if (!alloca_op.getDynamicSizes().empty()) { + // For dynamic dimensions, we need to create the alloca with the size + // arguments. + rewriter.replaceOpWithNewOp(alloca_op, result_type, + alloca_op.getDynamicSizes()); + } else { + // For static dimensions, we can create the alloca without size arguments. + rewriter.replaceOpWithNewOp(alloca_op, result_type, + Value()); + } + + return success(); + } +}; + struct LowerMemRefToNeuraPass : public PassWrapper> { @@ -64,8 +89,11 @@ struct LowerMemRefToNeuraPass ModuleOp module_op = getOperation(); MLIRContext *context = &getContext(); RewritePatternSet patterns(&getContext()); + patterns.add(context); patterns.add(context); + patterns.add(context); + module_op.walk([&](func::FuncOp func_op) { if (func_op->hasAttr(mlir::accel::kAcceleratorAttr)) { auto target = diff --git a/lib/NeuraDialect/Architecture/Architecture.cpp b/lib/NeuraDialect/Architecture/Architecture.cpp index 37961ae5..3143139b 100644 --- a/lib/NeuraDialect/Architecture/Architecture.cpp +++ b/lib/NeuraDialect/Architecture/Architecture.cpp @@ -209,8 +209,8 @@ Architecture::Architecture(int width, int height) { for (int x = 0; x < width; ++x) { // Gets the tile by coordinates. Tile *tile = getTile(x, y); - const int kNUM_REGS_PER_REGFILE = 4; - const int kNUM_REGFILES_PER_CLUSTER = 2; + const int kNUM_REGS_PER_REGFILE = 8; + const int kNUM_REGFILES_PER_CLUSTER = 4; // Assembles register files into a cluster. RegisterFileCluster *register_file_cluster = diff --git a/lib/NeuraDialect/Transforms/MapToAcceleratorPass.cpp b/lib/NeuraDialect/Transforms/MapToAcceleratorPass.cpp index 20c00db8..906f5ac1 100644 --- a/lib/NeuraDialect/Transforms/MapToAcceleratorPass.cpp +++ b/lib/NeuraDialect/Transforms/MapToAcceleratorPass.cpp @@ -173,7 +173,7 @@ struct MapToAcceleratorPass int res_mii = calculateResMii(func, architecture); const int possibleMinII = std::max(rec_mii, res_mii); - constexpr int maxII = 15; + constexpr int maxII = 20; std::vector topologically_sorted_ops = getTopologicallySortedOps(func); if (topologically_sorted_ops.empty()) { diff --git a/lib/NeuraDialect/Transforms/Optimizations/HwAgnosticOpt/FoldConstantPass.cpp b/lib/NeuraDialect/Transforms/Optimizations/HwAgnosticOpt/FoldConstantPass.cpp index 7283ef31..93f25a78 100644 --- a/lib/NeuraDialect/Transforms/Optimizations/HwAgnosticOpt/FoldConstantPass.cpp +++ b/lib/NeuraDialect/Transforms/Optimizations/HwAgnosticOpt/FoldConstantPass.cpp @@ -205,6 +205,34 @@ struct FuseFAddRhsConstantPattern } }; +struct FuseDivRhsConstantPattern : public FuseRhsConstantPattern { + using FuseRhsConstantPattern::FuseRhsConstantPattern; + + Operation * + createOpWithFusedRhsConstant(neura::DivOp op, Attribute rhs_const_value, + PatternRewriter &rewriter) const override { + auto fused_op = rewriter.create( + op.getLoc(), op.getResult().getType(), op.getLhs(), + /*rhs=*/nullptr); + addConstantAttribute(fused_op, "rhs_const_value", rhs_const_value); + return fused_op; + } +}; + +struct FuseRemRhsConstantPattern : public FuseRhsConstantPattern { + using FuseRhsConstantPattern::FuseRhsConstantPattern; + + Operation * + createOpWithFusedRhsConstant(neura::RemOp op, Attribute rhs_const_value, + PatternRewriter &rewriter) const override { + auto fused_op = rewriter.create( + op.getLoc(), op.getResult().getType(), op.getLhs(), + /*rhs=*/nullptr); + addConstantAttribute(fused_op, "rhs_const_value", rhs_const_value); + return fused_op; + } +}; + // ========================================= // FoldConstantPass Implementation // ========================================= @@ -226,6 +254,8 @@ struct FoldConstantPass patterns.add(&getContext()); patterns.add(&getContext()); patterns.add(&getContext()); + patterns.add(&getContext()); + patterns.add(&getContext()); patterns.add(&getContext()); FrozenRewritePatternSet frozen(std::move(patterns)); diff --git a/test/c2llvm2mlir/nested_loop/test.mlir b/test/c2llvm2mlir/nested_loop/test.mlir index 710b682b..bac316db 100644 --- a/test/c2llvm2mlir/nested_loop/test.mlir +++ b/test/c2llvm2mlir/nested_loop/test.mlir @@ -1,5 +1,5 @@ -// RUN: clang++ -S -emit-llvm kernel.cpp -o kernel.ll -// RUN: mlir-translate --import-llvm kernel.ll -o kernel.mlir +// RUN: clang++ -S -emit-llvm kernel.cpp -o %t-kernel.ll +// RUN: mlir-translate --import-llvm %t-kernel.ll -o %t-kernel.mlir // RUN: mlir-neura-opt --assign-accelerator \ // RUN: --lower-llvm-to-neura \ @@ -7,7 +7,7 @@ // RUN: --leverage-predicated-value \ // RUN: --transform-ctrl-to-data-flow \ // RUN: --fold-constant \ -// RUN: --insert-data-mov kernel.mlir | FileCheck %s --check-prefix=CHECK-LLVM2NEURA +// RUN: --insert-data-mov %t-kernel.mlir | FileCheck %s --check-prefix=CHECK-LLVM2NEURA // RUN: mlir-neura-opt --assign-accelerator \ // RUN: --lower-llvm-to-neura \ @@ -16,7 +16,7 @@ // RUN: --transform-ctrl-to-data-flow \ // RUN: --fold-constant \ // RUN: --insert-data-mov \ -// RUN: --map-to-accelerator="mapping-strategy=heuristic backtrack-config=simple" kernel.mlir | FileCheck %s --check-prefix=CHECK-LLVM2NEURA-MAP +// RUN: --map-to-accelerator="mapping-strategy=heuristic backtrack-config=simple" %t-kernel.mlir | FileCheck %s --check-prefix=CHECK-LLVM2NEURA-MAP // CHECK-LLVM2NEURA: accelerator = "neura" // CHECK-LLVM2NEURA: %25 = neura.alloca %24 : !neura.data -> !neura.data @@ -24,4 +24,4 @@ // CHECK-LLVM2NEURA: %175 = neura.sext %174 : !neura.data -> !neura.data // CHECK-LLVM2NEURA: %194 = "neura.mul"(%192, %193) : (!neura.data, !neura.data) -> !neura.data -// CHECK-LLVM2NEURA-MAP: func.func @_Z6kernelPiS_S_(%arg0: !llvm.ptr {llvm.noundef}, %arg1: !llvm.ptr {llvm.noundef}, %arg2: !llvm.ptr {llvm.noundef}) -> !llvm.void attributes {CConv = #llvm.cconv, accelerator = "neura", frame_pointer = #llvm.framePointerKind, linkage = #llvm.linkage, no_inline, no_unwind, optimize_none, passthrough = ["mustprogress", ["uwtable", "2"], ["min-legal-vector-width", "0"], ["no-trapping-math", "true"], ["stack-protector-buffer-size", "8"], ["target-cpu", "x86-64"]], target_cpu = "x86-64", target_features = #llvm.target_features<["+cmov", "+cx8", "+fxsr", "+mmx", "+sse", "+sse2", "+x87"]>, tune_cpu = "generic", unnamed_addr = 0 : i64, visibility_ = 0 : i64} { \ No newline at end of file +// CHECK-LLVM2NEURA-MAP: func.func @_Z6kernelPiS_S_(%arg0: !llvm.ptr {llvm.noundef}, %arg1: !llvm.ptr {llvm.noundef}, %arg2: !llvm.ptr {llvm.noundef}) -> !llvm.void attributes {CConv = #llvm.cconv, accelerator = "neura", frame_pointer = #llvm.framePointerKind, linkage = #llvm.linkage, mapping_info = {compiled_ii = 17 : i32, mapping_mode = "spatial-temporal", mapping_strategy = "heuristic", rec_mii = 9 : i32, res_mii = 6 : i32, x_tiles = 4 : i32, y_tiles = 4 : i32}, no_inline, no_unwind, optimize_none, passthrough = ["mustprogress", ["uwtable", "2"], ["min-legal-vector-width", "0"], ["no-trapping-math", "true"], ["stack-protector-buffer-size", "8"], ["target-cpu", "x86-64"]], target_cpu = "x86-64", target_features = #llvm.target_features<["+cmov", "+cx8", "+fxsr", "+mmx", "+sse", "+sse2", "+x87"]>, tune_cpu = "generic", unnamed_addr = 0 : i64, visibility_ = 0 : i64} { \ No newline at end of file diff --git a/test/code_gen/test_code_generate.mlir b/test/code_gen/test_code_generate.mlir index 46a17e1c..2c155802 100644 --- a/test/code_gen/test_code_generate.mlir +++ b/test/code_gen/test_code_generate.mlir @@ -68,63 +68,63 @@ func.func @loop_test() -> f32 { // written into local register $20. // -// YAML: - column: 1 -// YAML-NEXT: row: 0 -// YAML-NEXT: core_id: "1" -// YAML-NEXT: entries: -// YAML-NEXT: - entry_id: "entry0" -// YAML-NEXT: instructions: -// YAML-NEXT: - timestep: 1 -// YAML-NEXT: operations: -// YAML-NEXT: - opcode: "GRANT_ONCE" -// YAML-NEXT: src_operands: -// YAML-NEXT: - operand: "WEST" -// YAML-NEXT: color: "RED" -// YAML-NEXT: dst_operands: -// YAML-NEXT: - operand: "NORTH" -// YAML-NEXT: color: "RED" -// YAML-NEXT: - timestep: 2 -// YAML-NEXT: operations: -// YAML-NEXT: - opcode: "GRANT_ONCE" -// YAML-NEXT: src_operands: -// YAML-NEXT: - operand: "WEST" -// YAML-NEXT: color: "RED" -// YAML-NEXT: dst_operands: -// YAML-NEXT: - operand: "$8" -// YAML-NEXT: color: "RED" -// YAML-NEXT: - timestep: 3 -// YAML-NEXT: operations: -// YAML-NEXT: - opcode: "PHI" -// YAML-NEXT: src_operands: -// YAML-NEXT: - operand: "$9" -// YAML-NEXT: color: "RED" -// YAML-NEXT: - operand: "$8" -// YAML-NEXT: color: "RED" -// YAML-NEXT: dst_operands: -// YAML-NEXT: - operand: "NORTH" -// YAML-NEXT: color: "RED" -// YAML-NEXT: - operand: "$8" -// YAML-NEXT: color: "RED" -// YAML-NEXT: - timestep: 4 -// YAML-NEXT: operations: -// YAML-NEXT: - opcode: "DATA_MOV" -// YAML-NEXT: src_operands: -// YAML-NEXT: - operand: "EAST" -// YAML-NEXT: color: "RED" -// YAML-NEXT: dst_operands: -// YAML-NEXT: - operand: "NORTH" -// YAML-NEXT: color: "RED" -// YAML-NEXT: - timestep: 5 -// YAML-NEXT: operations: -// YAML-NEXT: - opcode: "GRANT_PREDICATE" -// YAML-NEXT: src_operands: -// YAML-NEXT: - operand: "$8" -// YAML-NEXT: color: "RED" -// YAML-NEXT: - operand: "NORTH" -// YAML-NEXT: color: "RED" -// YAML-NEXT: dst_operands: -// YAML-NEXT: - operand: "$9" -// YAML-NEXT: color: "RED" +// YAML: - column: 1 +// YAML-NEXT: row: 0 +// YAML-NEXT: core_id: "1" +// YAML-NEXT: entries: +// YAML-NEXT: - entry_id: "entry0" +// YAML-NEXT: instructions: +// YAML-NEXT: - timestep: 1 +// YAML-NEXT: operations: +// YAML-NEXT: - opcode: "GRANT_ONCE" +// YAML-NEXT: src_operands: +// YAML-NEXT: - operand: "WEST" +// YAML-NEXT: color: "RED" +// YAML-NEXT: dst_operands: +// YAML-NEXT: - operand: "NORTH" +// YAML-NEXT: color: "RED" +// YAML-NEXT: - timestep: 2 +// YAML-NEXT: operations: +// YAML-NEXT: - opcode: "GRANT_ONCE" +// YAML-NEXT: src_operands: +// YAML-NEXT: - operand: "WEST" +// YAML-NEXT: color: "RED" +// YAML-NEXT: dst_operands: +// YAML-NEXT: - operand: "$32" +// YAML-NEXT: color: "RED" +// YAML-NEXT: - timestep: 3 +// YAML-NEXT: operations: +// YAML-NEXT: - opcode: "PHI" +// YAML-NEXT: src_operands: +// YAML-NEXT: - operand: "$33" +// YAML-NEXT: color: "RED" +// YAML-NEXT: - operand: "$32" +// YAML-NEXT: color: "RED" +// YAML-NEXT: dst_operands: +// YAML-NEXT: - operand: "NORTH" +// YAML-NEXT: color: "RED" +// YAML-NEXT: - operand: "$32" +// YAML-NEXT: color: "RED" +// YAML-NEXT: - timestep: 4 +// YAML-NEXT: operations: +// YAML-NEXT: - opcode: "DATA_MOV" +// YAML-NEXT: src_operands: +// YAML-NEXT: - operand: "EAST" +// YAML-NEXT: color: "RED" +// YAML-NEXT: dst_operands: +// YAML-NEXT: - operand: "NORTH" +// YAML-NEXT: color: "RED" +// YAML-NEXT: - timestep: 5 +// YAML-NEXT: operations: +// YAML-NEXT: - opcode: "GRANT_PREDICATE" +// YAML-NEXT: src_operands: +// YAML-NEXT: - operand: "$32" +// YAML-NEXT: color: "RED" +// YAML-NEXT: - operand: "NORTH" +// YAML-NEXT: color: "RED" +// YAML-NEXT: dst_operands: +// YAML-NEXT: - operand: "$33" +// YAML-NEXT: color: "RED" // ASM: PE(0,0):