https://github.com/MacDue updated https://github.com/llvm/llvm-project/pull/231906
>From 719f1f3aa27f865062194322780b46279f09d478 Mon Sep 17 00:00:00 2001 From: Benjamin Maxwell <[email protected]> Date: Wed, 14 Oct 2026 12:35:30 +0000 Subject: [PATCH] [CIR] Use `llvm::ElementCount` to hold `cir::VectorType` size A separate scalability flag is a design issue inherited from MLIR. It makes dropping/ignoring scalability an easy mistake to make in common transforms and lowerings. This patch aligns ClangIR with LLVM and uses `ElementCount` to hold the vector size. This makes it simple to propagate the entire size (element count and scalability) and forces users to query the size they expect: - `.getFixedValue()` - Asserts the size is fixed and converts it to an integer - `.getKnownMinValue()` - Allowed for fixed/scalable vectors - Returns the element count at vscale=1 A few small bugs/missed verifier checks have been handled with this patch and are now tested: - Don't fold scalable splats into fixed-vector-only constants - Verify vectors are not scalable for fixed-vector-only operations - Preserve scalable `TypeSize` values in CIRDataLayout and lowering Assisted-by: Codex --- clang/include/clang/CIR/Dialect/IR/CIRTypes.h | 1 + .../include/clang/CIR/Dialect/IR/CIRTypes.td | 21 +++-- .../lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp | 70 ++++++++------ clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp | 92 +++++++++++-------- clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 3 +- clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 26 +++--- clang/lib/CIR/CodeGen/CIRGenTypes.cpp | 52 +++++------ clang/lib/CIR/Dialect/IR/CIRAttrs.cpp | 5 +- clang/lib/CIR/Dialect/IR/CIRDataLayout.cpp | 2 +- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 20 +++- clang/lib/CIR/Dialect/IR/CIRTypes.cpp | 37 ++++---- .../CIR/Dialect/Transforms/CIRSimplify.cpp | 5 +- .../Transforms/CallConvLoweringPass.cpp | 9 +- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 41 +++++---- clang/test/CIR/IR/invalid-vector.cir | 39 ++++++++ clang/test/CIR/Lowering/not.cir | 14 +++ clang/test/CIR/Transforms/vector-splat.cir | 11 +++ llvm/include/llvm/Support/TypeSize.h | 5 + 18 files changed, 293 insertions(+), 160 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.h b/clang/include/clang/CIR/Dialect/IR/CIRTypes.h index 19f86e83954367..ded2921c608c6f 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.h +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.h @@ -26,6 +26,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/Support/TypeSize.h" namespace llvm { struct fltSemantics; diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td index 366a4669c3a56f..2f61cbf2e6f97c 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td @@ -478,7 +478,7 @@ def CIR_ArrayType : CIR_Type<"Array", "array", [ } //===----------------------------------------------------------------------===// -// VectorType (fixed size) +// VectorType //===----------------------------------------------------------------------===// def CIR_VectorType : CIR_Type<"Vector", "vector", [ @@ -488,8 +488,9 @@ def CIR_VectorType : CIR_Type<"Vector", "vector", [ let summary = "CIR vector type"; let description = [{ The `!cir.vector` type represents a one-dimensional vector. - It takes three parameters: the element type, the number of elements and the - scalability flag (optional, defaults to `false`). + It takes two parameters: the element type and an element count, which + records both the known minimum number of elements and whether the vector is + scalable. Syntax: @@ -524,16 +525,20 @@ def CIR_VectorType : CIR_Type<"Vector", "vector", [ let parameters = (ins CIR_VectorElementType:$element_type, - "uint64_t":$size, - OptionalParameter<"bool">:$is_scalable + "llvm::ElementCount":$size ); let builders = [ TypeBuilderWithInferredContext<(ins - "mlir::Type":$element_type, "uint64_t":$size, CArg<"bool", - "false">:$is_scalable + "mlir::Type":$element_type, "llvm::ElementCount":$size ), [{ - return $_get(element_type.getContext(), element_type, size, is_scalable); + return $_get(element_type.getContext(), element_type, size); + }]>, + TypeBuilderWithInferredContext<(ins + "mlir::Type":$element_type, "uint64_t":$size + ), [{ + return $_get(element_type.getContext(), element_type, + llvm::ElementCount::getFixed(size)); }]>, ]; diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp index ba7355cffbaf04..0dd1dd741984c4 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp @@ -210,7 +210,7 @@ static mlir::Value emitNeonCall(CIRGenModule &cgm, CIRGenBuilderTy &builder, static cir::VectorType getNeonPairwiseWidenInputType(cir::VectorType resType, bool usgn) { mlir::Type elemTy = resType.getElementType(); - uint64_t resLanes = resType.getSize(); + uint64_t resLanes = resType.getSize().getFixedValue(); auto intTy = mlir::dyn_cast<cir::IntType>(elemTy); assert(intTy && "vpaddl result type must be an integer vector"); @@ -632,7 +632,7 @@ emitAArch64CompareBuiltinExpr(CIRGenFunction &cgf, CIRGenBuilderTy &builder, bool scalarCmp = !isa<cir::VectorType>(src.getType()); if (!scalarCmp) { - assert(!cast<cir::VectorType>(retTy).getIsScalable() && + assert(!cast<cir::VectorType>(retTy).getSize().isScalable() && "This is only intended for fixed-width vectors"); // Vector types are cast to i8 vectors. Recover original type. src = builder.createBitcast(src, retTy); @@ -906,7 +906,7 @@ static mlir::Value emitCommonNeonBuiltinExpr( case NEON::BI__builtin_neon_splat_laneq_v: case NEON::BI__builtin_neon_splatq_lane_v: case NEON::BI__builtin_neon_splatq_laneq_v: { - uint64_t numElements = vTy.getSize(); + uint64_t numElements = vTy.getSize().getFixedValue(); if (builtinID == NEON::BI__builtin_neon_splatq_lane_v) numElements *= 2; if (builtinID == NEON::BI__builtin_neon_splat_laneq_v) @@ -1511,8 +1511,8 @@ mlir::Value CIRGenFunction::emitSVEPredicateCast(mlir::Value pred, // TODO: Handle "aarch64.svcount" once we get round to supporting SME. - auto retTy = cir::VectorType::get(builder.getUIntNTy(1), minNumElts, - /*is_scalable=*/true); + auto retTy = cir::VectorType::get( + builder.getUIntNTy(1), llvm::ElementCount::getScalable(minNumElts)); if (pred.getType() == retTy) return pred; @@ -1585,33 +1585,46 @@ cir::VectorType CIRGenFunction::getSVEType(const SVETypeFlags &typeFlags) { llvm_unreachable("Invalid SVETypeFlag!"); case SVETypeFlags::EltTyInt8: - return cir::VectorType::get(builder.getUInt8Ty(), 16, true); + return cir::VectorType::get(builder.getUInt8Ty(), + llvm::ElementCount::getScalable(16)); case SVETypeFlags::EltTyInt16: - return cir::VectorType::get(builder.getUInt16Ty(), 8, true); + return cir::VectorType::get(builder.getUInt16Ty(), + llvm::ElementCount::getScalable(8)); case SVETypeFlags::EltTyInt32: - return cir::VectorType::get(builder.getUInt32Ty(), 4, true); + return cir::VectorType::get(builder.getUInt32Ty(), + llvm::ElementCount::getScalable(4)); case SVETypeFlags::EltTyInt64: - return cir::VectorType::get(builder.getUInt64Ty(), 2, true); + return cir::VectorType::get(builder.getUInt64Ty(), + llvm::ElementCount::getScalable(2)); case SVETypeFlags::EltTyMFloat8: - return cir::VectorType::get(builder.getUInt8Ty(), 16, true); + return cir::VectorType::get(builder.getUInt8Ty(), + llvm::ElementCount::getScalable(16)); case SVETypeFlags::EltTyFloat16: - return cir::VectorType::get(builder.getFp16Ty(), 8, true); + return cir::VectorType::get(builder.getFp16Ty(), + llvm::ElementCount::getScalable(8)); case SVETypeFlags::EltTyBFloat16: - return cir::VectorType::get(builder.getBF16Type(), 8, true); + return cir::VectorType::get(builder.getBF16Type(), + llvm::ElementCount::getScalable(8)); case SVETypeFlags::EltTyFloat32: - return cir::VectorType::get(builder.getF32Type(), 4, true); + return cir::VectorType::get(builder.getF32Type(), + llvm::ElementCount::getScalable(4)); case SVETypeFlags::EltTyFloat64: - return cir::VectorType::get(builder.getDoubleTy(), 2, true); + return cir::VectorType::get(builder.getDoubleTy(), + llvm::ElementCount::getScalable(2)); case SVETypeFlags::EltTyBool8: - return cir::VectorType::get(builder.getUIntNTy(1), 16, true); + return cir::VectorType::get(builder.getUIntNTy(1), + llvm::ElementCount::getScalable(16)); case SVETypeFlags::EltTyBool16: - return cir::VectorType::get(builder.getUIntNTy(1), 8, true); + return cir::VectorType::get(builder.getUIntNTy(1), + llvm::ElementCount::getScalable(8)); case SVETypeFlags::EltTyBool32: - return cir::VectorType::get(builder.getUIntNTy(1), 4, true); + return cir::VectorType::get(builder.getUIntNTy(1), + llvm::ElementCount::getScalable(4)); case SVETypeFlags::EltTyBool64: - return cir::VectorType::get(builder.getUIntNTy(1), 2, true); + return cir::VectorType::get(builder.getUIntNTy(1), + llvm::ElementCount::getScalable(2)); } } @@ -1622,7 +1635,7 @@ static cir::VectorType getSVEVectorForElementType(CIRGenModule &cgm, mlir::Type eltTy) { unsigned numElts = sveBitsPerBlock / cgm.getDataLayout().getTypeSizeInBits(eltTy); - return cir::VectorType::get(eltTy, numElts, /*is_scalable=*/true); + return cir::VectorType::get(eltTy, llvm::ElementCount::getScalable(numElts)); } //===----------------------------------------------------------------------===// @@ -3203,10 +3216,11 @@ CIRGenFunction::emitAArch64BuiltinExpr(unsigned builtinID, const CallExpr *expr, // same shape as the result vector. cir::VectorType sourceTy = cir::VectorType::get( ty.getElementType(), builtinID == NEON::BI__builtin_neon_vfmaq_lane_v - ? ty.getSize() / 2 - : ty.getSize()); + ? ty.getSize().getFixedValue() / 2 + : ty.getSize().getFixedValue()); mlir::Value laneSource = builder.createBitcast(ops[2], sourceTy); - laneSource = emitNeonSplat(builder, loc, laneSource, ops[3], ty.getSize()); + laneSource = emitNeonSplat(builder, loc, laneSource, ops[3], + ty.getSize().getFixedValue()); llvm::SmallVector<mlir::Value> fmaOps = {multiplicand, laneSource, addend}; return emitNeonCallToOp<cir::FMAOp>(cgm, builder, {ty, ty, ty}, fmaOps, @@ -3241,7 +3255,8 @@ CIRGenFunction::emitAArch64BuiltinExpr(unsigned builtinID, const CallExpr *expr, cir::VectorType sourceTy = cir::VectorType::get(ty.getElementType(), ty.getSize() * 2); mlir::Value laneSource = builder.createBitcast(ops[2], sourceTy); - laneSource = emitNeonSplat(builder, loc, laneSource, ops[3], ty.getSize()); + laneSource = emitNeonSplat(builder, loc, laneSource, ops[3], + ty.getSize().getFixedValue()); llvm::SmallVector<mlir::Value> fmaOps = {laneSource, multiplicand, addend}; return emitNeonCallToOp<cir::FMAOp>(cgm, builder, {ty, ty, ty}, fmaOps, @@ -3251,7 +3266,8 @@ CIRGenFunction::emitAArch64BuiltinExpr(unsigned builtinID, const CallExpr *expr, mlir::Value addend = builder.createBitcast(ops[0], ty); mlir::Value multiplicand = builder.createBitcast(ops[1], ty); mlir::Value laneSource = builder.createBitcast(ops[2], ty); - laneSource = emitNeonSplat(builder, loc, laneSource, ops[3], ty.getSize()); + laneSource = emitNeonSplat(builder, loc, laneSource, ops[3], + ty.getSize().getFixedValue()); llvm::SmallVector<mlir::Value> fmaOps = {laneSource, multiplicand, addend}; return emitNeonCallToOp<cir::FMAOp>(cgm, builder, {ty, ty, ty}, fmaOps, @@ -3843,7 +3859,7 @@ CIRGenFunction::emitAArch64BuiltinExpr(unsigned builtinID, const CallExpr *expr, for (unsigned vi = 0; vi != 2; ++vi) { llvm::SmallVector<int64_t, 16> indices; - for (unsigned i = 0, e = ty.getSize(); i != e; i += 2) { + for (unsigned i = 0, e = ty.getSize().getFixedValue(); i != e; i += 2) { indices.push_back(i + vi); indices.push_back(i + e + vi); } @@ -3864,7 +3880,7 @@ CIRGenFunction::emitAArch64BuiltinExpr(unsigned builtinID, const CallExpr *expr, mlir::Value sv; for (unsigned vi = 0; vi != 2; ++vi) { llvm::SmallVector<int64_t, 16> indices; - for (unsigned i = 0, e = ty.getSize(); i != e; ++i) { + for (unsigned i = 0, e = ty.getSize().getFixedValue(); i != e; ++i) { indices.push_back(2 * i + vi); } cir::ConstantOp idx = builder.getConstInt(loc, builder.getSInt32Ty(), vi); @@ -3884,7 +3900,7 @@ CIRGenFunction::emitAArch64BuiltinExpr(unsigned builtinID, const CallExpr *expr, mlir::Value sv; for (unsigned vi = 0; vi != 2; ++vi) { llvm::SmallVector<int64_t, 16> indices; - for (unsigned i = 0, e = ty.getSize(); i != e; i += 2) { + for (unsigned i = 0, e = ty.getSize().getFixedValue(); i != e; i += 2) { indices.push_back((i + vi * e) >> 1); indices.push_back(((i + vi * e) >> 1) + e); } diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp index febcaa7459edb0..50c88064edf948 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp @@ -91,7 +91,7 @@ static mlir::Value emitX86CompressStore(CIRGenBuilderTy &builder, ArrayRef<mlir::Value> ops) { auto resultTy = cast<cir::VectorType>(ops[1].getType()); mlir::Value maskValue = - getMaskVecValue(builder, loc, ops[2], resultTy.getSize()); + getMaskVecValue(builder, loc, ops[2], resultTy.getSize().getFixedValue()); return builder.emitIntrinsicCallOp( loc, "masked.compressstore", cir::VoidType::get(builder.getContext()), @@ -113,7 +113,7 @@ static cir::VecShuffleOp emitPshufWord(CIRGenBuilderTy &builder, uint32_t imm = CIRGenFunction::getZExtIntValueFromConstOp(immediate); auto vecTy = cast<cir::VectorType>(vec.getType()); - unsigned numElts = vecTy.getSize(); + unsigned numElts = vecTy.getSize().getFixedValue(); unsigned firstHalfStart = isLow ? 0 : 4; unsigned secondHalfStart = 4 - firstHalfStart; @@ -141,7 +141,7 @@ computeFullLaneShuffleMask(CIRGenFunction &cgf, const mlir::Value vec, uint32_t imm, const bool isShufP, llvm::SmallVectorImpl<int64_t> &outIndices) { auto vecTy = cast<cir::VectorType>(vec.getType()); - unsigned numElts = vecTy.getSize(); + unsigned numElts = vecTy.getSize().getFixedValue(); unsigned numLanes = cgf.cgm.getDataLayout().getTypeSizeInBits(vecTy) / 128; unsigned numLaneElts = numElts / numLanes; @@ -194,7 +194,8 @@ static mlir::Value emitX86CompressExpand(CIRGenBuilderTy &builder, const std::string &id) { auto resultTy = cast<cir::VectorType>(mask.getType()); mlir::Value maskValue = getMaskVecValue( - builder, loc, inputVector, cast<cir::VectorType>(resultTy).getSize()); + builder, loc, inputVector, + cast<cir::VectorType>(resultTy).getSize().getFixedValue()); return builder.emitIntrinsicCallOp(loc, id, resultTy, mlir::ValueRange{source, mask, maskValue}); } @@ -234,8 +235,9 @@ static mlir::Value emitX86Select(CIRGenBuilderTy &builder, mlir::Location loc, if (constOp && constOp.isAllOnesValue()) return op0; - mask = getMaskVecValue(builder, loc, mask, - cast<cir::VectorType>(op0.getType()).getSize()); + mask = getMaskVecValue( + builder, loc, mask, + cast<cir::VectorType>(op0.getType()).getSize().getFixedValue()); return cir::VecTernaryOp::create(builder, loc, mask, op0, op1); } @@ -385,7 +387,8 @@ emitX86MaskedCompare(CIRGenBuilderTy &builder, unsigned cc, bool isSigned, ArrayRef<mlir::Value> ops, mlir::Location loc) { assert((ops.size() == 2 || ops.size() == 4) && "Unexpected number of arguments"); - unsigned numElts = cast<cir::VectorType>(ops[0].getType()).getSize(); + unsigned numElts = + cast<cir::VectorType>(ops[0].getType()).getSize().getFixedValue(); mlir::Value cmp; if (cc == 3) { cmp = builder.getNullValue( @@ -447,7 +450,8 @@ static std::optional<mlir::Value> emitX86SExtMask(CIRGenBuilderTy &builder, mlir::Value op, mlir::Type dstTy, mlir::Location loc) { - unsigned numberOfElements = cast<cir::VectorType>(dstTy).getSize(); + unsigned numberOfElements = + cast<cir::VectorType>(dstTy).getSize().getFixedValue(); mlir::Value mask = getMaskVecValue(builder, loc, op, numberOfElements); return builder.createCast(loc, cir::CastKind::integral, mask, dstTy); @@ -456,7 +460,8 @@ static std::optional<mlir::Value> emitX86SExtMask(CIRGenBuilderTy &builder, static mlir::Value emitVecInsert(CIRGenBuilderTy &builder, mlir::Location loc, mlir::Value vec, mlir::Value value, mlir::Value indexOp) { - unsigned numElts = cast<cir::VectorType>(vec.getType()).getSize(); + unsigned numElts = + cast<cir::VectorType>(vec.getType()).getSize().getFixedValue(); uint64_t index = indexOp.getDefiningOp<cir::ConstantOp>().getIntValue().getZExtValue(); @@ -479,7 +484,7 @@ static mlir::Value emitX86FunnelShift(CIRGenBuilderTy &builder, // so we only care about the lowest log2 bits anyway. if (amt.getType() != op0Ty) { auto vecTy = mlir::cast<cir::VectorType>(op0Ty); - uint64_t numElems = vecTy.getSize(); + uint64_t numElems = vecTy.getSize().getFixedValue(); auto amtTy = mlir::cast<cir::IntType>(amt.getType()); auto vecElemTy = mlir::cast<cir::IntType>(vecTy.getElementType()); @@ -554,11 +559,12 @@ static mlir::Value emitX86CvtF16ToFloatExpr(CIRGenBuilderTy &builder, } } - unsigned numElts = cast<cir::VectorType>(dstTy).getSize(); + unsigned numElts = cast<cir::VectorType>(dstTy).getSize().getFixedValue(); mlir::Value src = ops[0]; // Extract the subvector - if (numElts != cast<cir::VectorType>(src.getType()).getSize()) { + if (numElts != + cast<cir::VectorType>(src.getType()).getSize().getFixedValue()) { assert(numElts == 4 && "Unexpected vector size"); src = builder.createVecShuffle(loc, src, {0, 1, 2, 3}); } @@ -635,7 +641,8 @@ static mlir::Value emitX86vpcom(CIRGenBuilderTy &builder, mlir::Location loc, static mlir::Value emitX86Fpclass(CIRGenBuilderTy &builder, mlir::Location loc, unsigned builtinID, SmallVectorImpl<mlir::Value> &ops) { - unsigned numElts = cast<cir::VectorType>(ops[0].getType()).getSize(); + unsigned numElts = + cast<cir::VectorType>(ops[0].getType()).getSize().getFixedValue(); mlir::Value maskIn = ops[2]; ops.erase(ops.begin() + 2); @@ -810,8 +817,9 @@ static mlir::Value emitX86MaskedLoad(CIRGenBuilderTy &builder, mlir::Location loc) { mlir::Type ty = ops[1].getType(); mlir::Value ptr = ops[0]; - mlir::Value maskVec = getMaskVecValue(builder, loc, ops[2], - cast<cir::VectorType>(ty).getSize()); + mlir::Value maskVec = + getMaskVecValue(builder, loc, ops[2], + cast<cir::VectorType>(ty).getSize().getFixedValue()); return builder.createMaskedLoad(loc, ty, ptr, alignment, maskVec, ops[1]); } @@ -820,7 +828,7 @@ static mlir::Value emitX86VPerm2f128(CIRGenBuilderTy &builder, mlir::Location loc, llvm::SmallVector<mlir::Value> ops) { auto inputType = cast<cir::VectorType>(ops[0].getType()); - assert(!inputType.getIsScalable() && + assert(!inputType.getSize().isScalable() && "This is only intended for fixed-width vectors"); const uint8_t imm = CIRGenFunction::getZExtIntValueFromConstOp(ops[2]); @@ -834,7 +842,7 @@ static mlir::Value emitX86VPerm2f128(CIRGenBuilderTy &builder, llvm::SmallVector<mlir::Attribute, 64> mask; cir::IntType i32Ty = builder.getSInt32Ty(); - const unsigned numElts = inputType.getSize(); + const unsigned numElts = inputType.getSize().getFixedValue(); // We must evaluated each lane(128 bits) separetely for (auto lane : llvm::seq(0, 2)) { bool isZeroBit = imm & (1 << ((lane * 4) + 3)), @@ -865,7 +873,7 @@ static mlir::Value emitX86PackedByteShift(CIRGenBuilderTy &builder, llvm::ArrayRef<mlir::Value> ops, llvm::Boolean isLeftShift) { auto byteVecType = cast<cir::VectorType>(ops[0].getType()); - assert(!byteVecType.getIsScalable() && + assert(!byteVecType.getSize().isScalable() && "This is only intended for fixed-width vectors"); unsigned shiftVal = CIRGenFunction::getZExtIntValueFromConstOp(ops[1]) & 0xFF; @@ -877,7 +885,7 @@ static mlir::Value emitX86PackedByteShift(CIRGenBuilderTy &builder, if (shiftVal >= 16) return zeroVector; - uint64_t numElts = byteVecType.getSize(); + uint64_t numElts = byteVecType.getSize().getFixedValue(); assert(numElts % 16 == 0 && "Expected a multiple of 16"); llvm::SmallVector<int64_t, 64> shuffleMask; @@ -1185,7 +1193,8 @@ CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID, const CallExpr *expr) { case X86::BI__builtin_ia32_vec_ext_v16hi: case X86::BI__builtin_ia32_vec_ext_v8si: case X86::BI__builtin_ia32_vec_ext_v4di: { - unsigned numElts = cast<cir::VectorType>(ops[0].getType()).getSize(); + unsigned numElts = + cast<cir::VectorType>(ops[0].getType()).getSize().getFixedValue(); uint64_t index = getZExtIntValueFromConstOp(ops[1]); index &= numElts - 1; @@ -1673,9 +1682,9 @@ CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID, const CallExpr *expr) { } mlir::Location loc = getLoc(expr->getExprLoc()); - unsigned minElts = - std::min(cast<cir::VectorType>(ops[0].getType()).getSize(), - cast<cir::VectorType>(ops[2].getType()).getSize()); + unsigned minElts = std::min( + cast<cir::VectorType>(ops[0].getType()).getSize().getFixedValue(), + cast<cir::VectorType>(ops[2].getType()).getSize().getFixedValue()); ops[3] = getMaskVecValue(builder, loc, ops[3], minElts); return builder.emitIntrinsicCallOp(loc, intrinsicName, convertType(expr->getType()), ops); @@ -1783,9 +1792,9 @@ CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID, const CallExpr *expr) { } mlir::Location loc = getLoc(expr->getExprLoc()); - unsigned minElts = - std::min(cast<cir::VectorType>(ops[2].getType()).getSize(), - cast<cir::VectorType>(ops[3].getType()).getSize()); + unsigned minElts = std::min( + cast<cir::VectorType>(ops[2].getType()).getSize().getFixedValue(), + cast<cir::VectorType>(ops[3].getType()).getSize().getFixedValue()); ops[1] = getMaskVecValue(builder, loc, ops[1], minElts); return builder.emitIntrinsicCallOp(loc, intrinsicName, @@ -1809,8 +1818,9 @@ CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID, const CallExpr *expr) { case X86::BI__builtin_ia32_extracti64x2_512_mask: { mlir::Location loc = getLoc(expr->getExprLoc()); cir::VectorType dstTy = cast<cir::VectorType>(convertType(expr->getType())); - unsigned numElts = dstTy.getSize(); - unsigned srcNumElts = cast<cir::VectorType>(ops[0].getType()).getSize(); + unsigned numElts = dstTy.getSize().getFixedValue(); + unsigned srcNumElts = + cast<cir::VectorType>(ops[0].getType()).getSize().getFixedValue(); unsigned subVectors = srcNumElts / numElts; assert(llvm::isPowerOf2_32(subVectors) && "Expected power of 2 subvectors"); unsigned index = @@ -1847,8 +1857,10 @@ CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID, const CallExpr *expr) { case X86::BI__builtin_ia32_inserti64x2_256: case X86::BI__builtin_ia32_insertf64x2_512: case X86::BI__builtin_ia32_inserti64x2_512: { - unsigned dstNumElts = cast<cir::VectorType>(ops[0].getType()).getSize(); - unsigned srcNumElts = cast<cir::VectorType>(ops[1].getType()).getSize(); + unsigned dstNumElts = + cast<cir::VectorType>(ops[0].getType()).getSize().getFixedValue(); + unsigned srcNumElts = + cast<cir::VectorType>(ops[1].getType()).getSize().getFixedValue(); unsigned subVectors = dstNumElts / srcNumElts; assert(llvm::isPowerOf2_32(subVectors) && "Expected power of 2 subvectors"); assert(dstNumElts <= 16); @@ -1890,7 +1902,8 @@ CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID, const CallExpr *expr) { case X86::BI__builtin_ia32_pblendd128: case X86::BI__builtin_ia32_pblendd256: { uint32_t imm = getZExtIntValueFromConstOp(ops[2]); - unsigned numElts = cast<cir::VectorType>(ops[0].getType()).getSize(); + unsigned numElts = + cast<cir::VectorType>(ops[0].getType()).getSize().getFixedValue(); llvm::SmallVector<mlir::Attribute, 16> indices; // If there are more than 8 elements, the immediate is used twice so make @@ -1949,7 +1962,8 @@ CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID, const CallExpr *expr) { case X86::BI__builtin_ia32_permdf512: { unsigned imm = ops[1].getDefiningOp<cir::ConstantOp>().getIntValue().getZExtValue(); - unsigned numElts = cast<cir::VectorType>(ops[0].getType()).getSize(); + unsigned numElts = + cast<cir::VectorType>(ops[0].getType()).getSize().getFixedValue(); // These intrinsics operate on 256-bit lanes of four 64-bit elements. int64_t Indices[8]; @@ -1966,7 +1980,8 @@ CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID, const CallExpr *expr) { case X86::BI__builtin_ia32_palignr512: { uint32_t shiftVal = getZExtIntValueFromConstOp(ops[2]) & 0xff; - unsigned numElts = cast<cir::VectorType>(ops[0].getType()).getSize(); + unsigned numElts = + cast<cir::VectorType>(ops[0].getType()).getSize().getFixedValue(); assert(numElts % 16 == 0); // If palignr is shifting the pair of vectors more than the size of two @@ -2004,7 +2019,8 @@ CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID, const CallExpr *expr) { case X86::BI__builtin_ia32_alignq128: case X86::BI__builtin_ia32_alignq256: case X86::BI__builtin_ia32_alignq512: { - unsigned numElts = cast<cir::VectorType>(ops[0].getType()).getSize(); + unsigned numElts = + cast<cir::VectorType>(ops[0].getType()).getSize().getFixedValue(); unsigned shiftVal = ops[2].getDefiningOp<cir::ConstantOp>().getIntValue().getZExtValue() & 0xff; @@ -2034,7 +2050,8 @@ CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID, const CallExpr *expr) { unsigned imm = ops[2].getDefiningOp<cir::ConstantOp>().getIntValue().getZExtValue(); - unsigned numElems = cast<cir::VectorType>(src1.getType()).getSize(); + unsigned numElems = + cast<cir::VectorType>(src1.getType()).getSize().getFixedValue(); unsigned totalBits = getContext().getTypeSize(expr->getArg(0)->getType()); unsigned numLanes = totalBits == 512 ? 4 : 2; unsigned numElemsPerLane = numElems / numLanes; @@ -2546,7 +2563,8 @@ CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID, const CallExpr *expr) { case X86::BI__builtin_ia32_vp2intersect_d_512: case X86::BI__builtin_ia32_vp2intersect_d_256: case X86::BI__builtin_ia32_vp2intersect_d_128: { - unsigned numElts = cast<cir::VectorType>(ops[0].getType()).getSize(); + unsigned numElts = + cast<cir::VectorType>(ops[0].getType()).getSize().getFixedValue(); mlir::Location loc = getLoc(expr->getExprLoc()); StringRef intrinsicName; @@ -2687,7 +2705,7 @@ CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID, const CallExpr *expr) { cir::VectorType resTy = cast<cir::VectorType>(convertType(expr->getType())); cir::VectorType inputTy = cast<cir::VectorType>(ops[0].getType()); - unsigned numElts = inputTy.getSize(); + unsigned numElts = inputTy.getSize().getFixedValue(); mlir::Value mask = getMaskVecValue(builder, loc, ops[2], numElts); diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index 9c71d987c37e16..bdf17087d89304 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -350,7 +350,8 @@ void CIRGenFunction::emitStoreThroughExtVectorComponentLValue(RValue src, mlir::Value vec = builder.createLoad(loc, dstAddr, dst.isVolatile()); if (const auto *vecTy = dst.getType()->getAs<clang::VectorType>()) { unsigned numSrcElts = vecTy->getNumElements(); - unsigned numDstElts = cast<cir::VectorType>(vec.getType()).getSize(); + unsigned numDstElts = + cast<cir::VectorType>(vec.getType()).getSize().getFixedValue(); if (numDstElts == numSrcElts) { // Use shuffle vector is the src and destination are the same number of // elements and restore the vector mask since it is on the side it will be diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index 8e8eea7c21ab55..a2c898b2e952ce 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -1619,12 +1619,14 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> { mlir::Type srcTy = src.getType(); mlir::Type dstTy = cgf.convertType(e->getType()); - unsigned numElementsSrc = isa<cir::VectorType>(srcTy) - ? cast<cir::VectorType>(srcTy).getSize() - : 0; - unsigned numElementsDst = isa<cir::VectorType>(dstTy) - ? cast<cir::VectorType>(dstTy).getSize() - : 0; + unsigned numElementsSrc = + isa<cir::VectorType>(srcTy) + ? cast<cir::VectorType>(srcTy).getSize().getFixedValue() + : 0; + unsigned numElementsDst = + isa<cir::VectorType>(dstTy) + ? cast<cir::VectorType>(dstTy).getSize().getFixedValue() + : 0; // Use bit vector expansion for ext_vector_type boolean vectors. if (e->getType()->isExtVectorBoolType()) { @@ -2994,11 +2996,12 @@ mlir::Value ScalarExprEmitter::VisitInitListExpr(InitListExpr *e) { } // Zero-initialize any remaining values. - if (numInitElements < vectorType.getSize()) { + const uint64_t vectorSize = vectorType.getSize().getFixedValue(); + if (numInitElements < vectorSize) { const mlir::Value zeroValue = cgf.getBuilder().getNullValue( vectorType.getElementType(), cgf.getLoc(e->getSourceRange())); - std::fill_n(std::back_inserter(elements), - vectorType.getSize() - numInitElements, zeroValue); + std::fill_n(std::back_inserter(elements), vectorSize - numInitElements, + zeroValue); } return cir::VecCreateOp::create(cgf.getBuilder(), @@ -3211,7 +3214,7 @@ mlir::Value ScalarExprEmitter::VisitUnaryExprOrTypeTraitExpr( return builder.getConstantInt(loc, cgf.cgm.sizeTy, alignment); } else if (e->getKind() == UETT_VectorElements) { auto vecTy = cast<cir::VectorType>(convertType(e->getTypeOfArgument())); - if (vecTy.getIsScalable()) { + if (vecTy.getSize().isScalable()) { cgf.getCIRGenModule().errorNYI( e->getSourceRange(), "VisitUnaryExprOrTypeTraitExpr: sizeOf scalable vector"); @@ -3221,7 +3224,8 @@ mlir::Value ScalarExprEmitter::VisitUnaryExprOrTypeTraitExpr( } return builder.getConstant( - loc, cir::IntAttr::get(cgf.cgm.sizeTy, vecTy.getSize())); + loc, + cir::IntAttr::get(cgf.cgm.sizeTy, vecTy.getSize().getFixedValue())); } // The result type is size_t (target-dependent width); use it so the IntAttr diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp index e1da57c9a38db7..92817f32024002 100644 --- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp @@ -378,56 +378,56 @@ mlir::Type CIRGenTypes::convertType(QualType type) { // SVE types case BuiltinType::SveInt8: - resultType = - cir::VectorType::get(builder.getSInt8Ty(), 16, /*is_scalable=*/true); + resultType = cir::VectorType::get(builder.getSInt8Ty(), + llvm::ElementCount::getScalable(16)); break; case BuiltinType::SveUint8: - resultType = - cir::VectorType::get(builder.getUInt8Ty(), 16, /*is_scalable=*/true); + resultType = cir::VectorType::get(builder.getUInt8Ty(), + llvm::ElementCount::getScalable(16)); break; case BuiltinType::SveInt16: - resultType = - cir::VectorType::get(builder.getSInt16Ty(), 8, /*is_scalable=*/true); + resultType = cir::VectorType::get(builder.getSInt16Ty(), + llvm::ElementCount::getScalable(8)); break; case BuiltinType::SveUint16: - resultType = - cir::VectorType::get(builder.getUInt16Ty(), 8, /*is_scalable=*/true); + resultType = cir::VectorType::get(builder.getUInt16Ty(), + llvm::ElementCount::getScalable(8)); break; case BuiltinType::SveFloat16: - resultType = cir::VectorType::get(builder.getFp16Ty(), 8, - /*is_scalable=*/true); + resultType = cir::VectorType::get(builder.getFp16Ty(), + llvm::ElementCount::getScalable(8)); break; case BuiltinType::SveBFloat16: - resultType = cir::VectorType::get(builder.getBfloat16Ty(), 8, - /*is_scalable=*/true); + resultType = cir::VectorType::get(builder.getBfloat16Ty(), + llvm::ElementCount::getScalable(8)); break; case BuiltinType::SveInt32: - resultType = - cir::VectorType::get(builder.getSInt32Ty(), 4, /*is_scalable=*/true); + resultType = cir::VectorType::get(builder.getSInt32Ty(), + llvm::ElementCount::getScalable(4)); break; case BuiltinType::SveUint32: - resultType = - cir::VectorType::get(builder.getUInt32Ty(), 4, /*is_scalable=*/true); + resultType = cir::VectorType::get(builder.getUInt32Ty(), + llvm::ElementCount::getScalable(4)); break; case BuiltinType::SveFloat32: - resultType = cir::VectorType::get(builder.getSingleTy(), 4, - /*is_scalable=*/true); + resultType = cir::VectorType::get(builder.getSingleTy(), + llvm::ElementCount::getScalable(4)); break; case BuiltinType::SveInt64: - resultType = - cir::VectorType::get(builder.getSInt64Ty(), 2, /*is_scalable=*/true); + resultType = cir::VectorType::get(builder.getSInt64Ty(), + llvm::ElementCount::getScalable(2)); break; case BuiltinType::SveUint64: - resultType = - cir::VectorType::get(builder.getUInt64Ty(), 2, /*is_scalable=*/true); + resultType = cir::VectorType::get(builder.getUInt64Ty(), + llvm::ElementCount::getScalable(2)); break; case BuiltinType::SveFloat64: - resultType = cir::VectorType::get(builder.getDoubleTy(), 2, - /*is_scalable=*/true); + resultType = cir::VectorType::get(builder.getDoubleTy(), + llvm::ElementCount::getScalable(2)); break; case BuiltinType::SveBool: - resultType = cir::VectorType::get(builder.getUIntNTy(1), 16, - /*is_scalable=*/true); + resultType = cir::VectorType::get(builder.getUIntNTy(1), + llvm::ElementCount::getScalable(16)); break; // Unsigned integral types. diff --git a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp index 2649ed14497393..267fec81828e68 100644 --- a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp @@ -902,7 +902,10 @@ cir::ConstVectorAttr::verify(function_ref<InFlightDiagnostic()> emitError, const auto vecType = mlir::cast<cir::VectorType>(type); - if (vecType.getSize() != elts.size()) + if (vecType.getSize().isScalable()) + return emitError() << "scalable vector constants are not supported"; + + if (vecType.getSize().getFixedValue() != elts.size()) return emitError() << "number of constant elements should match vector size"; diff --git a/clang/lib/CIR/Dialect/IR/CIRDataLayout.cpp b/clang/lib/CIR/Dialect/IR/CIRDataLayout.cpp index 5ce0c8f8e7a2c6..2347edcfee161d 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDataLayout.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDataLayout.cpp @@ -56,5 +56,5 @@ llvm::TypeSize CIRDataLayout::getTypeSizeInBits(mlir::Type ty) const { assert(!cir::MissingFeatures::addressSpace()); // This is calling mlir::DataLayout::getTypeSizeInBits(). - return llvm::TypeSize::getFixed(layout.getTypeSizeInBits(ty)); + return layout.getTypeSizeInBits(ty); } diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 3088a39e5a4d0a..4da147ea5e0dfe 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -4161,10 +4161,14 @@ LogicalResult cir::VecCreateOp::verify() { // vector, and that the type of all the arguments matches the type of the // elements in the vector. const cir::VectorType vecTy = getType(); - if (getElements().size() != vecTy.getSize()) { + if (vecTy.getSize().isScalable()) + return emitOpError() << "scalable vectors are not supported"; + + if (getElements().size() != vecTy.getSize().getFixedValue()) { return emitOpError() << "operand count of " << getElements().size() << " doesn't match vector type " << vecTy - << " element count of " << vecTy.getSize(); + << " element count of " + << vecTy.getSize().getFixedValue(); } const mlir::Type elementType = vecTy.getElementType(); @@ -4401,9 +4405,14 @@ OpFoldResult cir::VecShuffleOp::fold(FoldAdaptor adaptor) { } LogicalResult cir::VecShuffleOp::verify() { + if (getVec1().getType().getSize().isScalable() || + getVec2().getType().getSize().isScalable() || + getResult().getType().getSize().isScalable()) + return emitOpError() << "scalable vectors are not supported"; + // The number of elements in the indices array must match the number of // elements in the result type. - if (getIndices().size() != getResult().getType().getSize()) { + if (getIndices().size() != getResult().getType().getSize().getFixedValue()) { return emitOpError() << ": the number of elements in " << getIndices() << " and " << getResult().getType() << " don't match"; } @@ -4416,8 +4425,9 @@ LogicalResult cir::VecShuffleOp::verify() { << " and " << getResult().getType() << " don't match"; } - const uint64_t maxValidIndex = - getVec1().getType().getSize() + getVec2().getType().getSize() - 1; + const uint64_t maxValidIndex = getVec1().getType().getSize().getFixedValue() + + getVec2().getType().getSize().getFixedValue() - + 1; if (llvm::any_of( getIndices().getAsRange<cir::IntAttr>(), [&](cir::IntAttr idxAttr) { return idxAttr.getSInt() != -1 && idxAttr.getUInt() > maxValidIndex; diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp index 061d15cc3a0885..545f3668df873e 100644 --- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp @@ -1496,32 +1496,35 @@ llvm::TypeSize cir::VectorType::getTypeSizeInBits( ::mlir::DataLayoutEntryListRef params) const { // Clang packs a fixed-length bool vector one bit per element and rounds the // vector's size up to a power of two of at least a byte. - if (mlir::isa<cir::BoolType>(getElementType()) && !getIsScalable()) { + if (mlir::isa<cir::BoolType>(getElementType()) && getSize().isFixed()) { assert(!cir::MissingFeatures::hlsl()); return llvm::TypeSize::getFixed(llvm::PowerOf2Ceil(getBoolStorageWidth())); } - return llvm::TypeSize::getFixed( - getSize() * dataLayout.getTypeSizeInBits(getElementType())); + + llvm::TypeSize elementSize = dataLayout.getTypeSizeInBits(getElementType()); + return llvm::TypeSize::get(getSize().getKnownMinValue() * + elementSize.getFixedValue(), + getSize().isScalable()); } uint64_t cir::VectorType::getBoolStorageWidth() const { assert(mlir::isa<cir::BoolType>(getElementType()) && "only a bool vector is stored as an integer"); - return std::max<uint64_t>(getSize(), 8); + return std::max<uint64_t>(getSize().getFixedValue(), 8); } uint64_t cir::VectorType::getABIAlignment(const ::mlir::DataLayout &dataLayout, ::mlir::DataLayoutEntryListRef params) const { // This hook answers in bytes, not bits. - return llvm::PowerOf2Ceil( - llvm::divideCeil(dataLayout.getTypeSizeInBits(*this), 8u)); + return llvm::PowerOf2Ceil(llvm::divideCeil( + dataLayout.getTypeSizeInBits(*this).getKnownMinValue(), uint64_t{8})); } mlir::LogicalResult cir::VectorType::verify( llvm::function_ref<mlir::InFlightDiagnostic()> emitError, - mlir::Type elementType, uint64_t size, bool scalable) { - if (size == 0) + mlir::Type elementType, llvm::ElementCount size) { + if (size.isZero()) return emitError() << "the number of vector elements must be non-zero"; return success(); } @@ -1532,7 +1535,7 @@ mlir::Type cir::VectorType::parse(::mlir::AsmParser &odsParser) { mlir::Builder odsBuilder(odsParser.getContext()); mlir::FailureOr<::mlir::Type> elementType; mlir::FailureOr<uint64_t> size; - bool isScalabe = false; + bool isScalable = false; // Parse literal '<' if (odsParser.parseLess()) @@ -1540,7 +1543,7 @@ mlir::Type cir::VectorType::parse(::mlir::AsmParser &odsParser) { // Parse literal '[', if present, and set the scalability flag accordingly if (odsParser.parseOptionalLSquare().succeeded()) - isScalabe = true; + isScalable = true; // Parse variable 'size' size = mlir::FieldParser<uint64_t>::parse(odsParser); @@ -1553,7 +1556,7 @@ mlir::Type cir::VectorType::parse(::mlir::AsmParser &odsParser) { // Parse literal ']', which is expected when dealing with scalable // dim sizes - if (isScalabe && odsParser.parseRSquare().failed()) { + if (isScalable && odsParser.parseRSquare().failed()) { odsParser.emitError(odsParser.getCurrentLocation(), "missing closing `]` for scalable dim size"); return {}; @@ -1575,19 +1578,19 @@ mlir::Type cir::VectorType::parse(::mlir::AsmParser &odsParser) { // Parse literal '>' if (odsParser.parseGreater()) return {}; - return odsParser.getChecked<VectorType>(odsLoc, odsParser.getContext(), - mlir::Type((*elementType)), - uint64_t((*size)), isScalabe); + return odsParser.getChecked<VectorType>( + odsLoc, odsParser.getContext(), mlir::Type((*elementType)), + llvm::ElementCount::get(*size, isScalable)); } void cir::VectorType::print(mlir::AsmPrinter &odsPrinter) const { mlir::Builder odsBuilder(getContext()); odsPrinter << "<"; - if (this->getIsScalable()) + if (getSize().isScalable()) odsPrinter << "["; - odsPrinter.printStrippedAttrOrType(getSize()); - if (this->getIsScalable()) + odsPrinter.printStrippedAttrOrType(getSize().getKnownMinValue()); + if (getSize().isScalable()) odsPrinter << "]"; odsPrinter << ' ' << "x"; odsPrinter << ' '; diff --git a/clang/lib/CIR/Dialect/Transforms/CIRSimplify.cpp b/clang/lib/CIR/Dialect/Transforms/CIRSimplify.cpp index 9d569be7b80cb0..72807f877bf143 100644 --- a/clang/lib/CIR/Dialect/Transforms/CIRSimplify.cpp +++ b/clang/lib/CIR/Dialect/Transforms/CIRSimplify.cpp @@ -375,9 +375,10 @@ struct SimplifyVecSplat : public OpRewritePattern<VecSplatOp> { // we can simplify it here too. assert(!MissingFeatures::matrixType()); auto resultType = mlir::dyn_cast<cir::VectorType>(op.getResult().getType()); - if (!resultType) + if (!resultType || resultType.getSize().isScalable()) return mlir::failure(); - SmallVector<mlir::Attribute, 16> elements(resultType.getSize(), value); + SmallVector<mlir::Attribute, 16> elements( + resultType.getSize().getFixedValue(), value); auto constVecAttr = cir::ConstVectorAttr::get( resultType, mlir::ArrayAttr::get(getContext(), elements)); diff --git a/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp b/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp index e7632bdcb700d2..6f293dd8b408d4 100644 --- a/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp +++ b/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp @@ -254,7 +254,7 @@ static bool isSupportedType(mlir::Type ty, const DataLayout &dl) { if (auto vecTy = dyn_cast<cir::VectorType>(ty)) { // A scalable vector has no size the SysV eightbyte rules can read, and // x86_64 has no calling convention for one. - if (vecTy.getIsScalable()) + if (vecTy.getSize().isScalable()) return false; // mapCIRType maps a bool as a one-bit integer, so a bool vector is sized // one bit per element, as clang packs it. Vectors of a _BitInt whose @@ -413,8 +413,8 @@ static mlir::Type unwrapLongDoubleVectorElement(mlir::Type ty) { if (auto vecTy = dyn_cast<cir::VectorType>(ty)) { if (auto longDoubleTy = dyn_cast<cir::LongDoubleType>(vecTy.getElementType())) - return cir::VectorType::get(longDoubleTy.getUnderlying(), vecTy.getSize(), - vecTy.getIsScalable()); + return cir::VectorType::get(longDoubleTy.getUnderlying(), + vecTy.getSize()); } return ty; } @@ -472,8 +472,7 @@ static const llvm::abi::Type *mapCIRType(mlir::Type type, // always fixed here. return tb.getVectorType( mapCIRType(vecTy.getElementType(), typeMapper, dl, modOp), - llvm::ElementCount::getFixed(vecTy.getSize()), - llvm::Align(dl.getTypeABIAlignment(type))); + vecTy.getSize(), llvm::Align(dl.getTypeABIAlignment(type))); }) .Case([&](cir::ArrayType arrTy) { const llvm::abi::Type *elemAbi = diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 7b29331b762ad8..44a2f064eecff9 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -175,6 +175,8 @@ static mlir::Value emitFromMemory(mlir::ConversionPatternRewriter &rewriter, // Convert the `iN` back to boolean vectors if (auto vecTy = mlir::dyn_cast<cir::VectorType>(op.getType())) { if (mlir::isa<cir::BoolType>(vecTy.getElementType())) { + if (vecTy.getSize().isScalable()) + return value; auto rawIntTy = mlir::cast<mlir::IntegerType>(value.getType()); auto paddedVecTy = cir::VectorType::get(vecTy.getElementType(), rawIntTy.getWidth()); @@ -183,7 +185,8 @@ static mlir::Value emitFromMemory(mlir::ConversionPatternRewriter &rewriter, auto v = mlir::LLVM::BitcastOp::create(rewriter, value.getLoc(), mlirVecTy, value); // Shuffle <P x i1> --> <N x i1> (N is the actual bit size). - return emitBoolVecConversion(rewriter, v, vecTy.getSize()); + return emitBoolVecConversion(rewriter, v, + vecTy.getSize().getFixedValue()); } } @@ -218,9 +221,10 @@ static mlir::Value emitToMemory(mlir::ConversionPatternRewriter &rewriter, if (auto vecTy = mlir::dyn_cast<cir::VectorType>(origType)) { if (mlir::isa<cir::BoolType>(vecTy.getElementType())) { mlir::Type resultTy; - if (vecTy.getIsScalable()) - resultTy = mlir::VectorType::get( - vecTy.getSize(), vecTy.getElementType(), vecTy.getIsScalable()); + if (vecTy.getSize().isScalable()) + resultTy = mlir::VectorType::get(vecTy.getSize().getKnownMinValue(), + vecTy.getElementType(), + vecTy.getSize().isScalable()); else { resultTy = mlir::IntegerType::get(origType.getContext(), vecTy.getBoolStorageWidth()); @@ -3544,13 +3548,11 @@ mlir::LogicalResult CIRToLLVMNotOpLowering::matchAndRewrite( if (mlir::isa<cir::IntType>(elementType)) { mlir::Value minusOne; if (isVector) { - const uint64_t numElements = - mlir::cast<cir::VectorType>(op.getType()).getSize(); const unsigned eltWidth = mlir::cast<cir::IntType>(elementType).getWidth(); - SmallVector<APInt> values(numElements, APInt::getAllOnes(eltWidth)); - mlir::DenseIntElementsAttr denseVec = mlir::DenseIntElementsAttr::get( - mlir::cast<mlir::ShapedType>(llvmType), values); + mlir::DenseElementsAttr denseVec = + mlir::DenseElementsAttr::get(mlir::cast<mlir::ShapedType>(llvmType), + {APInt::getAllOnes(eltWidth)}); minusOne = mlir::LLVM::ConstantOp::create(rewriter, loc, llvmType, denseVec); } else { @@ -3566,10 +3568,8 @@ mlir::LogicalResult CIRToLLVMNotOpLowering::matchAndRewrite( if (mlir::isa<cir::BoolType>(elementType)) { mlir::Value one; if (isVector) { - const uint64_t numElements = - mlir::cast<cir::VectorType>(op.getType()).getSize(); - SmallVector<bool> values(numElements, true); - mlir::DenseIntElementsAttr denseVec = rewriter.getBoolVectorAttr(values); + mlir::DenseElementsAttr denseVec = mlir::DenseElementsAttr::get( + mlir::cast<mlir::ShapedType>(llvmType), {APInt(1, 1)}); one = mlir::LLVM::ConstantOp::create(rewriter, loc, llvmType, denseVec); } else { one = mlir::LLVM::ConstantOp::create(rewriter, loc, llvmType, 1); @@ -4194,7 +4194,8 @@ static void prepareTypeConverter(mlir::LLVMTypeConverter &converter, intTy && intTy.isBitInt()) return {}; const mlir::Type ty = converter.convertType(type.getElementType()); - return mlir::VectorType::get(type.getSize(), ty, {type.getIsScalable()}); + return mlir::VectorType::get(type.getSize().getKnownMinValue(), ty, + {type.getSize().isScalable()}); }); converter.addConversion([&](cir::MatrixType type) -> mlir::Type { const uint64_t size = type.getNumRows() * type.getNumColumns(); @@ -5225,10 +5226,11 @@ mlir::LogicalResult CIRToLLVMVecCreateOpLowering::matchAndRewrite( const mlir::Type llvmTy = typeConverter->convertType(vecTy); const mlir::Location loc = op.getLoc(); mlir::Value result = mlir::LLVM::PoisonOp::create(rewriter, loc, llvmTy); - assert(vecTy.getSize() == op.getElements().size() && + const uint64_t vectorSize = vecTy.getSize().getFixedValue(); + assert(vectorSize == op.getElements().size() && "cir.vec.create op count doesn't match vector type elements count"); - for (uint64_t i = 0; i < vecTy.getSize(); ++i) { + for (uint64_t i = 0; i < vectorSize; ++i) { const mlir::Value indexValue = mlir::LLVM::ConstantOp::create(rewriter, loc, rewriter.getI64Type(), i); result = mlir::LLVM::InsertElementOp::create( @@ -5320,8 +5322,9 @@ mlir::LogicalResult CIRToLLVMVecCmpOpLowering::matchAndRewrite( adaptor.getLhs(), adaptor.getRhs()); } else if (mlir::isa<cir::FPTypeInterface>(elementType)) { if (cir::FenvAttr fenv = op.getFenvAttr()) { - auto i1VecTy = mlir::VectorType::get(op.getLhs().getType().getSize(), - rewriter.getI1Type()); + llvm::ElementCount size = op.getLhs().getType().getSize(); + auto i1VecTy = mlir::VectorType::get( + size.getKnownMinValue(), rewriter.getI1Type(), {size.isScalable()}); bitResult = createConstrainedFCmpCall(rewriter, op.getLoc(), adaptor.getLhs(), adaptor.getRhs(), op.getKind(), fenv, i1VecTy) @@ -5434,7 +5437,7 @@ mlir::LogicalResult CIRToLLVMVecShuffleDynamicOpLowering::matchAndRewrite( getTypeConverter()->convertType(op.getIndices().getType()); mlir::Type llvmIndexType = getTypeConverter()->convertType( op.getIndices().getType().getElementType()); - uint64_t numElements = op.getVec().getType().getSize(); + uint64_t numElements = op.getVec().getType().getSize().getFixedValue(); uint64_t maskBits = llvm::NextPowerOf2(numElements - 1) - 1; mlir::Value maskValue = mlir::LLVM::ConstantOp::create( diff --git a/clang/test/CIR/IR/invalid-vector.cir b/clang/test/CIR/IR/invalid-vector.cir index 6152ca4a7a9481..3af3d494c5fd55 100644 --- a/clang/test/CIR/IR/invalid-vector.cir +++ b/clang/test/CIR/IR/invalid-vector.cir @@ -11,6 +11,45 @@ cir.global external @vec_b = #cir.zero : !cir.vector<4 x !cir.array<!s32i x 10>> // ----- +!s32i = !cir.int<s, 32> + +module { + cir.func @scalable_vector_constant() { + // expected-error @below {{scalable vector constants are not supported}} + %0 = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<2> : !s32i]> : !cir.vector<[2] x !s32i> + cir.return + } +} + +// ----- + +!s32i = !cir.int<s, 32> + +module { + cir.func @scalable_vector_create() { + %0 = cir.const #cir.int<1> : !s32i + %1 = cir.const #cir.int<2> : !s32i + // expected-error @below {{scalable vectors are not supported}} + %2 = cir.vec.create(%0, %1 : !s32i, !s32i) : !cir.vector<[2] x !s32i> + cir.return + } +} + +// ----- + +!s32i = !cir.int<s, 32> + +module { + cir.func @scalable_vector_shuffle(%arg0: !cir.vector<[2] x !s32i>, + %arg1: !cir.vector<[2] x !s32i>) { + // expected-error @below {{scalable vectors are not supported}} + %0 = cir.vec.shuffle(%arg0, %arg1 : !cir.vector<[2] x !s32i>) [#cir.int<0> : !s32i, #cir.int<1> : !s32i] : !cir.vector<[2] x !s32i> + cir.return + } +} + +// ----- + cir.func @invalid_scalable_vec_syntax() { // expected-error@+2 {{missing closing `]` for scalable dim size}} // expected-error @below {{expected ']'}} diff --git a/clang/test/CIR/Lowering/not.cir b/clang/test/CIR/Lowering/not.cir index d93f33cd84ba4b..adf8431ccd4278 100644 --- a/clang/test/CIR/Lowering/not.cir +++ b/clang/test/CIR/Lowering/not.cir @@ -2,6 +2,7 @@ // RUN: cir-translate %s -cir-to-llvmir --target x86_64-unknown-linux-gnu --disable-cc-lowering | FileCheck %s -check-prefix=LLVM !s128i = !cir.int<s, 128> +!s32i = !cir.int<s, 32> !u128i = !cir.int<u, 128> module attributes { cir.triple = "x86_64-unknown-linux-gnu" } { @@ -30,4 +31,17 @@ cir.func @unsigned(%arg: !u128i) -> !u128i { // LLVM: define i128 @unsigned(i128 %[[ARG:.*]]) // LLVM: %[[INVERT:.*]] = xor i128 %[[ARG]], -1 // LLVM: ret i128 %[[INVERT]] + +cir.func @scalable_vector(%arg: !cir.vector<[4] x !s32i>) -> !cir.vector<[4] x !s32i> { + %inverted = cir.not %arg : !cir.vector<[4] x !s32i> + cir.return %inverted : !cir.vector<[4] x !s32i> +} +// MLIR: llvm.func @scalable_vector(%[[ARG:.*]]: vector<[4]xi32>) -> vector<[4]xi32> +// MLIR: %[[NEG_ONE:.*]] = llvm.mlir.constant(dense<-1> : vector<[4]xi32>) : vector<[4]xi32> +// MLIR: %[[INVERT:.*]] = llvm.xor %[[ARG]], %[[NEG_ONE]] : vector<[4]xi32> +// MLIR: llvm.return %[[INVERT]] : vector<[4]xi32> + +// LLVM: define <vscale x 4 x i32> @scalable_vector(<vscale x 4 x i32> %[[ARG:.*]]) +// LLVM: %[[INVERT:.*]] = xor <vscale x 4 x i32> %[[ARG]], splat (i32 -1) +// LLVM: ret <vscale x 4 x i32> %[[INVERT]] } diff --git a/clang/test/CIR/Transforms/vector-splat.cir b/clang/test/CIR/Transforms/vector-splat.cir index 9b2b39d7f862e3..d444e2143d95dc 100644 --- a/clang/test/CIR/Transforms/vector-splat.cir +++ b/clang/test/CIR/Transforms/vector-splat.cir @@ -13,4 +13,15 @@ module { // CHECK-NEXT: %0 = cir.const #cir.const_vector<[#cir.int<3> : !s32i, #cir.int<3> : !s32i, // CHECK-SAME: #cir.int<3> : !s32i, #cir.int<3> : !s32i]> : !cir.vector<4 x !s32i> // CHECK-NEXT: cir.return %0 : !cir.vector<4 x !s32i> + + cir.func @do_not_fold_scalable_splat() -> !cir.vector<[4] x !s32i> { + %v = cir.const #cir.int<3> : !s32i + %vec = cir.vec.splat %v : !s32i, !cir.vector<[4] x !s32i> + cir.return %vec : !cir.vector<[4] x !s32i> + } + + // CHECK-LABEL: cir.func @do_not_fold_scalable_splat + // CHECK: %[[VALUE:.*]] = cir.const #cir.int<3> : !s32i + // CHECK-NEXT: %[[VEC:.*]] = cir.vec.splat %[[VALUE]] : !s32i, !cir.vector<[4] x !s32i> + // CHECK-NEXT: cir.return %[[VEC]] : !cir.vector<[4] x !s32i> } diff --git a/llvm/include/llvm/Support/TypeSize.h b/llvm/include/llvm/Support/TypeSize.h index 5a34c7daeb02f5..b9db5d5205dcd0 100644 --- a/llvm/include/llvm/Support/TypeSize.h +++ b/llvm/include/llvm/Support/TypeSize.h @@ -15,6 +15,7 @@ #ifndef LLVM_SUPPORT_TYPESIZE_H #define LLVM_SUPPORT_TYPESIZE_H +#include "llvm/ADT/Hashing.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" @@ -322,6 +323,10 @@ class ElementCount } }; +inline hash_code hash_value(const ElementCount &EC) { + return hash_combine(EC.getKnownMinValue(), EC.isScalable()); +} + // Stores the size of a type. If the type is of fixed size, it will represent // the exact size. If the type is a scalable vector, it will represent the known // minimum size. _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
