-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[CIR] Upstream ShuffleOp for VectorType #142288
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
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-clang Author: Amr Hesham (AmrDeveloper) ChangesThis change adds support for the Shuffle op for VectorType Issue #136487 Full diff: https://github.com/llvm/llvm-project/pull/142288.diff 8 Files Affected:
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 07851610a2abd..c176719941fc6 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -2156,6 +2156,50 @@ def VecCmpOp : CIR_Op<"vec.cmp", [Pure, SameTypeOperands]> {
}];
}
+//===----------------------------------------------------------------------===//
+// VecShuffleOp
+//===----------------------------------------------------------------------===//
+
+// TODO: Create an interface that both VecShuffleOp and VecShuffleDynamicOp
+// implement. This could be useful for passes that don't care how the vector
+// shuffle was specified.
+
+def VecShuffleOp : CIR_Op<"vec.shuffle",
+ [Pure, AllTypesMatch<["vec1", "vec2"]>]> {
+ let summary = "Combine two vectors using indices passed as constant integers";
+ let description = [{
+ The `cir.vec.shuffle` operation implements the documented form of Clang's
+ __builtin_shufflevector, where the indices of the shuffled result are
+ integer constants.
+
+ The two input vectors, which must have the same type, are concatenated.
+ Each of the integer constant arguments is interpreted as an index into that
+ concatenated vector, with a value of -1 meaning that the result value
+ doesn't matter. The result vector, which must have the same element type as
+ the input vectors and the same number of elements as the list of integer
+ constant indices, is constructed by taking the elements at the given
+ indices from the concatenated vector.
+
+ ```mlir
+ %new_vec = cir.vec.shuffle(%vec_1, %vec_2 : !cir.vector<2 x !s32i>)
+ [#cir.int<3> : !s64i, #cir.int<1> : !s64i] : !cir.vector<2 x !s32i>
+ ```
+ }];
+
+ let arguments = (ins
+ CIR_VectorType:$vec1,
+ CIR_VectorType:$vec2,
+ TypedArrayAttrBase<IntAttr, "Integer array attribute">:$indices
+ );
+
+ let results = (outs CIR_VectorType:$result);
+ let assemblyFormat = [{
+ `(` $vec1 `,` $vec2 `:` qualified(type($vec1)) `)` $indices `:`
+ qualified(type($result)) attr-dict
+ }];
+ let hasVerifier = 1;
+}
+
//===----------------------------------------------------------------------===//
// VecShuffleDynamicOp
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 8448c164a5e58..4b7dd75457d6a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -180,9 +180,24 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
cgf.getLoc(e->getSourceRange()), inputVec, indexVec);
}
- cgf.getCIRGenModule().errorNYI(e->getSourceRange(),
- "ShuffleVectorExpr with indices");
- return {};
+ mlir::Value vec1 = Visit(e->getExpr(0));
+ mlir::Value vec2 = Visit(e->getExpr(1));
+
+ // The documented form of __builtin_shufflevector, where the indices are
+ // a variable number of integer constants. The constants will be stored
+ // in an ArrayAttr.
+ SmallVector<mlir::Attribute, 8> indices;
+ for (unsigned i = 2; i < e->getNumSubExprs(); ++i) {
+ indices.push_back(
+ cir::IntAttr::get(cgf.builder.getSInt64Ty(),
+ e->getExpr(i)
+ ->EvaluateKnownConstInt(cgf.getContext())
+ .getSExtValue()));
+ }
+
+ return cgf.builder.create<cir::VecShuffleOp>(
+ cgf.getLoc(e->getSourceRange()), cgf.convertType(e->getType()), vec1,
+ vec2, cgf.builder.getArrayAttr(indices));
}
mlir::Value VisitConvertVectorExpr(ConvertVectorExpr *e) {
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 36f050de9f8bb..8ca150cba975c 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -21,6 +21,7 @@
#include "clang/CIR/Dialect/IR/CIROpsDialect.cpp.inc"
#include "clang/CIR/Dialect/IR/CIROpsEnums.cpp.inc"
#include "clang/CIR/MissingFeatures.h"
+
#include <numeric>
using namespace mlir;
@@ -1575,6 +1576,29 @@ OpFoldResult cir::VecExtractOp::fold(FoldAdaptor adaptor) {
return elements[index];
}
+//===----------------------------------------------------------------------===//
+// VecShuffle
+//===----------------------------------------------------------------------===//
+
+LogicalResult cir::VecShuffleOp::verify() {
+ // The number of elements in the indices array must match the number of
+ // elements in the result type.
+ if (getIndices().size() != getResult().getType().getSize()) {
+ return emitOpError() << ": the number of elements in " << getIndices()
+ << " and " << getResult().getType() << " don't match";
+ }
+
+ // The element types of the two input vectors and of the result type must
+ // match.
+ if (getVec1().getType().getElementType() !=
+ getResult().getType().getElementType()) {
+ return emitOpError() << ": element types of " << getVec1().getType()
+ << " and " << getResult().getType() << " don't match";
+ }
+
+ return success();
+}
+
//===----------------------------------------------------------------------===//
// VecShuffleDynamicOp
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index b07e61638c3b4..80803aec9a6c2 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -1708,6 +1708,7 @@ void ConvertCIRToLLVMPass::runOnOperation() {
CIRToLLVMVecExtractOpLowering,
CIRToLLVMVecInsertOpLowering,
CIRToLLVMVecCmpOpLowering,
+ CIRToLLVMVecShuffleOpLowering,
CIRToLLVMVecShuffleDynamicOpLowering
// clang-format on
>(converter, patterns.getContext());
@@ -1862,6 +1863,23 @@ mlir::LogicalResult CIRToLLVMVecCmpOpLowering::matchAndRewrite(
return mlir::success();
}
+mlir::LogicalResult CIRToLLVMVecShuffleOpLowering::matchAndRewrite(
+ cir::VecShuffleOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ // LLVM::ShuffleVectorOp takes an ArrayRef of int for the list of indices.
+ // Convert the ClangIR ArrayAttr of IntAttr constants into a
+ // SmallVector<int>.
+ SmallVector<int, 8> indices;
+ std::transform(
+ op.getIndices().begin(), op.getIndices().end(),
+ std::back_inserter(indices), [](mlir::Attribute intAttr) {
+ return mlir::cast<cir::IntAttr>(intAttr).getValue().getSExtValue();
+ });
+ rewriter.replaceOpWithNewOp<mlir::LLVM::ShuffleVectorOp>(
+ op, adaptor.getVec1(), adaptor.getVec2(), indices);
+ return mlir::success();
+}
+
mlir::LogicalResult CIRToLLVMVecShuffleDynamicOpLowering::matchAndRewrite(
cir::VecShuffleDynamicOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
index 6b8862db2c8be..4d37dfbc74227 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
@@ -352,6 +352,16 @@ class CIRToLLVMVecCmpOpLowering
mlir::ConversionPatternRewriter &) const override;
};
+class CIRToLLVMVecShuffleOpLowering
+ : public mlir::OpConversionPattern<cir::VecShuffleOp> {
+public:
+ using mlir::OpConversionPattern<cir::VecShuffleOp>::OpConversionPattern;
+
+ mlir::LogicalResult
+ matchAndRewrite(cir::VecShuffleOp op, OpAdaptor,
+ mlir::ConversionPatternRewriter &) const override;
+};
+
class CIRToLLVMVecShuffleDynamicOpLowering
: public mlir::OpConversionPattern<cir::VecShuffleDynamicOp> {
public:
diff --git a/clang/test/CIR/CodeGen/vector-ext.cpp b/clang/test/CIR/CodeGen/vector-ext.cpp
index 8a0479fc1d088..aa836c2e70a12 100644
--- a/clang/test/CIR/CodeGen/vector-ext.cpp
+++ b/clang/test/CIR/CodeGen/vector-ext.cpp
@@ -1091,3 +1091,28 @@ void foo17() {
// OGCG: %[[VEC_A:.*]] = alloca <2 x double>, align 16
// OGCG: %[[TMP:.*]] = load <2 x double>, ptr %[[VEC_A]], align 16
// OGCG: %[[RES:.*]]= fptoui <2 x double> %[[TMP]] to <2 x i16>
+
+void foo19() {
+ vi4 a;
+ vi4 b;
+ vi4 u = __builtin_shufflevector(a, b, 7, 5, 3, 1);
+}
+
+// CIR: %[[VEC_A:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["a"]
+// CIR: %[[VEC_B:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["b"]
+// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[VEC_A]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i>
+// CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[VEC_B]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i>
+// CIR: %[[SHUF:.*]] = cir.vec.shuffle(%[[TMP_A]], %[[TMP_B]] : !cir.vector<4 x !s32i>) [#cir.int<7> :
+// CIR-SAME: !s64i, #cir.int<5> : !s64i, #cir.int<3> : !s64i, #cir.int<1> : !s64i] : !cir.vector<4 x !s32i>
+
+// LLVM: %[[VEC_A:.*]] = alloca <4 x i32>, i64 1, align 16
+// LLVM: %[[VEC_B:.*]] = alloca <4 x i32>, i64 1, align 16
+// LLVM: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[VEC_A]], align 16
+// LLVM: %[[TMP_B:.*]] = load <4 x i32>, ptr %[[VEC_B]], align 16
+// LLVM: %[[SHUF:.*]] = shufflevector <4 x i32> %[[TMP_A]], <4 x i32> %[[TMP_B]], <4 x i32> <i32 7, i32 5, i32 3, i32 1>
+
+// OGCG: %[[VEC_A:.*]] = alloca <4 x i32>, align 16
+// OGCG: %[[VEC_B:.*]] = alloca <4 x i32>, align 16
+// OGCG: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[VEC_A]], align 16
+// OGCG: %[[TMP_B:.*]] = load <4 x i32>, ptr %[[VEC_B]], align 16
+// OGCG: %[[SHUF:.*]] = shufflevector <4 x i32> %[[TMP_A]], <4 x i32> %[[TMP_B]], <4 x i32> <i32 7, i32 5, i32 3, i32 1>
diff --git a/clang/test/CIR/CodeGen/vector.cpp b/clang/test/CIR/CodeGen/vector.cpp
index 4c50f68a56162..fe69d3ae6e579 100644
--- a/clang/test/CIR/CodeGen/vector.cpp
+++ b/clang/test/CIR/CodeGen/vector.cpp
@@ -1069,4 +1069,29 @@ void foo17() {
// OGCG: %[[VEC_A:.*]] = alloca <2 x double>, align 16
// OGCG: %[[TMP:.*]] = load <2 x double>, ptr %[[VEC_A]], align 16
-// OGCG: %[[RES:.*]]= fptoui <2 x double> %[[TMP]] to <2 x i16>
\ No newline at end of file
+// OGCG: %[[RES:.*]]= fptoui <2 x double> %[[TMP]] to <2 x i16>
+
+void foo19() {
+ vi4 a;
+ vi4 b;
+ vi4 u = __builtin_shufflevector(a, b, 7, 5, 3, 1);
+}
+
+// CIR: %[[VEC_A:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["a"]
+// CIR: %[[VEC_B:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["b"]
+// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[VEC_A]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i>
+// CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[VEC_B]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i>
+// CIR: %[[SHUF:.*]] = cir.vec.shuffle(%[[TMP_A]], %[[TMP_B]] : !cir.vector<4 x !s32i>) [#cir.int<7> :
+// CIR-SAME: !s64i, #cir.int<5> : !s64i, #cir.int<3> : !s64i, #cir.int<1> : !s64i] : !cir.vector<4 x !s32i>
+
+// LLVM: %[[VEC_A:.*]] = alloca <4 x i32>, i64 1, align 16
+// LLVM: %[[VEC_B:.*]] = alloca <4 x i32>, i64 1, align 16
+// LLVM: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[VEC_A]], align 16
+// LLVM: %[[TMP_B:.*]] = load <4 x i32>, ptr %[[VEC_B]], align 16
+// LLVM: %[[SHUF:.*]] = shufflevector <4 x i32> %[[TMP_A]], <4 x i32> %[[TMP_B]], <4 x i32> <i32 7, i32 5, i32 3, i32 1>
+
+// OGCG: %[[VEC_A:.*]] = alloca <4 x i32>, align 16
+// OGCG: %[[VEC_B:.*]] = alloca <4 x i32>, align 16
+// OGCG: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[VEC_A]], align 16
+// OGCG: %[[TMP_B:.*]] = load <4 x i32>, ptr %[[VEC_B]], align 16
+// OGCG: %[[SHUF:.*]] = shufflevector <4 x i32> %[[TMP_A]], <4 x i32> %[[TMP_B]], <4 x i32> <i32 7, i32 5, i32 3, i32 1>
diff --git a/clang/test/CIR/IR/invalid-vector.cir b/clang/test/CIR/IR/invalid-vector.cir
index d94eacedec1f5..4ff9e47b12ba4 100644
--- a/clang/test/CIR/IR/invalid-vector.cir
+++ b/clang/test/CIR/IR/invalid-vector.cir
@@ -8,3 +8,41 @@ module {
cir.global external @vec_b = #cir.zero : !cir.vector<4 x !cir.array<!s32i x 10>>
}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+!s64i = !cir.int<s, 64>
+
+module {
+ cir.func @invalid_vector_shuffle() {
+ %1 = cir.const #cir.int<1> : !s32i
+ %2 = cir.const #cir.int<2> : !s32i
+ %3 = cir.const #cir.int<3> : !s32i
+ %4 = cir.const #cir.int<4> : !s32i
+ %vec_1 = cir.vec.create(%1, %2, %3, %4 : !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i>
+ %vec_2 = cir.vec.create(%1, %2, %3, %4 : !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i>
+ // expected-error @below {{element types of '!cir.vector<4 x !cir.int<s, 32>>' and '!cir.vector<4 x !cir.int<s, 64>>' don't match}}
+ %new_vec = cir.vec.shuffle(%vec_1, %vec_2 : !cir.vector<4 x !s32i>) [#cir.int<7> : !s64i, #cir.int<5> : !s64i, #cir.int<3> : !s64i, #cir.int<1> : !s64i] : !cir.vector<4 x !s64i>
+ cir.return
+ }
+}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+!s64i = !cir.int<s, 64>
+
+module {
+ cir.func @invalid_vector_shuffle() {
+ %1 = cir.const #cir.int<1> : !s32i
+ %2 = cir.const #cir.int<2> : !s32i
+ %3 = cir.const #cir.int<3> : !s32i
+ %4 = cir.const #cir.int<4> : !s32i
+ %vec_1 = cir.vec.create(%1, %2, %3, %4 : !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i>
+ %vec_2 = cir.vec.create(%1, %2, %3, %4 : !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i>
+ // expected-error @below {{the number of elements in [#cir.int<7> : !cir.int<s, 64>, #cir.int<5> : !cir.int<s, 64>, #cir.int<3> : !cir.int<s, 64>] and '!cir.vector<4 x !cir.int<s, 64>>' don't match}}
+ %new_vec = cir.vec.shuffle(%vec_1, %vec_2 : !cir.vector<4 x !s32i>) [#cir.int<7> : !s64i, #cir.int<5> : !s64i, #cir.int<3> : !s64i] : !cir.vector<4 x !s64i>
+ cir.return
+ }
+}
|
@llvm/pr-subscribers-clangir Author: Amr Hesham (AmrDeveloper) ChangesThis change adds support for the Shuffle op for VectorType Issue #136487 Full diff: https://github.com/llvm/llvm-project/pull/142288.diff 8 Files Affected:
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 07851610a2abd..c176719941fc6 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -2156,6 +2156,50 @@ def VecCmpOp : CIR_Op<"vec.cmp", [Pure, SameTypeOperands]> {
}];
}
+//===----------------------------------------------------------------------===//
+// VecShuffleOp
+//===----------------------------------------------------------------------===//
+
+// TODO: Create an interface that both VecShuffleOp and VecShuffleDynamicOp
+// implement. This could be useful for passes that don't care how the vector
+// shuffle was specified.
+
+def VecShuffleOp : CIR_Op<"vec.shuffle",
+ [Pure, AllTypesMatch<["vec1", "vec2"]>]> {
+ let summary = "Combine two vectors using indices passed as constant integers";
+ let description = [{
+ The `cir.vec.shuffle` operation implements the documented form of Clang's
+ __builtin_shufflevector, where the indices of the shuffled result are
+ integer constants.
+
+ The two input vectors, which must have the same type, are concatenated.
+ Each of the integer constant arguments is interpreted as an index into that
+ concatenated vector, with a value of -1 meaning that the result value
+ doesn't matter. The result vector, which must have the same element type as
+ the input vectors and the same number of elements as the list of integer
+ constant indices, is constructed by taking the elements at the given
+ indices from the concatenated vector.
+
+ ```mlir
+ %new_vec = cir.vec.shuffle(%vec_1, %vec_2 : !cir.vector<2 x !s32i>)
+ [#cir.int<3> : !s64i, #cir.int<1> : !s64i] : !cir.vector<2 x !s32i>
+ ```
+ }];
+
+ let arguments = (ins
+ CIR_VectorType:$vec1,
+ CIR_VectorType:$vec2,
+ TypedArrayAttrBase<IntAttr, "Integer array attribute">:$indices
+ );
+
+ let results = (outs CIR_VectorType:$result);
+ let assemblyFormat = [{
+ `(` $vec1 `,` $vec2 `:` qualified(type($vec1)) `)` $indices `:`
+ qualified(type($result)) attr-dict
+ }];
+ let hasVerifier = 1;
+}
+
//===----------------------------------------------------------------------===//
// VecShuffleDynamicOp
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 8448c164a5e58..4b7dd75457d6a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -180,9 +180,24 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
cgf.getLoc(e->getSourceRange()), inputVec, indexVec);
}
- cgf.getCIRGenModule().errorNYI(e->getSourceRange(),
- "ShuffleVectorExpr with indices");
- return {};
+ mlir::Value vec1 = Visit(e->getExpr(0));
+ mlir::Value vec2 = Visit(e->getExpr(1));
+
+ // The documented form of __builtin_shufflevector, where the indices are
+ // a variable number of integer constants. The constants will be stored
+ // in an ArrayAttr.
+ SmallVector<mlir::Attribute, 8> indices;
+ for (unsigned i = 2; i < e->getNumSubExprs(); ++i) {
+ indices.push_back(
+ cir::IntAttr::get(cgf.builder.getSInt64Ty(),
+ e->getExpr(i)
+ ->EvaluateKnownConstInt(cgf.getContext())
+ .getSExtValue()));
+ }
+
+ return cgf.builder.create<cir::VecShuffleOp>(
+ cgf.getLoc(e->getSourceRange()), cgf.convertType(e->getType()), vec1,
+ vec2, cgf.builder.getArrayAttr(indices));
}
mlir::Value VisitConvertVectorExpr(ConvertVectorExpr *e) {
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 36f050de9f8bb..8ca150cba975c 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -21,6 +21,7 @@
#include "clang/CIR/Dialect/IR/CIROpsDialect.cpp.inc"
#include "clang/CIR/Dialect/IR/CIROpsEnums.cpp.inc"
#include "clang/CIR/MissingFeatures.h"
+
#include <numeric>
using namespace mlir;
@@ -1575,6 +1576,29 @@ OpFoldResult cir::VecExtractOp::fold(FoldAdaptor adaptor) {
return elements[index];
}
+//===----------------------------------------------------------------------===//
+// VecShuffle
+//===----------------------------------------------------------------------===//
+
+LogicalResult cir::VecShuffleOp::verify() {
+ // The number of elements in the indices array must match the number of
+ // elements in the result type.
+ if (getIndices().size() != getResult().getType().getSize()) {
+ return emitOpError() << ": the number of elements in " << getIndices()
+ << " and " << getResult().getType() << " don't match";
+ }
+
+ // The element types of the two input vectors and of the result type must
+ // match.
+ if (getVec1().getType().getElementType() !=
+ getResult().getType().getElementType()) {
+ return emitOpError() << ": element types of " << getVec1().getType()
+ << " and " << getResult().getType() << " don't match";
+ }
+
+ return success();
+}
+
//===----------------------------------------------------------------------===//
// VecShuffleDynamicOp
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index b07e61638c3b4..80803aec9a6c2 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -1708,6 +1708,7 @@ void ConvertCIRToLLVMPass::runOnOperation() {
CIRToLLVMVecExtractOpLowering,
CIRToLLVMVecInsertOpLowering,
CIRToLLVMVecCmpOpLowering,
+ CIRToLLVMVecShuffleOpLowering,
CIRToLLVMVecShuffleDynamicOpLowering
// clang-format on
>(converter, patterns.getContext());
@@ -1862,6 +1863,23 @@ mlir::LogicalResult CIRToLLVMVecCmpOpLowering::matchAndRewrite(
return mlir::success();
}
+mlir::LogicalResult CIRToLLVMVecShuffleOpLowering::matchAndRewrite(
+ cir::VecShuffleOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ // LLVM::ShuffleVectorOp takes an ArrayRef of int for the list of indices.
+ // Convert the ClangIR ArrayAttr of IntAttr constants into a
+ // SmallVector<int>.
+ SmallVector<int, 8> indices;
+ std::transform(
+ op.getIndices().begin(), op.getIndices().end(),
+ std::back_inserter(indices), [](mlir::Attribute intAttr) {
+ return mlir::cast<cir::IntAttr>(intAttr).getValue().getSExtValue();
+ });
+ rewriter.replaceOpWithNewOp<mlir::LLVM::ShuffleVectorOp>(
+ op, adaptor.getVec1(), adaptor.getVec2(), indices);
+ return mlir::success();
+}
+
mlir::LogicalResult CIRToLLVMVecShuffleDynamicOpLowering::matchAndRewrite(
cir::VecShuffleDynamicOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
index 6b8862db2c8be..4d37dfbc74227 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
@@ -352,6 +352,16 @@ class CIRToLLVMVecCmpOpLowering
mlir::ConversionPatternRewriter &) const override;
};
+class CIRToLLVMVecShuffleOpLowering
+ : public mlir::OpConversionPattern<cir::VecShuffleOp> {
+public:
+ using mlir::OpConversionPattern<cir::VecShuffleOp>::OpConversionPattern;
+
+ mlir::LogicalResult
+ matchAndRewrite(cir::VecShuffleOp op, OpAdaptor,
+ mlir::ConversionPatternRewriter &) const override;
+};
+
class CIRToLLVMVecShuffleDynamicOpLowering
: public mlir::OpConversionPattern<cir::VecShuffleDynamicOp> {
public:
diff --git a/clang/test/CIR/CodeGen/vector-ext.cpp b/clang/test/CIR/CodeGen/vector-ext.cpp
index 8a0479fc1d088..aa836c2e70a12 100644
--- a/clang/test/CIR/CodeGen/vector-ext.cpp
+++ b/clang/test/CIR/CodeGen/vector-ext.cpp
@@ -1091,3 +1091,28 @@ void foo17() {
// OGCG: %[[VEC_A:.*]] = alloca <2 x double>, align 16
// OGCG: %[[TMP:.*]] = load <2 x double>, ptr %[[VEC_A]], align 16
// OGCG: %[[RES:.*]]= fptoui <2 x double> %[[TMP]] to <2 x i16>
+
+void foo19() {
+ vi4 a;
+ vi4 b;
+ vi4 u = __builtin_shufflevector(a, b, 7, 5, 3, 1);
+}
+
+// CIR: %[[VEC_A:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["a"]
+// CIR: %[[VEC_B:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["b"]
+// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[VEC_A]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i>
+// CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[VEC_B]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i>
+// CIR: %[[SHUF:.*]] = cir.vec.shuffle(%[[TMP_A]], %[[TMP_B]] : !cir.vector<4 x !s32i>) [#cir.int<7> :
+// CIR-SAME: !s64i, #cir.int<5> : !s64i, #cir.int<3> : !s64i, #cir.int<1> : !s64i] : !cir.vector<4 x !s32i>
+
+// LLVM: %[[VEC_A:.*]] = alloca <4 x i32>, i64 1, align 16
+// LLVM: %[[VEC_B:.*]] = alloca <4 x i32>, i64 1, align 16
+// LLVM: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[VEC_A]], align 16
+// LLVM: %[[TMP_B:.*]] = load <4 x i32>, ptr %[[VEC_B]], align 16
+// LLVM: %[[SHUF:.*]] = shufflevector <4 x i32> %[[TMP_A]], <4 x i32> %[[TMP_B]], <4 x i32> <i32 7, i32 5, i32 3, i32 1>
+
+// OGCG: %[[VEC_A:.*]] = alloca <4 x i32>, align 16
+// OGCG: %[[VEC_B:.*]] = alloca <4 x i32>, align 16
+// OGCG: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[VEC_A]], align 16
+// OGCG: %[[TMP_B:.*]] = load <4 x i32>, ptr %[[VEC_B]], align 16
+// OGCG: %[[SHUF:.*]] = shufflevector <4 x i32> %[[TMP_A]], <4 x i32> %[[TMP_B]], <4 x i32> <i32 7, i32 5, i32 3, i32 1>
diff --git a/clang/test/CIR/CodeGen/vector.cpp b/clang/test/CIR/CodeGen/vector.cpp
index 4c50f68a56162..fe69d3ae6e579 100644
--- a/clang/test/CIR/CodeGen/vector.cpp
+++ b/clang/test/CIR/CodeGen/vector.cpp
@@ -1069,4 +1069,29 @@ void foo17() {
// OGCG: %[[VEC_A:.*]] = alloca <2 x double>, align 16
// OGCG: %[[TMP:.*]] = load <2 x double>, ptr %[[VEC_A]], align 16
-// OGCG: %[[RES:.*]]= fptoui <2 x double> %[[TMP]] to <2 x i16>
\ No newline at end of file
+// OGCG: %[[RES:.*]]= fptoui <2 x double> %[[TMP]] to <2 x i16>
+
+void foo19() {
+ vi4 a;
+ vi4 b;
+ vi4 u = __builtin_shufflevector(a, b, 7, 5, 3, 1);
+}
+
+// CIR: %[[VEC_A:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["a"]
+// CIR: %[[VEC_B:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["b"]
+// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[VEC_A]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i>
+// CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[VEC_B]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i>
+// CIR: %[[SHUF:.*]] = cir.vec.shuffle(%[[TMP_A]], %[[TMP_B]] : !cir.vector<4 x !s32i>) [#cir.int<7> :
+// CIR-SAME: !s64i, #cir.int<5> : !s64i, #cir.int<3> : !s64i, #cir.int<1> : !s64i] : !cir.vector<4 x !s32i>
+
+// LLVM: %[[VEC_A:.*]] = alloca <4 x i32>, i64 1, align 16
+// LLVM: %[[VEC_B:.*]] = alloca <4 x i32>, i64 1, align 16
+// LLVM: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[VEC_A]], align 16
+// LLVM: %[[TMP_B:.*]] = load <4 x i32>, ptr %[[VEC_B]], align 16
+// LLVM: %[[SHUF:.*]] = shufflevector <4 x i32> %[[TMP_A]], <4 x i32> %[[TMP_B]], <4 x i32> <i32 7, i32 5, i32 3, i32 1>
+
+// OGCG: %[[VEC_A:.*]] = alloca <4 x i32>, align 16
+// OGCG: %[[VEC_B:.*]] = alloca <4 x i32>, align 16
+// OGCG: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[VEC_A]], align 16
+// OGCG: %[[TMP_B:.*]] = load <4 x i32>, ptr %[[VEC_B]], align 16
+// OGCG: %[[SHUF:.*]] = shufflevector <4 x i32> %[[TMP_A]], <4 x i32> %[[TMP_B]], <4 x i32> <i32 7, i32 5, i32 3, i32 1>
diff --git a/clang/test/CIR/IR/invalid-vector.cir b/clang/test/CIR/IR/invalid-vector.cir
index d94eacedec1f5..4ff9e47b12ba4 100644
--- a/clang/test/CIR/IR/invalid-vector.cir
+++ b/clang/test/CIR/IR/invalid-vector.cir
@@ -8,3 +8,41 @@ module {
cir.global external @vec_b = #cir.zero : !cir.vector<4 x !cir.array<!s32i x 10>>
}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+!s64i = !cir.int<s, 64>
+
+module {
+ cir.func @invalid_vector_shuffle() {
+ %1 = cir.const #cir.int<1> : !s32i
+ %2 = cir.const #cir.int<2> : !s32i
+ %3 = cir.const #cir.int<3> : !s32i
+ %4 = cir.const #cir.int<4> : !s32i
+ %vec_1 = cir.vec.create(%1, %2, %3, %4 : !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i>
+ %vec_2 = cir.vec.create(%1, %2, %3, %4 : !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i>
+ // expected-error @below {{element types of '!cir.vector<4 x !cir.int<s, 32>>' and '!cir.vector<4 x !cir.int<s, 64>>' don't match}}
+ %new_vec = cir.vec.shuffle(%vec_1, %vec_2 : !cir.vector<4 x !s32i>) [#cir.int<7> : !s64i, #cir.int<5> : !s64i, #cir.int<3> : !s64i, #cir.int<1> : !s64i] : !cir.vector<4 x !s64i>
+ cir.return
+ }
+}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+!s64i = !cir.int<s, 64>
+
+module {
+ cir.func @invalid_vector_shuffle() {
+ %1 = cir.const #cir.int<1> : !s32i
+ %2 = cir.const #cir.int<2> : !s32i
+ %3 = cir.const #cir.int<3> : !s32i
+ %4 = cir.const #cir.int<4> : !s32i
+ %vec_1 = cir.vec.create(%1, %2, %3, %4 : !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i>
+ %vec_2 = cir.vec.create(%1, %2, %3, %4 : !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i>
+ // expected-error @below {{the number of elements in [#cir.int<7> : !cir.int<s, 64>, #cir.int<5> : !cir.int<s, 64>, #cir.int<3> : !cir.int<s, 64>] and '!cir.vector<4 x !cir.int<s, 64>>' don't match}}
+ %new_vec = cir.vec.shuffle(%vec_1, %vec_2 : !cir.vector<4 x !s32i>) [#cir.int<7> : !s64i, #cir.int<5> : !s64i, #cir.int<3> : !s64i] : !cir.vector<4 x !s64i>
+ cir.return
+ }
+}
|
Notes:
|
@xlauko I moved the argument Constraints to use
|
let arguments = (ins | ||
CIR_VectorType:$vec1, | ||
CIR_VectorType:$vec2, | ||
TypedArrayAttrBase<IntAttr, "Integer array attribute">:$indices |
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.
Any reason for them to be cir::IntAttr? why not just use DenseI64ArrayAttr
, maybe even DenseI32ArrayAttr
would be sufficient?
Also if we decide to use TypedArrayAttrBase<IntAtt
please define it as constraint elsewhere:
def CIR_IntArrayAttr : TypedArrayAttrBase<IntAttr, "integer array attribute">;
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.
There will be soon CIRAttrConstraints.td
file soon (or you can add it) where this kind of constraint should be placed later.
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.
My idea was to move the constraints mlir::isa<cir::IntAttr>
from the verifier to the td, so i used IntAttr, i move it to CIRAttrConstraints.td
and check the other options too
Quoiting the docs: the result of |
Thank you, i will put it back to the description |
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef CLANG_CIR_DIALECT_IR_CIRATTRCONSTRAINTS_TD | ||
#define CLANG_CIR_DIALECT_IRCIRATTRCONSTRAINTS_TD_ |
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.
#define CLANG_CIR_DIALECT_IRCIRATTRCONSTRAINTS_TD_ | |
#define CLANG_CIR_DIALECT_IR_CIRATTRCONSTRAINTS_TD |
include "clang/CIR/Dialect/IR/CIRAttrs.td" | ||
include "mlir/IR/CommonAttrConstraints.td" | ||
|
||
def CIR_IntArrayAttr : TypedArrayAttrBase<IntAttr, "integer array attribute">; |
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.
You cannot include CIRAttrs.td here as it will eventually create circular dependency.
To constrain on IntAttr
add CIR_AnyIntAttr
see following suggestion:
include "clang/CIR/Dialect/IR/CIRAttrs.td" | |
include "mlir/IR/CommonAttrConstraints.td" | |
def CIR_IntArrayAttr : TypedArrayAttrBase<IntAttr, "integer array attribute">; | |
include "mlir/IR/CommonAttrConstraints.td" | |
class CIR_IsAttrPred<code attr> : CPred<"::mlir::isa<" # attr # ">($_self)">; | |
class CIR_AttrConstraint<code attr, string summary = ""> | |
: AttrConstraint<CIR_IsAttrPred<attr>, summary>; | |
//===----------------------------------------------------------------------===// | |
// IntAttr constraints | |
//===----------------------------------------------------------------------===// | |
def CIR_AnyIntAttr : CIR_AttrConstraint<"::cir::IntAttr", "integer attribute">; | |
//===----------------------------------------------------------------------===// | |
// ArrayAttr constraints | |
//===----------------------------------------------------------------------===// | |
def CIR_IntArrayAttr : TypedArrayAttrBase<IntAttr, "integer array attribute">; |
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 part will not compile TypedArrayAttrBase<IntAttr, ...
, I am thinking how to use CIR_AnyIntAttr
inside TypedArrayAttrBase
, for example like TypedArrayAttrBase<CIR_AnyIntAttr
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.
I used those to create the constraints 🤔
def CIR_AnyIntAttr : Attr<CPred<"mlir::isa<cir::IntAttr>($_self)">, "integer attribute">;
def CIR_IntArrayAttr : TypedArrayAttrBase<CIR_AnyIntAttr, "integer array attribute">;
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.
My bad, it should have been TypedArrayAttrBase<CIR_AnyIntAttr, "integer array attribute">
.
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.
Done, but i used class CIR_AttrConstraint<code attr, string summary = ""> : Attr<CIR_IsAttrPred<attr>, summary>;
similar to my snippet to make it work
let summary = "Combine two vectors using indices passed as constant integers"; | ||
let description = [{ | ||
The `cir.vec.shuffle` operation implements the documented form of Clang's | ||
__builtin_shufflevector, where the indices of the shuffled result are |
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.
__builtin_shufflevector, where the indices of the shuffled result are | |
`__builtin_shufflevector`, where the indices of the shuffled result are |
188cc43
to
6e7ffc3
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, one minor nit
set(LLVM_TARGET_DEFINITIONS CIRAttrConstraints.td) | ||
mlir_tablegen(CIRAttrConstraints.h.inc -gen-type-constraint-decls) | ||
mlir_tablegen(CIRAttrConstraints.cpp.inc -gen-type-constraint-defs) | ||
add_public_tablegen_target(MLIRCIRAttrConstraintsIncGen) | ||
add_dependencies(mlir-headers MLIRCIRAttrConstraintsIncGen) |
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.
Why is this here? I believe CIRAttrConstraints
are not generating anything to h.inc
and cpp.inc
yet.
Also it is nowhere included.
9c2dabb
to
a120f28
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
This change adds support for the Shuffle op for VectorType
Issue #136487