From 90c4339808061f4921824fd44cc31fe70a0dd77c Mon Sep 17 00:00:00 2001 From: ilgeco Date: Fri, 5 Jun 2026 17:12:16 +0200 Subject: [PATCH] SpatialSubOp --- .../ONNXToSpatial/ONNXToSpatialPass.cpp | 1 + .../Patterns/Math/Elementwise.cpp | 1 + .../Conversion/SpatialToPim/SpatialToPim.td | 6 ++ src/PIM/Dialect/Spatial/Spatial.td | 19 ++++ src/PIM/Dialect/Spatial/SpatialOpsVerify.cpp | 6 ++ validation/operations/gen_tests.py | 84 ++++++++++++++++++ .../sub/after_gemm/sub_after_gemm.onnx | Bin 0 -> 8594 bytes .../operations/sub/basic/sub_basic.onnx | Bin 0 -> 100 bytes .../sub/broadcast_row/sub_broadcast_row.onnx | Bin 0 -> 130 bytes .../sub_channel_broadcast_1024.onnx | Bin 0 -> 4231 bytes .../sub_constant_lhs_broadcast.onnx | Bin 0 -> 140 bytes .../sub_leading_dimension_broadcast.onnx | Bin 0 -> 136 bytes 12 files changed, 117 insertions(+) create mode 100644 validation/operations/sub/after_gemm/sub_after_gemm.onnx create mode 100644 validation/operations/sub/basic/sub_basic.onnx create mode 100644 validation/operations/sub/broadcast_row/sub_broadcast_row.onnx create mode 100644 validation/operations/sub/channel_broadcast_1024/sub_channel_broadcast_1024.onnx create mode 100644 validation/operations/sub/constant_lhs_broadcast/sub_constant_lhs_broadcast.onnx create mode 100644 validation/operations/sub/leading_dimension_broadcast/sub_leading_dimension_broadcast.onnx diff --git a/src/PIM/Conversion/ONNXToSpatial/ONNXToSpatialPass.cpp b/src/PIM/Conversion/ONNXToSpatial/ONNXToSpatialPass.cpp index cbcc67a..edf311e 100644 --- a/src/PIM/Conversion/ONNXToSpatial/ONNXToSpatialPass.cpp +++ b/src/PIM/Conversion/ONNXToSpatial/ONNXToSpatialPass.cpp @@ -124,6 +124,7 @@ void ONNXToSpatialPass::runOnOperation() { target.addIllegalOp(); target.addIllegalOp(); target.addIllegalOp(); + target.addIllegalOp(); target.addIllegalOp(); target.addIllegalOp(); target.addIllegalOp(); diff --git a/src/PIM/Conversion/ONNXToSpatial/Patterns/Math/Elementwise.cpp b/src/PIM/Conversion/ONNXToSpatial/Patterns/Math/Elementwise.cpp index 2912e49..506456f 100644 --- a/src/PIM/Conversion/ONNXToSpatial/Patterns/Math/Elementwise.cpp +++ b/src/PIM/Conversion/ONNXToSpatial/Patterns/Math/Elementwise.cpp @@ -189,6 +189,7 @@ struct DivToSpatialCompute : OpConversionPattern { void populateElementwisePatterns(RewritePatternSet& patterns, MLIRContext* ctx) { patterns.add>(ctx); + patterns.add>(ctx); patterns.add>(ctx); patterns.add(ctx); } diff --git a/src/PIM/Conversion/SpatialToPim/SpatialToPim.td b/src/PIM/Conversion/SpatialToPim/SpatialToPim.td index 31a4e13..dfc6c47 100644 --- a/src/PIM/Conversion/SpatialToPim/SpatialToPim.td +++ b/src/PIM/Conversion/SpatialToPim/SpatialToPim.td @@ -27,6 +27,12 @@ def spatToPimVVAdd : Pat< (NativeCodeCall<"onnx_mlir::getBestOutputTensorFromOperandsOrAllocate($_builder, $0.getDefiningOp())"> $srcOpRes)) >; +def spatToPimVVSub : Pat< + (SpatVSubOp:$srcOpRes $a, $b), + (PimVVSubOp $a, $b, + (NativeCodeCall<"onnx_mlir::getBestOutputTensorFromOperandsOrAllocate($_builder, $0.getDefiningOp())"> $srcOpRes)) +>; + def spatToPimVVMul : Pat< (SpatVMulOp:$srcOpRes $a, $b), (PimVVMulOp $a, $b, diff --git a/src/PIM/Dialect/Spatial/Spatial.td b/src/PIM/Dialect/Spatial/Spatial.td index cdd3464..56347d8 100644 --- a/src/PIM/Dialect/Spatial/Spatial.td +++ b/src/PIM/Dialect/Spatial/Spatial.td @@ -257,6 +257,25 @@ def SpatVAddOp : SpatOp<"vadd", []> { }]; } +def SpatVSubOp : SpatOp<"vsub", []> { + let summary = "Element-wise subtraction between two tensors; rhs must match lhs or be 1x1"; + + let arguments = (ins + SpatTensor:$lhs, + SpatTensor:$rhs + ); + + let results = (outs + SpatTensor:$output + ); + + let hasVerifier = 1; + + let assemblyFormat = [{ + $lhs `,` $rhs attr-dict `:` `(` type($lhs) `,` type($rhs) `)` `->` type($output) + }]; +} + def SpatVMulOp : SpatOp<"vmul", []> { let summary = "Element-wise multiplication between two tensors; rhs must match lhs or be 1x1"; diff --git a/src/PIM/Dialect/Spatial/SpatialOpsVerify.cpp b/src/PIM/Dialect/Spatial/SpatialOpsVerify.cpp index 2639423..02bc62d 100644 --- a/src/PIM/Dialect/Spatial/SpatialOpsVerify.cpp +++ b/src/PIM/Dialect/Spatial/SpatialOpsVerify.cpp @@ -254,6 +254,12 @@ LogicalResult SpatVAddOp::verify() { return OpTrait::impl::verifySameOperandsAndResultType(*this); } +LogicalResult SpatVSubOp::verify() { + if (failed(OpTrait::impl::verifyAtLeastNOperands(*this, 2))) + return failure(); + return OpTrait::impl::verifySameOperandsAndResultType(*this); +} + LogicalResult SpatVMaxOp::verify() { if (failed(OpTrait::impl::verifyAtLeastNOperands(*this, 2))) return failure(); diff --git a/validation/operations/gen_tests.py b/validation/operations/gen_tests.py index ba09a7a..1d5adce 100644 --- a/validation/operations/gen_tests.py +++ b/validation/operations/gen_tests.py @@ -1549,6 +1549,82 @@ def add_leading_dimension_broadcast(): save_model(model, "add/leading_dimension_broadcast", "add_leading_dimension_broadcast.onnx") +# --------------------------------------------------------------------------- +# Sub tests +# --------------------------------------------------------------------------- + +def sub_basic(): + """Elementwise Sub on two runtime inputs with identical shapes.""" + A = helper.make_tensor_value_info("A", TensorProto.FLOAT, [4, 8]) + B = helper.make_tensor_value_info("B", TensorProto.FLOAT, [4, 8]) + Y = helper.make_tensor_value_info("Y", TensorProto.FLOAT, [4, 8]) + node = helper.make_node("Sub", ["A", "B"], ["Y"]) + graph = helper.make_graph([node], "sub_basic", [A, B], [Y]) + model = helper.make_model(graph, opset_imports=[helper.make_opsetid("", 13)]) + save_model(model, "sub/basic", "sub_basic.onnx") + + +def sub_broadcast_row(): + """Elementwise Sub with a broadcast row-vector RHS constant.""" + A = helper.make_tensor_value_info("A", TensorProto.FLOAT, [4, 8]) + Y = helper.make_tensor_value_info("Y", TensorProto.FLOAT, [4, 8]) + B = numpy_helper.from_array(np.random.default_rng(103).uniform(-1, 1, (8,)).astype(np.float32), name="B") + node = helper.make_node("Sub", ["A", "B"], ["Y"]) + graph = helper.make_graph([node], "sub_broadcast_row", [A], [Y], initializer=[B]) + model = helper.make_model(graph, opset_imports=[helper.make_opsetid("", 13)]) + save_model(model, "sub/broadcast_row", "sub_broadcast_row.onnx") + + +def sub_constant_lhs_broadcast(): + """Elementwise Sub with a broadcast constant LHS to preserve operand order.""" + B = helper.make_tensor_value_info("B", TensorProto.FLOAT, [4, 8]) + Y = helper.make_tensor_value_info("Y", TensorProto.FLOAT, [4, 8]) + A = numpy_helper.from_array(np.random.default_rng(104).uniform(-1, 1, (8,)).astype(np.float32), name="A") + node = helper.make_node("Sub", ["A", "B"], ["Y"]) + graph = helper.make_graph([node], "sub_constant_lhs_broadcast", [B], [Y], initializer=[A]) + model = helper.make_model(graph, opset_imports=[helper.make_opsetid("", 13)]) + save_model(model, "sub/constant_lhs_broadcast", "sub_constant_lhs_broadcast.onnx") + + +def sub_after_gemm(): + """Gemm followed by Sub with a broadcast constant vector.""" + B, K, N = 4, 64, 32 + rng = np.random.default_rng(105) + W = numpy_helper.from_array(rng.uniform(-1, 1, (K, N)).astype(np.float32), name="W") + C = numpy_helper.from_array(rng.uniform(-1, 1, (N,)).astype(np.float32), name="C") + S = numpy_helper.from_array(rng.uniform(-1, 1, (N,)).astype(np.float32), name="S") + A = helper.make_tensor_value_info("A", TensorProto.FLOAT, [B, K]) + Y = helper.make_tensor_value_info("Y", TensorProto.FLOAT, [B, N]) + gemm = helper.make_node("Gemm", ["A", "W", "C"], ["G"]) + sub = helper.make_node("Sub", ["G", "S"], ["Y"]) + graph = helper.make_graph([gemm, sub], "sub_after_gemm", [A], [Y], initializer=[W, C, S]) + model = helper.make_model(graph, opset_imports=[helper.make_opsetid("", 13)]) + save_model(model, "sub/after_gemm", "sub_after_gemm.onnx") + + +def sub_channel_broadcast_1024(): + """Elementwise Sub with 1024-channel constant broadcasting.""" + A = helper.make_tensor_value_info("A", TensorProto.FLOAT, [1, 1024, 1, 1]) + Y = helper.make_tensor_value_info("Y", TensorProto.FLOAT, [1, 1024, 1, 1]) + B = numpy_helper.from_array( + np.random.default_rng(106).uniform(-1, 1, (1, 1024, 1, 1)).astype(np.float32), name="B") + node = helper.make_node("Sub", ["A", "B"], ["Y"]) + graph = helper.make_graph([node], "sub_channel_broadcast_1024", [A], [Y], initializer=[B]) + model = helper.make_model(graph, opset_imports=[helper.make_opsetid("", 13)]) + save_model(model, "sub/channel_broadcast_1024", "sub_channel_broadcast_1024.onnx") + + +def sub_leading_dimension_broadcast(): + """Elementwise Sub with trailing-dimension constant broadcasting.""" + A = helper.make_tensor_value_info("A", TensorProto.FLOAT, [2, 3, 4]) + Y = helper.make_tensor_value_info("Y", TensorProto.FLOAT, [2, 3, 4]) + B = numpy_helper.from_array(np.random.default_rng(107).uniform(-1, 1, (4,)).astype(np.float32), name="B") + node = helper.make_node("Sub", ["A", "B"], ["Y"]) + graph = helper.make_graph([node], "sub_leading_dimension_broadcast", [A], [Y], initializer=[B]) + model = helper.make_model(graph, opset_imports=[helper.make_opsetid("", 13)]) + save_model(model, "sub/leading_dimension_broadcast", "sub_leading_dimension_broadcast.onnx") + + # --------------------------------------------------------------------------- # Mul tests # --------------------------------------------------------------------------- @@ -1844,6 +1920,14 @@ if __name__ == "__main__": add_channel_broadcast_1024() add_leading_dimension_broadcast() + print("\nGenerating Sub tests:") + sub_basic() + sub_broadcast_row() + sub_constant_lhs_broadcast() + sub_after_gemm() + sub_channel_broadcast_1024() + sub_leading_dimension_broadcast() + print("\nGenerating Mul tests:") mul_basic() mul_scalar_constant() diff --git a/validation/operations/sub/after_gemm/sub_after_gemm.onnx b/validation/operations/sub/after_gemm/sub_after_gemm.onnx new file mode 100644 index 0000000000000000000000000000000000000000..0f79fa965f6bec19ed9a11ed4616e490dbcbd505 GIT binary patch literal 8594 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 literal 0 HcmV?d00001 diff --git a/validation/operations/sub/basic/sub_basic.onnx b/validation/operations/sub/basic/sub_basic.onnx new file mode 100644 index 0000000000000000000000000000000000000000..eda1d67bd24a562b7e59924b83dcd01ad74e99ae GIT binary patch literal 100 zcmdj8tL{E=>~REG|uoPf9G#OpX!;N(u3C@o+E-ad0tlumCX! VNYDvgFbOCai7x2G!o?uK3jog43p@Y- literal 0 HcmV?d00001 diff --git a/validation/operations/sub/broadcast_row/sub_broadcast_row.onnx b/validation/operations/sub/broadcast_row/sub_broadcast_row.onnx new file mode 100644 index 0000000000000000000000000000000000000000..39e80a619db8b5f17923ced5a152e7f257d03528 GIT binary patch literal 130 zcmdj8tL{E=>{=EG|uoPb$h!Oi4~GE{QM7FW1uK;1FPRVs!FS z_K20^={qxT&?GMYeus_dlZh!Zu*Z!+NuJ02lUTPO53^YxMkBf(cQHXEL;o%yZ~B}AH)Cv literal 0 HcmV?d00001 diff --git a/validation/operations/sub/channel_broadcast_1024/sub_channel_broadcast_1024.onnx b/validation/operations/sub/channel_broadcast_1024/sub_channel_broadcast_1024.onnx new file mode 100644 index 0000000000000000000000000000000000000000..f37e916f9c00e3e015d5f05a5c106354fb70b1cd GIT binary patch literal 4231 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 literal 0 HcmV?d00001 diff --git a/validation/operations/sub/constant_lhs_broadcast/sub_constant_lhs_broadcast.onnx b/validation/operations/sub/constant_lhs_broadcast/sub_constant_lhs_broadcast.onnx new file mode 100644 index 0000000000000000000000000000000000000000..ec9995fd29a81857ebdde9def88d85e0782ff83f GIT binary patch literal 140 zcmd$Z}F-H literal 0 HcmV?d00001 diff --git a/validation/operations/sub/leading_dimension_broadcast/sub_leading_dimension_broadcast.onnx b/validation/operations/sub/leading_dimension_broadcast/sub_leading_dimension_broadcast.onnx new file mode 100644 index 0000000000000000000000000000000000000000..b757a010ff5cda8299b95c7ba7f5386279cfd27c GIT binary patch literal 136 zcmdj8tL{E=>}WFD^}r&q+;8$;?ZSPsz+p%`48#&x=ng%1=y5 zPAo3blH_0!V02=1@)9^JIm52(nAzTCshh10vOm~Gi380N65