diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 94d39f543394..c1ec731e9715 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -2198,6 +2198,69 @@ def VecTernaryOp : CIR_Op<"vec.ternary", let hasVerifier = 1; } +//===----------------------------------------------------------------------===// +// VecShuffle +//===----------------------------------------------------------------------===// + +// 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. The size of the result vector does + not have to match the size of the individual input vectors or of the + concatenated vector. + }]; + let arguments = (ins CIR_VectorType:$vec1, CIR_VectorType:$vec2, + ArrayAttr:$indices); + let results = (outs CIR_VectorType:$result); + let assemblyFormat = [{ + `(` $vec1 `,` $vec2 `:` qualified(type($vec1)) `)` $indices `:` + qualified(type($result)) attr-dict + }]; + let hasVerifier = 1; +} + +//===----------------------------------------------------------------------===// +// VecShuffleDynamic +//===----------------------------------------------------------------------===// + +def VecShuffleDynamicOp : CIR_Op<"vec.shuffle.dynamic", + [Pure, AllTypesMatch<["vec", "result"]>]> { + let summary = "Shuffle a vector using indices in another vector"; + let description = [{ + The `cir.vec.shuffle.dynamic` operation implements the undocumented form of + Clang's __builtin_shufflevector, where the indices of the shuffled result + can be runtime values. + + There are two input vectors, which must have the same number of elements. + The second input vector must have an integral element type. The elements of + the second vector are interpreted as indices into the first vector. The + result vector is constructed by taking the elements from the first input + vector from the indices indicated by the elements of the second vector. + }]; + let arguments = (ins CIR_VectorType:$vec, IntegerVector:$indices); + let results = (outs CIR_VectorType:$result); + let assemblyFormat = [{ + $vec `:` qualified(type($vec)) `,` $indices `:` qualified(type($indices)) + attr-dict + }]; + let hasVerifier = 1; +} + //===----------------------------------------------------------------------===// // BaseClassAddr //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index 91559b08fa7e..e6093c52ca84 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -280,10 +280,37 @@ class ScalarExprEmitter : public StmtVisitor { llvm_unreachable("NYI"); } mlir::Value VisitShuffleVectorExpr(ShuffleVectorExpr *E) { - llvm_unreachable("NYI"); + if (E->getNumSubExprs() == 2) { + // The undocumented form of __builtin_shufflevector. + mlir::Value InputVec = Visit(E->getExpr(0)); + mlir::Value IndexVec = Visit(E->getExpr(1)); + return CGF.builder.create( + CGF.getLoc(E->getSourceRange()), InputVec, IndexVec); + } else { + // The documented form of __builtin_shufflevector, where the indices are + // a variable number of integer constants. The constants will be stored + // in an ArrayAttr. + mlir::Value Vec1 = Visit(E->getExpr(0)); + mlir::Value Vec2 = Visit(E->getExpr(1)); + SmallVector Indices; + for (unsigned i = 2; i < E->getNumSubExprs(); ++i) { + Indices.push_back(mlir::cir::IntAttr::get( + CGF.builder.getSInt64Ty(), + E->getExpr(i) + ->EvaluateKnownConstInt(CGF.getContext()) + .getSExtValue())); + } + return CGF.builder.create( + CGF.getLoc(E->getSourceRange()), CGF.getCIRType(E->getType()), Vec1, + Vec2, CGF.builder.getArrayAttr(Indices)); + } } mlir::Value VisitConvertVectorExpr(ConvertVectorExpr *E) { - llvm_unreachable("NYI"); + // __builtin_convertvector is an element-wise cast, and is implemented as a + // regular cast. The back end handles casts of vectors correctly. + return buildScalarConversion(Visit(E->getSrcExpr()), + E->getSrcExpr()->getType(), E->getType(), + E->getSourceRange().getBegin()); } mlir::Value VisitMemberExpr(MemberExpr *E); mlir::Value VisitExtVectorelementExpr(Expr *E) { llvm_unreachable("NYI"); } @@ -1725,9 +1752,9 @@ mlir::Value ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *E) { } // Conversion from bool, integral, or floating-point to integral or -// floating-point. Conversions involving other types are handled elsewhere. +// floating-point. Conversions involving other types are handled elsewhere. // Conversion to bool is handled elsewhere because that's a comparison against -// zero, not a simple cast. +// zero, not a simple cast. This handles both individual scalars and vectors. mlir::Value ScalarExprEmitter::buildScalarCast( mlir::Value Src, QualType SrcType, QualType DstType, mlir::Type SrcTy, mlir::Type DstTy, ScalarConversionOpts Opts) { @@ -1736,9 +1763,20 @@ mlir::Value ScalarExprEmitter::buildScalarCast( if (SrcTy.isa() || DstTy.isa()) llvm_unreachable("Obsolete code. Don't use mlir::IntegerType with CIR."); + mlir::Type FullDstTy = DstTy; + if (SrcTy.isa() && + DstTy.isa()) { + // Use the element types of the vectors to figure out the CastKind. + SrcTy = SrcTy.dyn_cast().getEltType(); + DstTy = DstTy.dyn_cast().getEltType(); + } + assert(!SrcTy.isa() && + !DstTy.isa() && + "buildScalarCast given a vector type and a non-vector type"); + std::optional CastKind; - if (SrcType->isBooleanType()) { + if (SrcTy.isa()) { if (Opts.TreatBooleanAsSigned) llvm_unreachable("NYI: signed bool"); if (CGF.getBuilder().isInt(DstTy)) { @@ -1768,7 +1806,7 @@ mlir::Value ScalarExprEmitter::buildScalarCast( CastKind = mlir::cir::CastKind::float_to_int; } else if (DstTy.isa()) { // TODO: split this to createFPExt/createFPTrunc - return Builder.createFloatingCast(Src, DstTy); + return Builder.createFloatingCast(Src, FullDstTy); } else { llvm_unreachable("Internal error: Cast to unexpected type"); } @@ -1777,7 +1815,8 @@ mlir::Value ScalarExprEmitter::buildScalarCast( } assert(CastKind.has_value() && "Internal error: CastKind not set."); - return Builder.create(Src.getLoc(), DstTy, *CastKind, Src); + return Builder.create(Src.getLoc(), FullDstTy, *CastKind, + Src); } LValue diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index d9b227519ccd..aa4364ffa169 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -395,6 +395,14 @@ LogicalResult CastOp::verify() { auto resType = getResult().getType(); auto srcType = getSrc().getType(); + if (srcType.isa() && + resType.isa()) { + // Use the element type of the vector to verify the cast kind. (Except for + // bitcast, see below.) + srcType = srcType.dyn_cast().getEltType(); + resType = resType.dyn_cast().getEltType(); + } + switch (getKind()) { case cir::CastKind::int_to_bool: { if (!resType.isa()) @@ -433,10 +441,12 @@ LogicalResult CastOp::verify() { return success(); } case cir::CastKind::bitcast: { - if ((!srcType.isa() || - !resType.isa()) && - (!srcType.isa() || - !resType.isa())) + // This is the only cast kind where we don't want vector types to decay + // into the element type. + if ((!getSrc().getType().isa() || + !getResult().getType().isa()) && + (!getSrc().getType().isa() || + !getResult().getType().isa())) return emitOpError() << "requires !cir.ptr or !cir.vector type for source and result"; return success(); @@ -444,7 +454,7 @@ LogicalResult CastOp::verify() { case cir::CastKind::floating: { if (!srcType.isa() || !resType.isa()) - return emitOpError() << "requries floating for source and result"; + return emitOpError() << "requires floating for source and result"; return success(); } case cir::CastKind::float_to_int: { @@ -544,6 +554,47 @@ LogicalResult VecTernaryOp::verify() { return success(); } +//===----------------------------------------------------------------------===// +// VecShuffle +//===----------------------------------------------------------------------===// + +LogicalResult 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().getEltType() != getResult().getType().getEltType()) { + return emitOpError() << ": element types of " << getVec1().getType() + << " and " << getResult().getType() << " don't match"; + } + // The indices must all be integer constants + if (not std::all_of(getIndices().begin(), getIndices().end(), + [](mlir::Attribute attr) { + return attr.isa(); + })) { + return emitOpError() << "all index values must be integers"; + } + return success(); +} + +//===----------------------------------------------------------------------===// +// VecShuffleDynamic +//===----------------------------------------------------------------------===// + +LogicalResult VecShuffleDynamicOp::verify() { + // The number of elements in the two input vectors must match. + if (getVec().getType().getSize() != + getIndices().getType().cast().getSize()) { + return emitOpError() << ": the number of elements in " << getVec().getType() + << " and " << getIndices().getType() << " don't match"; + } + return success(); +} + //===----------------------------------------------------------------------===// // ReturnOp //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index e249c59c964f..1be19653a897 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -142,6 +142,15 @@ convertCmpKindToFCmpPredicate(mlir::cir::CmpOpKind kind) { llvm_unreachable("Unknown CmpOpKind"); } +/// If the given type is a vector type, return the vector's element type. +/// Otherwise return the given type unchanged. +mlir::Type elementTypeIfVector(mlir::Type type) { + if (auto VecType = type.dyn_cast()) { + return VecType.getEltType(); + } + return type; +} + } // namespace //===----------------------------------------------------------------------===// @@ -574,6 +583,10 @@ class CIRCastOpLowering : public mlir::OpConversionPattern { mlir::LogicalResult matchAndRewrite(mlir::cir::CastOp castOp, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const override { + // For arithmetic conversions, LLVM IR uses the same instruction to convert + // both individual scalars and entire vectors. This lowering pass handles + // both situations. + auto src = adaptor.getSrc(); switch (castOp.getKind()) { @@ -597,43 +610,46 @@ class CIRCastOpLowering : public mlir::OpConversionPattern { break; } case mlir::cir::CastKind::integral: { - auto dstType = castOp.getResult().getType().cast(); - auto srcType = castOp.getSrc().getType().dyn_cast(); + auto srcType = castOp.getSrc().getType(); + auto dstType = castOp.getResult().getType(); auto llvmSrcVal = adaptor.getOperands().front(); - auto llvmDstTy = - getTypeConverter()->convertType(dstType).cast(); - - // Target integer is smaller: truncate source value. - if (dstType.getWidth() < srcType.getWidth()) { - rewriter.replaceOpWithNewOp(castOp, llvmDstTy, + auto llvmDstType = getTypeConverter()->convertType(dstType); + mlir::cir::IntType srcIntType = + elementTypeIfVector(srcType).cast(); + mlir::cir::IntType dstIntType = + elementTypeIfVector(dstType).cast(); + + if (dstIntType.getWidth() < srcIntType.getWidth()) { + // Bigger to smaller. Truncate. + rewriter.replaceOpWithNewOp(castOp, llvmDstType, llvmSrcVal); - } - // Target integer is larger: sign extend or zero extend. - else if (dstType.getWidth() > srcType.getWidth()) { - if (srcType.isUnsigned()) - rewriter.replaceOpWithNewOp(castOp, llvmDstTy, + } else if (dstIntType.getWidth() > srcIntType.getWidth()) { + // Smaller to bigger. Zero extend or sign extend based on signedness. + if (srcIntType.isUnsigned()) + rewriter.replaceOpWithNewOp(castOp, llvmDstType, llvmSrcVal); else - rewriter.replaceOpWithNewOp(castOp, llvmDstTy, + rewriter.replaceOpWithNewOp(castOp, llvmDstType, llvmSrcVal); - } else { // Target integer is of the same size: do nothing. + } else { + // Same size. Signedness changes doesn't matter to LLVM. Do nothing. rewriter.replaceOp(castOp, llvmSrcVal); } break; } case mlir::cir::CastKind::floating: { - auto dstTy = castOp.getResult().getType(); - auto srcTy = castOp.getSrc().getType(); + auto llvmSrcVal = adaptor.getOperands().front(); + auto llvmDstTy = + getTypeConverter()->convertType(castOp.getResult().getType()); + + auto srcTy = elementTypeIfVector(castOp.getSrc().getType()); + auto dstTy = elementTypeIfVector(castOp.getResult().getType()); if (!dstTy.isa() || !srcTy.isa()) return castOp.emitError() << "NYI cast from " << srcTy << " to " << dstTy; - auto llvmSrcVal = adaptor.getOperands().front(); - auto llvmDstTy = - getTypeConverter()->convertType(dstTy).cast(); - auto getFloatWidth = [](mlir::Type ty) -> unsigned { return ty.cast().getWidth(); }; @@ -706,7 +722,9 @@ class CIRCastOpLowering : public mlir::OpConversionPattern { auto dstTy = castOp.getType(); auto llvmSrcVal = adaptor.getOperands().front(); auto llvmDstTy = getTypeConverter()->convertType(dstTy); - if (castOp.getSrc().getType().cast().isSigned()) + if (elementTypeIfVector(castOp.getSrc().getType()) + .cast() + .isSigned()) rewriter.replaceOpWithNewOp(castOp, llvmDstTy, llvmSrcVal); else @@ -718,7 +736,9 @@ class CIRCastOpLowering : public mlir::OpConversionPattern { auto dstTy = castOp.getType(); auto llvmSrcVal = adaptor.getOperands().front(); auto llvmDstTy = getTypeConverter()->convertType(dstTy); - if (castOp.getResult().getType().cast().isSigned()) + if (elementTypeIfVector(castOp.getResult().getType()) + .cast() + .isSigned()) rewriter.replaceOpWithNewOp(castOp, llvmDstTy, llvmSrcVal); else @@ -1299,8 +1319,7 @@ class CIRVectorCmpOpLowering "Vector compare with non-vector type"); // LLVM IR vector comparison returns a vector of i1. This one-bit vector // must be sign-extended to the correct result type. - auto elementType = - op.getLhs().getType().dyn_cast().getEltType(); + auto elementType = elementTypeIfVector(op.getLhs().getType()); mlir::Value bitResult; if (auto intType = elementType.dyn_cast()) { bitResult = rewriter.create( @@ -1330,8 +1349,8 @@ class CIRVectorSplatLowering mlir::ConversionPatternRewriter &rewriter) const override { // Vector splat can be implemented with an `insertelement` and a // `shufflevector`, which is better than an `insertelement` for each - // element in vector. Start with an undef vector. Insert the value into - // the first element. Then use a `shufflevector` with a mask of all 0 to + // element in the vector. Start with an undef vector. Insert the value into + // the first element. Then use a `shufflevector` with a mask of all 0 to // fill out the entire vector with that value. auto vecTy = op.getType().dyn_cast(); assert(vecTy && "result type of cir.vec.splat op is not VectorType"); @@ -1376,6 +1395,84 @@ class CIRVectorTernaryLowering } }; +class CIRVectorShuffleIntsLowering + : public mlir::OpConversionPattern { +public: + using OpConversionPattern::OpConversionPattern; + + mlir::LogicalResult + matchAndRewrite(mlir::cir::VecShuffleOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const override { + // LLVM::ShuffleVectorOp takes an ArrayRef of int for the list of indices. + // Convert the ClangIR ArrayAttr of IntAttr constants into a + // SmallVector. + SmallVector indices; + std::transform( + op.getIndices().begin(), op.getIndices().end(), + std::back_inserter(indices), [](mlir::Attribute intAttr) { + return intAttr.cast().getValue().getSExtValue(); + }); + rewriter.replaceOpWithNewOp( + op, adaptor.getVec1(), adaptor.getVec2(), indices); + return mlir::success(); + } +}; + +class CIRVectorShuffleVecLowering + : public mlir::OpConversionPattern { +public: + using OpConversionPattern< + mlir::cir::VecShuffleDynamicOp>::OpConversionPattern; + + mlir::LogicalResult + matchAndRewrite(mlir::cir::VecShuffleDynamicOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const override { + // LLVM IR does not have an operation that corresponds to this form of + // the built-in. + // __builtin_shufflevector(V, I) + // is implemented as this pseudocode, where the for loop is unrolled + // and N is the number of elements: + // masked = I & (N-1) + // for (i in 0 <= i < N) + // result[i] = V[masked[i]] + auto loc = op.getLoc(); + mlir::Value input = adaptor.getVec(); + mlir::Type llvmIndexVecType = + getTypeConverter()->convertType(op.getIndices().getType()); + mlir::Type llvmIndexType = getTypeConverter()->convertType( + elementTypeIfVector(op.getIndices().getType())); + uint64_t numElements = + op.getVec().getType().cast().getSize(); + mlir::Value maskValue = rewriter.create( + loc, llvmIndexType, + mlir::IntegerAttr::get(llvmIndexType, numElements - 1)); + mlir::Value maskVector = + rewriter.create(loc, llvmIndexVecType); + for (uint64_t i = 0; i < numElements; ++i) { + mlir::Value iValue = rewriter.create( + loc, rewriter.getI64Type(), i); + maskVector = rewriter.create( + loc, maskVector, maskValue, iValue); + } + mlir::Value maskedIndices = rewriter.create( + loc, llvmIndexVecType, adaptor.getIndices(), maskVector); + mlir::Value result = rewriter.create( + loc, getTypeConverter()->convertType(op.getVec().getType())); + for (uint64_t i = 0; i < numElements; ++i) { + mlir::Value iValue = rewriter.create( + loc, rewriter.getI64Type(), i); + mlir::Value indexValue = rewriter.create( + loc, maskedIndices, iValue); + mlir::Value valueAtIndex = + rewriter.create(loc, input, indexValue); + result = rewriter.create( + loc, result, valueAtIndex, iValue); + } + rewriter.replaceOp(op, result); + return mlir::success(); + } +}; + class CIRVAStartLowering : public mlir::OpConversionPattern { public: @@ -1779,12 +1876,8 @@ class CIRUnaryOpLowering assert(op.getType() == op.getInput().getType() && "Unary operation's operand type and result type are different"); mlir::Type type = op.getType(); - mlir::Type elementType = type; - bool IsVector = false; - if (auto VecType = type.dyn_cast()) { - IsVector = true; - elementType = VecType.getEltType(); - } + mlir::Type elementType = elementTypeIfVector(type); + bool IsVector = type.isa(); auto llvmType = getTypeConverter()->convertType(type); auto loc = op.getLoc(); @@ -1940,8 +2033,7 @@ class CIRBinOpLowering : public mlir::OpConversionPattern { auto rhs = adaptor.getRhs(); auto lhs = adaptor.getLhs(); - if (type.isa()) - type = type.dyn_cast().getEltType(); + type = elementTypeIfVector(type); switch (op.getKind()) { case mlir::cir::BinOpKind::Add: @@ -2761,10 +2853,12 @@ void populateCIRToLLVMConversionPatterns(mlir::RewritePatternSet &patterns, CIRFAbsOpLowering, CIRExpectOpLowering, CIRVTableAddrPointOpLowering, CIRVectorCreateLowering, CIRVectorInsertLowering, CIRVectorExtractLowering, CIRVectorCmpOpLowering, CIRVectorSplatLowering, - CIRVectorTernaryLowering, CIRStackSaveLowering, CIRStackRestoreLowering, - CIRUnreachableLowering, CIRTrapLowering, CIRInlineAsmOpLowering, - CIRSetBitfieldLowering, CIRGetBitfieldLowering, CIRPrefetchLowering, - CIRIsConstantOpLowering>(converter, patterns.getContext()); + CIRVectorTernaryLowering, CIRVectorShuffleIntsLowering, + CIRVectorShuffleVecLowering, CIRStackSaveLowering, + CIRStackRestoreLowering, CIRUnreachableLowering, CIRTrapLowering, + CIRInlineAsmOpLowering, CIRSetBitfieldLowering, CIRGetBitfieldLowering, + CIRPrefetchLowering, CIRIsConstantOpLowering>(converter, + patterns.getContext()); } namespace { diff --git a/clang/test/CIR/CodeGen/vectype.cpp b/clang/test/CIR/CodeGen/vectype.cpp index 75554e7c6e5a..266ebda4a772 100644 --- a/clang/test/CIR/CodeGen/vectype.cpp +++ b/clang/test/CIR/CodeGen/vectype.cpp @@ -3,6 +3,7 @@ typedef int vi4 __attribute__((vector_size(16))); typedef double vd2 __attribute__((vector_size(16))); typedef long long vll2 __attribute__((vector_size(16))); +typedef unsigned short vus2 __attribute__((vector_size(4))); void vector_int_test(int x) { @@ -84,6 +85,12 @@ void vector_int_test(int x) { // CHECK: %{{[0-9]+}} = cir.vec.cmp(le, %{{[0-9]+}}, %{{[0-9]+}}) : !cir.vector, !cir.vector vi4 t = a >= b; // CHECK: %{{[0-9]+}} = cir.vec.cmp(ge, %{{[0-9]+}}, %{{[0-9]+}}) : !cir.vector, !cir.vector + + // __builtin_shufflevector + vi4 u = __builtin_shufflevector(a, b, 7, 5, 3, 1); + // CHECK: %{{[0-9]+}} = cir.vec.shuffle(%{{[0-9]+}}, %{{[0-9]+}} : !cir.vector) [#cir.int<7> : !s64i, #cir.int<5> : !s64i, #cir.int<3> : !s64i, #cir.int<1> : !s64i] : !cir.vector + vi4 v = __builtin_shufflevector(a, b); + // CHECK: %{{[0-9]+}} = cir.vec.shuffle.dynamic %{{[0-9]+}} : !cir.vector, %{{[0-9]+}} : !cir.vector } void vector_double_test(int x, double y) { @@ -146,4 +153,8 @@ void vector_double_test(int x, double y) { // CHECK: %{{[0-9]+}} = cir.vec.cmp(le, %{{[0-9]+}}, %{{[0-9]+}}) : !cir.vector, !cir.vector vll2 t = a >= b; // CHECK: %{{[0-9]+}} = cir.vec.cmp(ge, %{{[0-9]+}}, %{{[0-9]+}}) : !cir.vector, !cir.vector + + // __builtin_convertvector + vus2 w = __builtin_convertvector(a, vus2); + // CHECK: %{{[0-9]+}} = cir.cast(float_to_int, %{{[0-9]+}} : !cir.vector), !cir.vector } diff --git a/clang/test/CIR/IR/invalid.cir b/clang/test/CIR/IR/invalid.cir index 28cae0cc8214..74ab743bb2fd 100644 --- a/clang/test/CIR/IR/invalid.cir +++ b/clang/test/CIR/IR/invalid.cir @@ -195,7 +195,7 @@ cir.func @cast10(%p : !cir.float) { !u32i = !cir.int cir.func @cast11(%p : !cir.float) { - %2 = cir.cast(floating, %p : !cir.float), !u32i // expected-error {{requries floating for source and result}} + %2 = cir.cast(floating, %p : !cir.float), !u32i // expected-error {{requires floating for source and result}} cir.return } @@ -203,7 +203,7 @@ cir.func @cast11(%p : !cir.float) { !u32i = !cir.int cir.func @cast12(%p : !u32i) { - %2 = cir.cast(floating, %p : !u32i), !cir.float // expected-error {{requries floating for source and result}} + %2 = cir.cast(floating, %p : !u32i), !cir.float // expected-error {{requires floating for source and result}} cir.return } @@ -471,6 +471,42 @@ cir.func @vec_ternary_not_int(%p : !cir.float) { // ----- +!s32i = !cir.int +cir.func @vec_shuffle_mismatch_args(%f : !cir.float, %n : !s32i) { + %0 = cir.vec.create(%f, %f : !cir.float, !cir.float) : !cir.vector + %1 = cir.vec.create(%n, %n : !s32i, !s32i) : !cir.vector // expected-note {{prior use here}} + %2 = cir.vec.shuffle(%0, %1 : !cir.vector) [#cir.int<0> : !s32i, #cir.int<1> : !s32i] : !cir.vector // expected-error {{use of value '%1' expects different type than prior uses: '!cir.vector' vs '!cir.vector x 2>}} + cir.return +} + +// ----- + +cir.func @vec_shuffle_non_ints(%f : !cir.float) { + %0 = cir.vec.create(%f, %f : !cir.float, !cir.float) : !cir.vector + %1 = cir.vec.shuffle(%0, %0 : !cir.vector) [#cir.fp<1.000000e+00> : !cir.float, #cir.fp<1.000000e+00> : !cir.float] : !cir.vector // expected-error {{'cir.vec.shuffle' op all index values must be integers}} + cir.return +} + +// ----- + +!s32i = !cir.int +cir.func @vec_shuffle_result_size(%f : !cir.float) { + %0 = cir.vec.create(%f, %f : !cir.float, !cir.float) : !cir.vector + %1 = cir.vec.shuffle(%0, %0 : !cir.vector) [#cir.int<1> : !s32i, #cir.int<1> : !s32i] : !cir.vector // expected-error {{'cir.vec.shuffle' op : the number of elements in [#cir.int<1> : !cir.int, #cir.int<1> : !cir.int] and '!cir.vector' don't match}} + cir.return +} + +// ----- + +!s32i = !cir.int +cir.func @vec_shuffle_result_element(%f : !cir.float) { + %0 = cir.vec.create(%f, %f : !cir.float, !cir.float) : !cir.vector + %1 = cir.vec.shuffle(%0, %0 : !cir.vector) [#cir.int<1> : !s32i, #cir.int<1> : !s32i] : !cir.vector // expected-error {{'cir.vec.shuffle' op : element types of '!cir.vector' and '!cir.vector x 2>' don't match}} + cir.return +} + +// ----- + cir.func coroutine @bad_task() { // expected-error {{coroutine body must use at least one cir.await op}} cir.return } diff --git a/clang/test/CIR/Lowering/vectype.cpp b/clang/test/CIR/Lowering/vectype.cpp index 05009ea41662..c15bb58265aa 100644 --- a/clang/test/CIR/Lowering/vectype.cpp +++ b/clang/test/CIR/Lowering/vectype.cpp @@ -5,6 +5,7 @@ typedef int vi4 __attribute__((vector_size(16))); typedef double vd2 __attribute__((vector_size(16))); typedef long long vll2 __attribute__((vector_size(16))); +typedef unsigned short vus2 __attribute__((vector_size(4))); void vector_int_test(int x) { @@ -182,6 +183,42 @@ void vector_int_test(int x) { // CHECK: %[[#T127:]] = llvm.icmp "sge" %[[#T125]], %[[#T126]] : vector<4xi32> // CHECK: %[[#T128:]] = llvm.sext %[[#T127]] : vector<4xi1> to vector<4xi32> // CHECK: llvm.store %[[#T128]], %[[#Tt:]] : vector<4xi32>, !llvm.ptr + + // __builtin_shufflevector + vi4 u = __builtin_shufflevector(a, b, 7, 5, 3, 1); + // CHECK: %[[#Tu:]] = llvm.shufflevector %[[#bsva:]], %[[#bsvb:]] [7, 5, 3, 1] : vector<4xi32> + vi4 v = __builtin_shufflevector(a, b); + // CHECK: %[[#sv_a:]] = llvm.load %[[#T3]] : !llvm.ptr -> vector<4xi32> + // CHECK: %[[#sv_b:]] = llvm.load %[[#T5]] : !llvm.ptr -> vector<4xi32> + // CHECK: %[[#sv0:]] = llvm.mlir.constant(3 : i32) : i32 + // CHECK: %[[#sv1:]] = llvm.mlir.undef : vector<4xi32> + // CHECK: %[[#sv2:]] = llvm.mlir.constant(0 : i64) : i64 + // CHECK: %[[#sv3:]] = llvm.insertelement %[[#sv0]], %[[#sv1]][%[[#sv2]] : i64] : vector<4xi32> + // CHECK: %[[#sv4:]] = llvm.mlir.constant(1 : i64) : i64 + // CHECK: %[[#sv5:]] = llvm.insertelement %[[#sv0]], %[[#sv3]][%[[#sv4]] : i64] : vector<4xi32> + // CHECK: %[[#sv6:]] = llvm.mlir.constant(2 : i64) : i64 + // CHECK: %[[#sv7:]] = llvm.insertelement %[[#sv0]], %[[#sv5]][%[[#sv6]] : i64] : vector<4xi32> + // CHECK: %[[#sv8:]] = llvm.mlir.constant(3 : i64) : i64 + // CHECK: %[[#sv9:]] = llvm.insertelement %[[#sv0]], %[[#sv7]][%[[#sv8]] : i64] : vector<4xi32> + // CHECK: %[[#svA:]] = llvm.and %[[#sv_b]], %[[#sv9]] : vector<4xi32> + // CHECK: %[[#svB:]] = llvm.mlir.undef : vector<4xi32> + // CHECK: %[[#svC:]] = llvm.mlir.constant(0 : i64) : i64 + // CHECK: %[[#svD:]] = llvm.extractelement %[[#svA]][%[[#svC]] : i64] : vector<4xi32> + // CHECK: %[[#svE:]] = llvm.extractelement %[[#sv_a]][%[[#svD]] : i32] : vector<4xi32> + // CHECK: %[[#svF:]] = llvm.insertelement %[[#svE]], %[[#svB]][%[[#svC]] : i64] : vector<4xi32> + // CHECK: %[[#svG:]] = llvm.mlir.constant(1 : i64) : i64 + // CHECK: %[[#svH:]] = llvm.extractelement %[[#svA]][%[[#svG]] : i64] : vector<4xi32> + // CHECK: %[[#svI:]] = llvm.extractelement %[[#sv_a]][%[[#svH]] : i32] : vector<4xi32> + // CHECK: %[[#svJ:]] = llvm.insertelement %[[#svI]], %[[#svF]][%[[#svG]] : i64] : vector<4xi32> + // CHECK: %[[#svK:]] = llvm.mlir.constant(2 : i64) : i64 + // CHECK: %[[#svL:]] = llvm.extractelement %[[#svA]][%[[#svK]] : i64] : vector<4xi32> + // CHECK: %[[#svM:]] = llvm.extractelement %[[#sv_a]][%[[#svL]] : i32] : vector<4xi32> + // CHECK: %[[#svN:]] = llvm.insertelement %[[#svM]], %[[#svJ]][%[[#svK]] : i64] : vector<4xi32> + // CHECK: %[[#svO:]] = llvm.mlir.constant(3 : i64) : i64 + // CHECK: %[[#svP:]] = llvm.extractelement %[[#svA]][%[[#svO]] : i64] : vector<4xi32> + // CHECK: %[[#svQ:]] = llvm.extractelement %[[#sv_a]][%[[#svP:]] : i32] : vector<4xi32> + // CHECK: %[[#svR:]] = llvm.insertelement %[[#svQ]], %[[#svN]][%[[#svO]] : i64] : vector<4xi32> + // CHECK: llvm.store %[[#svR]], %[[#sv_v:]] : vector<4xi32>, !llvm.ptr } void vector_double_test(int x, double y) { @@ -294,4 +331,8 @@ void vector_double_test(int x, double y) { // CHECK: %[[#T82:]] = llvm.fcmp "oge" %[[#T80]], %[[#T81]] : vector<2xf64> // CHECK: %[[#T83:]] = llvm.sext %[[#T82]] : vector<2xi1> to vector<2xi64> // CHECK: llvm.store %[[#T83]], %[[#Tt:]] : vector<2xi64>, !llvm.ptr + + // __builtin_convertvector + vus2 w = __builtin_convertvector(a, vus2); + // CHECK: %[[#cv0:]] = llvm.fptoui %[[#cv1:]] : vector<2xf64> to vector<2xi16> }