-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[CIR] Implement folder for VecShuffleDynamicOp #142315
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-clang @llvm/pr-subscribers-clangir Author: Amr Hesham (AmrDeveloper) ChangesThis change adds a folder for the VecShuffleDynamicOp Issue #136487 Full diff: https://github.com/llvm/llvm-project/pull/142315.diff 4 Files Affected:
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 07851610a2abd..4442c3a5607ae 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -2188,6 +2188,7 @@ def VecShuffleDynamicOp : CIR_Op<"vec.shuffle.dynamic",
}];
let hasVerifier = 1;
+ let hasFolder = 1;
}
#endif // CLANG_CIR_DIALECT_IR_CIROPS_TD
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 36f050de9f8bb..90b32950e4774 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -1579,6 +1579,38 @@ OpFoldResult cir::VecExtractOp::fold(FoldAdaptor adaptor) {
// VecShuffleDynamicOp
//===----------------------------------------------------------------------===//
+OpFoldResult cir::VecShuffleDynamicOp::fold(FoldAdaptor adaptor) {
+ mlir::Attribute vec = adaptor.getVec();
+ mlir::Attribute indices = adaptor.getIndices();
+ if (mlir::isa_and_nonnull<cir::ConstVectorAttr>(vec) &&
+ mlir::isa_and_nonnull<cir::ConstVectorAttr>(indices)) {
+ auto vecAttr = mlir::cast<cir::ConstVectorAttr>(vec);
+ auto indicesAttr = mlir::cast<cir::ConstVectorAttr>(indices);
+ auto vecTy = cast<cir::VectorType>(vecAttr.getType());
+
+ mlir::ArrayAttr vecElts = vecAttr.getElts();
+ mlir::ArrayAttr indicesElts = indicesAttr.getElts();
+
+ const uint64_t numElements = vecElts.size();
+
+ SmallVector<mlir::Attribute, 16> elements;
+ elements.reserve(numElements);
+
+ const uint64_t maskBits = llvm::NextPowerOf2(numElements - 1) - 1;
+ for (uint64_t i = 0; i < numElements; i++) {
+ cir::IntAttr idxAttr = mlir::cast<cir::IntAttr>(indicesElts[i]);
+ uint64_t idxValue = idxAttr.getUInt();
+ uint64_t newIdx = idxValue & maskBits;
+ elements.push_back(vecElts[newIdx]);
+ }
+
+ return cir::ConstVectorAttr::get(
+ vecTy, mlir::ArrayAttr::get(getContext(), elements));
+ }
+
+ return {};
+}
+
LogicalResult cir::VecShuffleDynamicOp::verify() {
// The number of elements in the two input vectors must match.
if (getVec().getType().getSize() !=
diff --git a/clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp b/clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp
index fb000adee04c6..7d03e374c27e8 100644
--- a/clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp
@@ -138,10 +138,10 @@ void CIRCanonicalizePass::runOnOperation() {
assert(!cir::MissingFeatures::complexRealOp());
assert(!cir::MissingFeatures::complexImagOp());
assert(!cir::MissingFeatures::callOp());
- // CastOp, UnaryOp and VecExtractOp are here to perform a manual `fold` in
- // applyOpPatternsGreedily.
+ // CastOp, UnaryOp, VecExtractOp and VecShuffleDynamicOp are here to perform
+ // a manual `fold` in applyOpPatternsGreedily.
if (isa<BrOp, BrCondOp, CastOp, ScopeOp, SwitchOp, SelectOp, UnaryOp,
- VecExtractOp>(op))
+ VecExtractOp, VecShuffleDynamicOp>(op))
ops.push_back(op);
});
diff --git a/clang/test/CIR/Transforms/vector-shuffle-dynamic-fold.cir b/clang/test/CIR/Transforms/vector-shuffle-dynamic-fold.cir
new file mode 100644
index 0000000000000..db5d6bff04d5b
--- /dev/null
+++ b/clang/test/CIR/Transforms/vector-shuffle-dynamic-fold.cir
@@ -0,0 +1,18 @@
+// RUN: cir-opt %s -cir-canonicalize -o - | FileCheck %s
+
+!s32i = !cir.int<s, 32>
+
+module {
+ cir.func @fold_shuffle_dynamic_vector_op_test() {
+ %alloca = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["r", init]
+ %vec = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, #cir.int<3> : !s32i, #cir.int<4> : !s32i]> : !cir.vector<4 x !s32i>
+ %indices = cir.const #cir.const_vector<[#cir.int<8> : !s32i, #cir.int<7> : !s32i, #cir.int<6> : !s32i, #cir.int<5> : !s32i]> : !cir.vector<4 x !s32i>
+ %new_vec = cir.vec.shuffle.dynamic %vec : !cir.vector<4 x !s32i>, %indices : !cir.vector<4 x !s32i>
+ cir.store align(16) %new_vec, %alloca : !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>
+ cir.return
+ }
+
+ // CHECK: %[[NEW_VEC:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<4> : !s32i, #cir.int<3> : !s32i, #cir.int<2> : !s32i]> : !cir.vector<4 x !s32i>
+}
+
+
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Others should approve, but I only have 1 concern.
vecTy, mlir::ArrayAttr::get(getContext(), elements)); | ||
} | ||
|
||
return {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this branch have a 'not yet implemented' thing here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As far as I understood, no, it should be null because that means we can't fold VecShuffleDynamicOp
with non Const vec operands
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm + minor nits
for (uint64_t i = 0; i < numElements; i++) { | ||
cir::IntAttr idxAttr = mlir::cast<cir::IntAttr>(indicesElts[i]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might use getAsValueRange()
on indicesElts
to remove cast and use range for?
mlir::isa_and_nonnull<cir::ConstVectorAttr>(indices)) { | ||
auto vecAttr = mlir::cast<cir::ConstVectorAttr>(vec); | ||
auto indicesAttr = mlir::cast<cir::ConstVectorAttr>(indices); | ||
auto vecTy = cast<cir::VectorType>(vecAttr.getType()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
auto vecTy = cast<cir::VectorType>(vecAttr.getType()); | |
auto vecTy = mlir::cast<cir::VectorType>(vecAttr.getType()); |
for (const mlir::APInt &idxAttr : | ||
indicesElts.getAsValueRange<cir::IntAttr, mlir::APInt>()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does not work simply: for (const auto &idxAttr : indicesElts.getAsValueRange<cir::IntAttr>()) {
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or maybe use just getAsRange
ie.:
for (const auto &idxAttr : indicesElts.getAsRange<cir::IntAttr>()) {
and original uint64_t idxValue = idxAttr.getUInt();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does not work simply: for (const auto &idxAttr : indicesElts.getAsValueRangecir::IntAttr()) {?
Yes, it reports “Cannot form a reference to void”
I will use getAsRange
b3a2fed
to
ec7d646
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM w one nit
cir.return | ||
} | ||
|
||
// CHECK: %[[NEW_VEC:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<4> : !s32i, #cir.int<3> : !s32i, #cir.int<2> : !s32i]> : !cir.vector<4 x !s32i> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please change the testcase to return the vector instead of storing it and have a CHECK line that checks the return value is NEW_VEC
.
cir.return | ||
} | ||
|
||
// CHECK: %[[NEW_VEC:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<4> : !s32i, #cir.int<3> : !s32i, #cir.int<2> : !s32i]> : !cir.vector<4 x !s32i> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not obvious to me from this check what the full form of the transformed function will be. I assume we're getting rid of some dead instructions here, but that's not clear from the check. I'd suggest showing the full transformed function with CHECK-NEXT to verify that no unnecessary artifacts were left behind.
It isn't obvious at all why "8, 7, 6, 5" yielded the result here. I see that those values are ANDed with 3 to use "0, 3, 2, 1" as the shuffle indexes. Maybe add another test with indexes that don't require the mask and add a comment explaining the masking here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
This change adds a folder for the VecShuffleDynamicOp
Issue #136487