From c8f68cfd77f356a105c8f69592abc3d6d6168020 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Feb 2026 23:40:31 +0000 Subject: [PATCH 01/10] Initial plan From 219e255ccdb29c72efc3a8213a45a4134978dc40 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Feb 2026 23:45:36 +0000 Subject: [PATCH 02/10] Add EqualElementTypesOpTrait and apply to ExtractOp, BroadcastOp, PermuteOp, and RegisterOp Co-authored-by: ftynse <1512299+ftynse@users.noreply.github.com> --- .../water/Dialect/Wave/IR/WaveInterfaces.h | 13 +++++++ .../water/Dialect/Wave/IR/WaveInterfaces.td | 5 +++ .../include/water/Dialect/Wave/IR/WaveOps.td | 12 ++++--- water/lib/Dialect/Wave/IR/WaveInterfaces.cpp | 36 +++++++++++++++++++ water/lib/Dialect/Wave/IR/WaveOps.cpp | 22 ------------ 5 files changed, 62 insertions(+), 26 deletions(-) diff --git a/water/include/water/Dialect/Wave/IR/WaveInterfaces.h b/water/include/water/Dialect/Wave/IR/WaveInterfaces.h index 421340f82..2a9117382 100644 --- a/water/include/water/Dialect/Wave/IR/WaveInterfaces.h +++ b/water/include/water/Dialect/Wave/IR/WaveInterfaces.h @@ -266,6 +266,10 @@ verifyTypesMatchingDimensions(std::optional loc, // corresponding flag is set, compatible address spaces. llvm::LogicalResult verifyCompatibleOperandsAndResultsOpTrait( mlir::Operation *op, bool includeAddressSpace, bool includeElementalType); + +// Verification logic for the equal-element-types trait. Succeeds if all +// operands and results have the same element type. +llvm::LogicalResult verifyEqualElementTypesOpTrait(mlir::Operation *op); }; // namespace detail template @@ -301,6 +305,15 @@ class CompatibleOperandsAndResultsShapeOpTrait } }; +template +class EqualElementTypesOpTrait + : public mlir::OpTrait::TraitBase { +public: + static llvm::LogicalResult verifyTrait(mlir::Operation *op) { + return detail::verifyEqualElementTypesOpTrait(op); + } +}; + //----------------------------------------------------------------------------- // WaveElementsPerThreadOpInterface //----------------------------------------------------------------------------- diff --git a/water/include/water/Dialect/Wave/IR/WaveInterfaces.td b/water/include/water/Dialect/Wave/IR/WaveInterfaces.td index d8481f473..0c97a892b 100644 --- a/water/include/water/Dialect/Wave/IR/WaveInterfaces.td +++ b/water/include/water/Dialect/Wave/IR/WaveInterfaces.td @@ -181,6 +181,11 @@ def CompatibleOperandsAndResultsShapeOpTrait let cppNamespace = "::wave"; } +def EqualElementTypesOpTrait + : NativeOpTrait<"EqualElementTypesOpTrait"> { + let cppNamespace = "::wave"; +} + //----------------------------------------------------------------------------- // WaveInferIndexExprsOpInterface and implementation traits //----------------------------------------------------------------------------- diff --git a/water/include/water/Dialect/Wave/IR/WaveOps.td b/water/include/water/Dialect/Wave/IR/WaveOps.td index 5379d27a0..e24760575 100644 --- a/water/include/water/Dialect/Wave/IR/WaveOps.td +++ b/water/include/water/Dialect/Wave/IR/WaveOps.td @@ -373,7 +373,8 @@ def AllocateOp : WaveOp<"allocate", [ } def ExtractOp : WaveOp<"extract", - [DeclareOpInterfaceMethods]> { + [DeclareOpInterfaceMethods, + EqualElementTypesOpTrait]> { let summary = "Extracts a single element from a vector at the given index"; let description = [{ This is an internal operation that appears during expansion/lowering and @@ -477,7 +478,8 @@ def ReadOp : WaveOp<"read", [ def RegisterOp : WaveOp<"register", [ WaveInferTypeOpInterface, NoOpTypeInferenceOpTrait, NoOpElementsPerThreadOpTrait, - WaveInferIndexExprsOpInterface, IdentityIndexExprsOpTrait]> { + WaveInferIndexExprsOpInterface, IdentityIndexExprsOpTrait, + EqualElementTypesOpTrait]> { let summary = "Defines a tensor value known to be placed in a register"; let description = [{ Defines a new register-resident tensor initialized with the given scalar @@ -661,7 +663,8 @@ def CastOp : WaveOp<"cast", [ def BroadcastOp : WaveOp<"broadcast", [ DeclareOpInterfaceMethods, DeclareOpInterfaceMethods, - WaveInferIndexExprsOpInterface, IdentityIndexExprsOpTrait]> { + WaveInferIndexExprsOpInterface, IdentityIndexExprsOpTrait, + EqualElementTypesOpTrait]> { let summary = "Broadcast a tensor to a larger shape by replicating values"; let description = [{ Broadcasts the source tensor to the result shape by replicating values @@ -740,7 +743,8 @@ def SelfIndexOp : WaveOp<"self_index", [ def PermuteOp : WaveOp<"permute", [ DeclareOpInterfaceMethods, WaveElementsPerThreadOpInterface, IdentityElementsPerThreadOpTrait, - DeclareOpInterfaceMethods]> { + DeclareOpInterfaceMethods, + EqualElementTypesOpTrait]> { let summary = "Permute the dimensions of a register-resident tensor"; let description = [{ Reorders the symbolic dimensions of a register-resident tensor according diff --git a/water/lib/Dialect/Wave/IR/WaveInterfaces.cpp b/water/lib/Dialect/Wave/IR/WaveInterfaces.cpp index ee72f069d..6529dc525 100644 --- a/water/lib/Dialect/Wave/IR/WaveInterfaces.cpp +++ b/water/lib/Dialect/Wave/IR/WaveInterfaces.cpp @@ -685,6 +685,42 @@ llvm::LogicalResult wave::detail::verifyCompatibleOperandsAndResultsOpTrait( kResultNamePrefix, os.str()); } +llvm::LogicalResult wave::detail::verifyEqualElementTypesOpTrait( + Operation *op) { + if (op->getNumOperands() == 0 && op->getNumResults() == 0) + return llvm::success(); + + // Get the reference type from the first operand or result + Type referenceType; + std::string referenceName; + if (op->getNumOperands() > 0) { + referenceType = op->getOperandTypes()[0]; + referenceName = "operand #0"; + } else { + referenceType = op->getResultTypes()[0]; + referenceName = "result #0"; + } + + // Verify all operand element types match + for (auto [idx, operandType] : llvm::enumerate(op->getOperandTypes())) { + std::string operandName = "operand #" + std::to_string(idx); + if (failed(verifyElementTypesMatch(op->getLoc(), referenceName, + referenceType, operandName, + operandType))) + return llvm::failure(); + } + + // Verify all result element types match + for (auto [idx, resultType] : llvm::enumerate(op->getResultTypes())) { + std::string resultName = "result #" + std::to_string(idx); + if (failed(verifyElementTypesMatch(op->getLoc(), referenceName, + referenceType, resultName, resultType))) + return llvm::failure(); + } + + return llvm::success(); +} + //----------------------------------------------------------------------------- // Lattice implementation //----------------------------------------------------------------------------- diff --git a/water/lib/Dialect/Wave/IR/WaveOps.cpp b/water/lib/Dialect/Wave/IR/WaveOps.cpp index 547c07874..b5c386362 100644 --- a/water/lib/Dialect/Wave/IR/WaveOps.cpp +++ b/water/lib/Dialect/Wave/IR/WaveOps.cpp @@ -1669,13 +1669,6 @@ wave::ReadOp::propagateElementsPerThreadBackward( LogicalResult wave::RegisterOp::verify() { Type type = getResult().getType(); auto tensorType = dyn_cast(type); - auto elementType = tensorType ? tensorType.getElementType() - : cast(type).getElementType(); - Type initType = getInit().getType(); - if (elementType != initType) { - return emitOpError() << "expected the type of the init value to match the " - "elemental type of the result"; - } if (!tensorType) return success(); @@ -1715,12 +1708,6 @@ LogicalResult ExtractOp::verify() { << position.getRank(); } - if (failed(detail::verifyElementTypesMatch(getLoc(), "source", - getSource().getType(), "result", - getResult().getType()))) { - return failure(); - } - if (auto resultVectorType = dyn_cast(getResult().getType())) { if (resultVectorType.getShape()[0] != 1) { return emitOpError() << "result must be a 1-element vector, got " @@ -2151,11 +2138,6 @@ llvm::SmallVector wave::BroadcastOp::inferBroadcastDims() { } LogicalResult wave::BroadcastOp::verify() { - if (failed(detail::verifyElementTypesMatch(getLoc(), "source", - getSource().getType(), "result", - getResult().getType()))) - return failure(); - auto sourceType = llvm::dyn_cast(getSource().getType()); auto resultType = llvm::dyn_cast(getResult().getType()); @@ -2290,10 +2272,6 @@ LogicalResult wave::PermuteOp::verify() { Value input = getValue(); Value result = getResult(); - if (failed(detail::verifyElementTypesMatch(getLoc(), "input", input.getType(), - "result", result.getType()))) - return failure(); - auto inputType = dyn_cast(input.getType()); auto resultType = dyn_cast(result.getType()); From 20317565d29999a3b3d5062f093b2b5c05b9a15e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Feb 2026 23:47:05 +0000 Subject: [PATCH 03/10] Update test expectations for new EqualElementTypesOpTrait error messages Co-authored-by: ftynse <1512299+ftynse@users.noreply.github.com> --- water/test/Dialect/Wave/ops-invalid.mlir | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/water/test/Dialect/Wave/ops-invalid.mlir b/water/test/Dialect/Wave/ops-invalid.mlir index 0f2a3b662..d2f8410ec 100644 --- a/water/test/Dialect/Wave/ops-invalid.mlir +++ b/water/test/Dialect/Wave/ops-invalid.mlir @@ -63,7 +63,7 @@ func.func @invalid_register_type(%arg0: f32) { // ----- func.func @register_type_mismatch(%arg0: f32) { - // expected-error @below {{expected the type of the init value to match the elemental type of the result}} + // expected-error @below {{expected operand #0 and result #0 elemental types to match}} "wave.register"(%arg0) : (f32) -> !wave.tensor<[@A, @B] of bf16> } @@ -843,7 +843,7 @@ func.func @broadcast_explicit_dims_with_fully_specified_types(%arg0: !wave.tenso func.func @broadcast_element_type_mismatch(%arg0: !wave.tensor<[@M, @N] of f32, >) { // Source and result must have matching element types. - // expected-error @below {{expected source and result elemental types to match, got 'f32', 'f16'}} + // expected-error @below {{expected operand #0 and result #0 elemental types to match}} wave.broadcast %arg0 : (!wave.tensor<[@M, @N] of f32, >) -> !wave.tensor<[@M, @N, @K] of f16, > return } @@ -893,7 +893,7 @@ func.func @permute_empty_result_shape(%arg0: !wave.tensor<[@M, @N] of f32, >) { - // expected-error @below {{expected input and result elemental types to match, got 'f32', 'f16'}} + // expected-error @below {{expected operand #0 and result #0 elemental types to match}} wave.permute %arg0 : !wave.tensor<[@M, @N] of f32, > to !wave.tensor<[@N, @M] of f16, > return } From a3728ee7b678bd5e28f979ad6694a6b13e33edc8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Feb 2026 23:51:23 +0000 Subject: [PATCH 04/10] Address code review: avoid redundant element type checks Co-authored-by: ftynse <1512299+ftynse@users.noreply.github.com> --- water/lib/Dialect/Wave/IR/WaveInterfaces.cpp | 23 ++++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/water/lib/Dialect/Wave/IR/WaveInterfaces.cpp b/water/lib/Dialect/Wave/IR/WaveInterfaces.cpp index 6529dc525..73a10e60d 100644 --- a/water/lib/Dialect/Wave/IR/WaveInterfaces.cpp +++ b/water/lib/Dialect/Wave/IR/WaveInterfaces.cpp @@ -690,29 +690,38 @@ llvm::LogicalResult wave::detail::verifyEqualElementTypesOpTrait( if (op->getNumOperands() == 0 && op->getNumResults() == 0) return llvm::success(); - // Get the reference type from the first operand or result + // Get the reference type from the first operand if available, otherwise from + // the first result Type referenceType; std::string referenceName; + bool isOperandReference = false; if (op->getNumOperands() > 0) { referenceType = op->getOperandTypes()[0]; referenceName = "operand #0"; + isOperandReference = true; } else { referenceType = op->getResultTypes()[0]; referenceName = "result #0"; } - // Verify all operand element types match - for (auto [idx, operandType] : llvm::enumerate(op->getOperandTypes())) { - std::string operandName = "operand #" + std::to_string(idx); + // Verify all operand element types match (skip operand #0 if it's the + // reference to avoid redundant check) + unsigned startIdx = isOperandReference ? 1 : 0; + for (auto [idx, operandType] : + llvm::enumerate(op->getOperandTypes().drop_front(startIdx))) { + std::string operandName = "operand #" + std::to_string(idx + startIdx); if (failed(verifyElementTypesMatch(op->getLoc(), referenceName, referenceType, operandName, operandType))) return llvm::failure(); } - // Verify all result element types match - for (auto [idx, resultType] : llvm::enumerate(op->getResultTypes())) { - std::string resultName = "result #" + std::to_string(idx); + // Verify all result element types match (skip result #0 if it's the + // reference to avoid redundant check) + startIdx = !isOperandReference ? 1 : 0; + for (auto [idx, resultType] : + llvm::enumerate(op->getResultTypes().drop_front(startIdx))) { + std::string resultName = "result #" + std::to_string(idx + startIdx); if (failed(verifyElementTypesMatch(op->getLoc(), referenceName, referenceType, resultName, resultType))) return llvm::failure(); From 4fa1051b85a28a51752149339af3220b5171e52e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Feb 2026 23:51:55 +0000 Subject: [PATCH 05/10] Final verification and documentation Co-authored-by: ftynse <1512299+ftynse@users.noreply.github.com> --- _codeql_detected_source_root | 1 + 1 file changed, 1 insertion(+) create mode 120000 _codeql_detected_source_root diff --git a/_codeql_detected_source_root b/_codeql_detected_source_root new file mode 120000 index 000000000..945c9b46d --- /dev/null +++ b/_codeql_detected_source_root @@ -0,0 +1 @@ +. \ No newline at end of file From 52a3478078561af1bdc7717429a6348212e3df6d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Feb 2026 08:17:04 +0000 Subject: [PATCH 06/10] Fix build error: use llvm::Twine instead of std::to_string Co-authored-by: ftynse <1512299+ftynse@users.noreply.github.com> --- water/lib/Dialect/Wave/IR/WaveInterfaces.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/water/lib/Dialect/Wave/IR/WaveInterfaces.cpp b/water/lib/Dialect/Wave/IR/WaveInterfaces.cpp index 73a10e60d..b3cad97dd 100644 --- a/water/lib/Dialect/Wave/IR/WaveInterfaces.cpp +++ b/water/lib/Dialect/Wave/IR/WaveInterfaces.cpp @@ -709,10 +709,9 @@ llvm::LogicalResult wave::detail::verifyEqualElementTypesOpTrait( unsigned startIdx = isOperandReference ? 1 : 0; for (auto [idx, operandType] : llvm::enumerate(op->getOperandTypes().drop_front(startIdx))) { - std::string operandName = "operand #" + std::to_string(idx + startIdx); - if (failed(verifyElementTypesMatch(op->getLoc(), referenceName, - referenceType, operandName, - operandType))) + if (failed(verifyElementTypesMatch( + op->getLoc(), referenceName, referenceType, + "operand #" + llvm::Twine(idx + startIdx), operandType))) return llvm::failure(); } @@ -721,9 +720,9 @@ llvm::LogicalResult wave::detail::verifyEqualElementTypesOpTrait( startIdx = !isOperandReference ? 1 : 0; for (auto [idx, resultType] : llvm::enumerate(op->getResultTypes().drop_front(startIdx))) { - std::string resultName = "result #" + std::to_string(idx + startIdx); - if (failed(verifyElementTypesMatch(op->getLoc(), referenceName, - referenceType, resultName, resultType))) + if (failed(verifyElementTypesMatch( + op->getLoc(), referenceName, referenceType, + "result #" + llvm::Twine(idx + startIdx), resultType))) return llvm::failure(); } From 05744cf0d9b883c5d1b915e7bbaebb546cca9c2c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Feb 2026 09:27:25 +0000 Subject: [PATCH 07/10] Fix build error: use traditional for loops instead of drop_front on ValueTypeRange Co-authored-by: ftynse <1512299+ftynse@users.noreply.github.com> --- water/lib/Dialect/Wave/IR/WaveInterfaces.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/water/lib/Dialect/Wave/IR/WaveInterfaces.cpp b/water/lib/Dialect/Wave/IR/WaveInterfaces.cpp index b3cad97dd..928869536 100644 --- a/water/lib/Dialect/Wave/IR/WaveInterfaces.cpp +++ b/water/lib/Dialect/Wave/IR/WaveInterfaces.cpp @@ -707,22 +707,20 @@ llvm::LogicalResult wave::detail::verifyEqualElementTypesOpTrait( // Verify all operand element types match (skip operand #0 if it's the // reference to avoid redundant check) unsigned startIdx = isOperandReference ? 1 : 0; - for (auto [idx, operandType] : - llvm::enumerate(op->getOperandTypes().drop_front(startIdx))) { + for (unsigned idx = startIdx; idx < op->getNumOperands(); ++idx) { if (failed(verifyElementTypesMatch( op->getLoc(), referenceName, referenceType, - "operand #" + llvm::Twine(idx + startIdx), operandType))) + "operand #" + llvm::Twine(idx), op->getOperandTypes()[idx]))) return llvm::failure(); } // Verify all result element types match (skip result #0 if it's the // reference to avoid redundant check) startIdx = !isOperandReference ? 1 : 0; - for (auto [idx, resultType] : - llvm::enumerate(op->getResultTypes().drop_front(startIdx))) { + for (unsigned idx = startIdx; idx < op->getNumResults(); ++idx) { if (failed(verifyElementTypesMatch( op->getLoc(), referenceName, referenceType, - "result #" + llvm::Twine(idx + startIdx), resultType))) + "result #" + llvm::Twine(idx), op->getResultTypes()[idx]))) return llvm::failure(); } From ee783f38326e96b013ad2d6c72ad8913692e4afc Mon Sep 17 00:00:00 2001 From: Alex Zinenko Date: Fri, 20 Feb 2026 14:16:26 +0100 Subject: [PATCH 08/10] don't use it for register Signed-off-by: Alex Zinenko --- water/include/water/Dialect/Wave/IR/WaveOps.td | 3 +-- water/lib/Dialect/Wave/IR/WaveInterfaces.cpp | 8 ++++---- water/lib/Dialect/Wave/IR/WaveOps.cpp | 7 +++++++ water/test/Dialect/Wave/ops-invalid.mlir | 2 +- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/water/include/water/Dialect/Wave/IR/WaveOps.td b/water/include/water/Dialect/Wave/IR/WaveOps.td index e24760575..d26e1a167 100644 --- a/water/include/water/Dialect/Wave/IR/WaveOps.td +++ b/water/include/water/Dialect/Wave/IR/WaveOps.td @@ -478,8 +478,7 @@ def ReadOp : WaveOp<"read", [ def RegisterOp : WaveOp<"register", [ WaveInferTypeOpInterface, NoOpTypeInferenceOpTrait, NoOpElementsPerThreadOpTrait, - WaveInferIndexExprsOpInterface, IdentityIndexExprsOpTrait, - EqualElementTypesOpTrait]> { + WaveInferIndexExprsOpInterface, IdentityIndexExprsOpTrait]> { let summary = "Defines a tensor value known to be placed in a register"; let description = [{ Defines a new register-resident tensor initialized with the given scalar diff --git a/water/lib/Dialect/Wave/IR/WaveInterfaces.cpp b/water/lib/Dialect/Wave/IR/WaveInterfaces.cpp index 928869536..70d2a5197 100644 --- a/water/lib/Dialect/Wave/IR/WaveInterfaces.cpp +++ b/water/lib/Dialect/Wave/IR/WaveInterfaces.cpp @@ -685,8 +685,8 @@ llvm::LogicalResult wave::detail::verifyCompatibleOperandsAndResultsOpTrait( kResultNamePrefix, os.str()); } -llvm::LogicalResult wave::detail::verifyEqualElementTypesOpTrait( - Operation *op) { +llvm::LogicalResult +wave::detail::verifyEqualElementTypesOpTrait(Operation *op) { if (op->getNumOperands() == 0 && op->getNumResults() == 0) return llvm::success(); @@ -710,7 +710,7 @@ llvm::LogicalResult wave::detail::verifyEqualElementTypesOpTrait( for (unsigned idx = startIdx; idx < op->getNumOperands(); ++idx) { if (failed(verifyElementTypesMatch( op->getLoc(), referenceName, referenceType, - "operand #" + llvm::Twine(idx), op->getOperandTypes()[idx]))) + "operand #" + std::to_string(idx), op->getOperandTypes()[idx]))) return llvm::failure(); } @@ -720,7 +720,7 @@ llvm::LogicalResult wave::detail::verifyEqualElementTypesOpTrait( for (unsigned idx = startIdx; idx < op->getNumResults(); ++idx) { if (failed(verifyElementTypesMatch( op->getLoc(), referenceName, referenceType, - "result #" + llvm::Twine(idx), op->getResultTypes()[idx]))) + "result #" + std::to_string(idx), op->getResultTypes()[idx]))) return llvm::failure(); } diff --git a/water/lib/Dialect/Wave/IR/WaveOps.cpp b/water/lib/Dialect/Wave/IR/WaveOps.cpp index b5c386362..7af3296db 100644 --- a/water/lib/Dialect/Wave/IR/WaveOps.cpp +++ b/water/lib/Dialect/Wave/IR/WaveOps.cpp @@ -1669,6 +1669,13 @@ wave::ReadOp::propagateElementsPerThreadBackward( LogicalResult wave::RegisterOp::verify() { Type type = getResult().getType(); auto tensorType = dyn_cast(type); + auto elementType = tensorType ? tensorType.getElementType() + : cast(type).getElementType(); + Type initType = getInit().getType(); + if (elementType != initType) { + return emitOpError() << "expected the type of the init value to match the " + "elemental type of the result"; + } if (!tensorType) return success(); diff --git a/water/test/Dialect/Wave/ops-invalid.mlir b/water/test/Dialect/Wave/ops-invalid.mlir index d2f8410ec..0cedc1a6e 100644 --- a/water/test/Dialect/Wave/ops-invalid.mlir +++ b/water/test/Dialect/Wave/ops-invalid.mlir @@ -63,7 +63,7 @@ func.func @invalid_register_type(%arg0: f32) { // ----- func.func @register_type_mismatch(%arg0: f32) { - // expected-error @below {{expected operand #0 and result #0 elemental types to match}} + // expected-error @below {{expected the type of the init value to match the elemental type of the result}} "wave.register"(%arg0) : (f32) -> !wave.tensor<[@A, @B] of bf16> } From d66de9e55c33d3cdcc730c6c166e04d92da1186b Mon Sep 17 00:00:00 2001 From: Alex Zinenko Date: Fri, 20 Feb 2026 14:16:58 +0100 Subject: [PATCH 09/10] drop artefact Signed-off-by: Alex Zinenko --- _codeql_detected_source_root | 1 - 1 file changed, 1 deletion(-) delete mode 120000 _codeql_detected_source_root diff --git a/_codeql_detected_source_root b/_codeql_detected_source_root deleted file mode 120000 index 945c9b46d..000000000 --- a/_codeql_detected_source_root +++ /dev/null @@ -1 +0,0 @@ -. \ No newline at end of file From 0b07423d8e88b4b48fb87010861f3c828a15cdbe Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Feb 2026 13:50:29 +0000 Subject: [PATCH 10/10] Use llvm::StringRef and llvm::Twine, add ExtractOp negative test - Changed std::string to llvm::StringRef for referenceName - Changed std::to_string to llvm::Twine for string concatenation - Added negative test for ExtractOp element type mismatch Co-authored-by: martin-luecke <16363540+martin-luecke@users.noreply.github.com> --- water/lib/Dialect/Wave/IR/WaveInterfaces.cpp | 6 +++--- water/test/Dialect/Wave/ops-invalid.mlir | 8 ++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/water/lib/Dialect/Wave/IR/WaveInterfaces.cpp b/water/lib/Dialect/Wave/IR/WaveInterfaces.cpp index 70d2a5197..977a17dd2 100644 --- a/water/lib/Dialect/Wave/IR/WaveInterfaces.cpp +++ b/water/lib/Dialect/Wave/IR/WaveInterfaces.cpp @@ -693,7 +693,7 @@ wave::detail::verifyEqualElementTypesOpTrait(Operation *op) { // Get the reference type from the first operand if available, otherwise from // the first result Type referenceType; - std::string referenceName; + llvm::StringRef referenceName; bool isOperandReference = false; if (op->getNumOperands() > 0) { referenceType = op->getOperandTypes()[0]; @@ -710,7 +710,7 @@ wave::detail::verifyEqualElementTypesOpTrait(Operation *op) { for (unsigned idx = startIdx; idx < op->getNumOperands(); ++idx) { if (failed(verifyElementTypesMatch( op->getLoc(), referenceName, referenceType, - "operand #" + std::to_string(idx), op->getOperandTypes()[idx]))) + "operand #" + llvm::Twine(idx), op->getOperandTypes()[idx]))) return llvm::failure(); } @@ -720,7 +720,7 @@ wave::detail::verifyEqualElementTypesOpTrait(Operation *op) { for (unsigned idx = startIdx; idx < op->getNumResults(); ++idx) { if (failed(verifyElementTypesMatch( op->getLoc(), referenceName, referenceType, - "result #" + std::to_string(idx), op->getResultTypes()[idx]))) + "result #" + llvm::Twine(idx), op->getResultTypes()[idx]))) return llvm::failure(); } diff --git a/water/test/Dialect/Wave/ops-invalid.mlir b/water/test/Dialect/Wave/ops-invalid.mlir index 0cedc1a6e..a1682c596 100644 --- a/water/test/Dialect/Wave/ops-invalid.mlir +++ b/water/test/Dialect/Wave/ops-invalid.mlir @@ -599,6 +599,14 @@ func.func @extract_dimension_mismatch(%src: !wave.tensor<[@M, @N] of f32>) { // ----- +func.func @extract_element_type_mismatch(%src: !wave.tensor<[@M, @N] of f32>) { + // expected-error @below {{expected operand #0 and result #0 elemental types to match}} + %0 = wave.extract %src[#wave.expr_list<[] -> (0)>] : (!wave.tensor<[@M, @N] of f32>) -> !wave.tensor<[@M] of f16> + return +} + +// ----- + func.func @extract_slice_mismatch_offset_size(%memory: !wave.tensor<[@A, @B] of f16>) { // expected-error @below {{offset, size, and stride must all have the same rank, but got offset rank 1, size rank 2, and stride rank 1}} wave.extract_slice %memory {offset = #wave.expr_list<[] -> (3)>, size = #wave.expr_list<[] -> (32, 16)>, stride = #wave.expr_list<[] -> (2)>} : (!wave.tensor<[@A, @B] of f16>) -> !wave.tensor<[@A, @B] of f16>