[clang] [llvm] [CIR] Use `llvm::ElementCount` to hold `cir::VectorType` size (PR #231906)
Benjamin Maxwell via cfe-commits
cfe-commits at lists.llvm.org
Wed Oct 14 09:53:41 PDT 2026
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 <benjamin.maxwell at arm.com>
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 at +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.
More information about the cfe-commits
mailing list