Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 79 additions & 27 deletions clang/lib/CIR/CodeGen/CIRGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,14 @@ CIRGenCallee CIRGenFunction::emitCallee(const clang::Expr *E) {

mlir::Value CIRGenFunction::emitToMemory(mlir::Value Value, QualType Ty) {
// Bool has a different representation in memory than in registers.

// ExtVectorBoolType: In ClangIR, ExtVectorBoolType is always represented
// as an integer type (!cir.int<u, N>) throughout the IR, including both
// in registers and in memory. This differs from traditional CodeGen where
// it may exist as a vector type that needs conversion to integer for storage.
// Since we use integer representation consistently, no conversion is needed.
// See CIRGenTypes.cpp:675-683 for the type conversion logic.

return Value;
}

Expand All @@ -653,18 +661,21 @@ void CIRGenFunction::emitStoreOfScalar(mlir::Value value, Address addr,

auto eltTy = addr.getElementType();
if (const auto *clangVecTy = ty->getAs<clang::VectorType>()) {
// Boolean vectors use `iN` as storage type.
// Boolean vectors use `iN` as storage type. The type conversion in
// CIRGenTypes::convertType (lines 675-683) returns an integer type for
// ExtVectorBoolType, so eltTy is already an integer. Skip vector
// optimizations for bool vectors since they're not actually vectors in CIR.
if (clangVecTy->isExtVectorBoolType()) {
llvm_unreachable("isExtVectorBoolType NYI");
}

// Handle vectors of size 3 like size 4 for better performance.
const auto vTy = cast<cir::VectorType>(eltTy);
auto newVecTy =
CGM.getABIInfo().getOptimalVectorMemoryType(vTy, getLangOpts());
// Storage is already an integer type, nothing special needed
} else {
// Handle vectors of size 3 like size 4 for better performance.
const auto vTy = cast<cir::VectorType>(eltTy);
auto newVecTy =
CGM.getABIInfo().getOptimalVectorMemoryType(vTy, getLangOpts());

if (vTy != newVecTy) {
llvm_unreachable("NYI");
if (vTy != newVecTy) {
llvm_unreachable("NYI");
}
}
}

Expand Down Expand Up @@ -868,6 +879,16 @@ void CIRGenFunction::emitStoreThroughLValue(RValue Src, LValue Dst,
bool isInit) {
if (!Dst.isSimple()) {
if (Dst.isVectorElt()) {
// Check if this is an ExtVectorBoolType element assignment
QualType vectorType = Dst.getType();
if (const auto *vecTy = vectorType->getAs<clang::VectorType>()) {
if (vecTy->isExtVectorBoolType()) {
llvm_unreachable(
"NYI: ExtVectorBoolType element assignment (requires bit "
"manipulation to set/clear individual bits in integer storage)");
}
}

// Read/modify/write the vector, inserting the new element
mlir::Location loc = Dst.getVectorPointer().getLoc();
mlir::Value Vector = builder.createLoad(loc, Dst.getVectorAddress());
Expand Down Expand Up @@ -2735,6 +2756,8 @@ LValue CIRGenFunction::emitLValue(const Expr *E) {
return emitStmtExprLValue(cast<StmtExpr>(E));
case Expr::ChooseExprClass:
return emitLValue(cast<ChooseExpr>(E)->getChosenSubExpr());
case Expr::CXXTypeidExprClass:
return emitCXXTypeidLValue(cast<CXXTypeidExpr>(E));
}

llvm_unreachable("NYI");
Expand Down Expand Up @@ -2956,6 +2979,13 @@ mlir::Value CIRGenFunction::emitFromMemory(mlir::Value Value, QualType Ty) {
llvm_unreachable("NIY");
}

// ExtVectorBoolType: In ClangIR, ExtVectorBoolType is always represented
// as an integer type (!cir.int<u, N>) throughout the IR, including both
// in registers and in memory. This differs from traditional CodeGen where
// it may need truncation from storage type to value type. Since we use
// integer representation consistently, no conversion is needed.
// See CIRGenTypes.cpp:675-683 for the type conversion logic.

return Value;
}

Expand All @@ -2977,24 +3007,27 @@ mlir::Value CIRGenFunction::emitLoadOfScalar(Address addr, bool isVolatile,
auto eltTy = addr.getElementType();

if (const auto *clangVecTy = ty->getAs<clang::VectorType>()) {
// Boolean vectors use `iN` as storage type.
// Boolean vectors use `iN` as storage type. The type conversion in
// CIRGenTypes::convertType (lines 675-683) returns an integer type for
// ExtVectorBoolType, so eltTy is already an integer. Skip vector
// optimizations for bool vectors since they're not actually vectors in CIR.
if (clangVecTy->isExtVectorBoolType()) {
llvm_unreachable("NYI");
}

// Handle vectors of size 3 like size 4 for better performance.
const auto vTy = cast<cir::VectorType>(eltTy);
auto newVecTy =
CGM.getABIInfo().getOptimalVectorMemoryType(vTy, getLangOpts());

if (vTy != newVecTy) {
const Address cast = addr.withElementType(builder, newVecTy);
mlir::Value v = builder.createLoad(loc, cast, isVolatile);
const uint64_t oldNumElements = vTy.getSize();
SmallVector<int64_t, 16> mask(oldNumElements);
std::iota(mask.begin(), mask.end(), 0);
v = builder.createVecShuffle(loc, v, mask);
return emitFromMemory(v, ty);
// Storage is already an integer type, nothing special needed
} else {
// Handle vectors of size 3 like size 4 for better performance.
const auto vTy = cast<cir::VectorType>(eltTy);
auto newVecTy =
CGM.getABIInfo().getOptimalVectorMemoryType(vTy, getLangOpts());

if (vTy != newVecTy) {
const Address cast = addr.withElementType(builder, newVecTy);
mlir::Value v = builder.createLoad(loc, cast, isVolatile);
const uint64_t oldNumElements = vTy.getSize();
SmallVector<int64_t, 16> mask(oldNumElements);
std::iota(mask.begin(), mask.end(), 0);
v = builder.createVecShuffle(loc, v, mask);
return emitFromMemory(v, ty);
}
}
}

Expand Down Expand Up @@ -3445,3 +3478,22 @@ RValue CIRGenFunction::emitPseudoObjectRValue(const PseudoObjectExpr *expr,
LValue CIRGenFunction::emitPseudoObjectLValue(const PseudoObjectExpr *expr) {
return emitPseudoObjectExpr(*this, expr, true, AggValueSlot::ignored()).lv;
}

LValue CIRGenFunction::emitCXXTypeidLValue(const CXXTypeidExpr *E) {
// Emit the typeid expression, which returns a pointer to the RTTI descriptor.
mlir::Value typeInfoPtr = emitCXXTypeidExpr(E);

// Cast the pointer to the actual type_info type for proper type safety.
auto typeInfoTy = convertTypeForMem(E->getType());
auto typeInfoPtrTy = builder.getPointerTo(typeInfoTy);
typeInfoPtr = builder.createBitcast(getLoc(E->getSourceRange()), typeInfoPtr,
typeInfoPtrTy);

// Create an LValue from the pointer with natural alignment.
// We use getTypeAlignInChars() which returns the natural alignment for the
// type_info type, matching traditional CodeGen's getNaturalTypeAlignment().
Address addr(typeInfoPtr, typeInfoTy,
getContext().getTypeAlignInChars(E->getType()));

return makeAddrLValue(addr, E->getType(), AlignmentSource::Decl);
}
42 changes: 37 additions & 5 deletions clang/lib/CIR/CodeGen/CIRGenExprConst.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1134,11 +1134,42 @@ class ConstExprEmitter
}

mlir::Attribute EmitVectorInitialization(InitListExpr *ILE, QualType T) {
cir::VectorType VecTy = mlir::cast<cir::VectorType>(CGM.convertType(T));
unsigned NumElements = VecTy.getSize();
auto *VecTy = T->castAs<VectorType>();

// ExtVectorBoolType uses integer storage, not vector type
if (VecTy->isExtVectorBoolType()) {
// For ExtVectorBoolType, the storage is an integer type
// Compute the value by packing bools into an integer
uint64_t numElements = VecTy->getNumElements();
unsigned numInits = ILE->getNumInits();
assert(numElements >= numInits && "Too many initializers for a vector");

// Create integer value by packing bool elements
uint64_t value = 0;
for (unsigned i = 0; i < numInits; ++i) {
auto Init = ILE->getInit(i);
Expr::EvalResult result;
if (!Init->EvaluateAsRValue(result, CGM.getASTContext()))
return {};
bool boolVal = result.Val.getInt().getBoolValue();
if (boolVal)
value |= (uint64_t(1) << i);
}

// Pad to at least 8 bits
uint64_t storageBits = std::max<uint64_t>(numElements, 8);
auto storageTy =
cir::IntType::get(CGM.getBuilder().getContext(), storageBits,
/*isSigned=*/false);
return cir::IntAttr::get(storageTy, value);
}

// Regular vector type
cir::VectorType CIRVecTy = mlir::cast<cir::VectorType>(CGM.convertType(T));
unsigned NumElements = CIRVecTy.getSize();
unsigned NumInits = ILE->getNumInits();
assert(NumElements >= NumInits && "Too many initializers for a vector");
QualType EltTy = T->castAs<VectorType>()->getElementType();
QualType EltTy = VecTy->getElementType();
SmallVector<mlir::Attribute, 8> Elts;
// Process the explicit initializers
for (unsigned i = 0; i < NumInits; ++i) {
Expand All @@ -1149,10 +1180,11 @@ class ConstExprEmitter
}
// Zero-fill the rest of the vector
for (unsigned i = NumInits; i < NumElements; ++i) {
Elts.push_back(CGM.getBuilder().getZeroInitAttr(VecTy.getElementType()));
Elts.push_back(
CGM.getBuilder().getZeroInitAttr(CIRVecTy.getElementType()));
}
return cir::ConstVectorAttr::get(
VecTy, mlir::ArrayAttr::get(CGM.getBuilder().getContext(), Elts));
CIRVecTy, mlir::ArrayAttr::get(CGM.getBuilder().getContext(), Elts));
}

mlir::Attribute VisitImplicitValueInitExpr(ImplicitValueInitExpr *E,
Expand Down
53 changes: 51 additions & 2 deletions clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -309,8 +309,39 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
if (E->getBase()->getType()->isVectorType()) {
assert(!cir::MissingFeatures::scalableVectors() &&
"NYI: index into scalable vector");
// Subscript of vector type. This is handled differently, with a custom
// operation.

// ExtVectorBoolType uses integer storage, handle it specially
const auto *VecTy = E->getBase()
->getType()
.getCanonicalType()
->getAs<clang::VectorType>();
if (VecTy && VecTy->isExtVectorBoolType()) {
// For ExtVectorBoolType, extract a bit from the integer
mlir::Value IntValue = Visit(E->getBase());
mlir::Value IndexValue = Visit(E->getIdx());

// Extract the bit: (IntValue >> IndexValue) & 1
auto Loc = CGF.getLoc(E->getSourceRange());
auto BoolTy = CGF.builder.getBoolTy();
auto IntTy = IntValue.getType();

// Shift right by index: IntValue >> IndexValue
mlir::Value Shifted =
cir::ShiftOp::create(CGF.builder, Loc, IntTy, IntValue, IndexValue,
/*isShiftLeft=*/false);

// Mask with 1: Shifted & 1
mlir::Value One = CGF.builder.getConstInt(Loc, IntTy, 1);
mlir::Value Masked = cir::BinOp::create(
CGF.builder, Loc, IntTy, cir::BinOpKind::And, Shifted, One);

// Convert to bool: Masked != 0
mlir::Value Zero = CGF.builder.getConstInt(Loc, IntTy, 0);
return cir::CmpOp::create(CGF.builder, Loc, BoolTy, cir::CmpOpKind::ne,
Masked, Zero);
}

// Regular vector subscript
mlir::Value VecValue = Visit(E->getBase());
mlir::Value IndexValue = Visit(E->getIdx());
return cir::VecExtractOp::create(CGF.getBuilder(),
Expand Down Expand Up @@ -976,6 +1007,15 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
mlir::Value RHS = BOInfo.RHS;

if (LHSTy->isVectorType()) {
// Check for ExtVectorBoolType which uses integer storage, not vector
if (const auto *vecTy = LHSTy->getAs<clang::VectorType>()) {
if (vecTy->isExtVectorBoolType()) {
llvm_unreachable(
"NYI: ExtVectorBoolType comparison operations (requires "
"element-wise comparison on packed integer representation)");
}
}

if (!E->getType()->isVectorType()) {
// If AltiVec, the comparison results in a numeric type, so we use
// intrinsics comparing vectors and giving 0 or 1 as a result
Expand Down Expand Up @@ -2076,6 +2116,15 @@ mlir::Value ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *E) {
if (E->getType()->isVectorType() &&
E->getType()->castAs<VectorType>()->getVectorKind() ==
VectorKind::Generic) {
// Check for ExtVectorBoolType which uses integer storage, not vector
if (const auto *vecTy = E->getType()->getAs<clang::VectorType>()) {
if (vecTy->isExtVectorBoolType()) {
llvm_unreachable(
"NYI: ExtVectorBoolType logical NOT (requires handling padding "
"bits in integer storage to ensure correct element-wise negation)");
}
}

mlir::Value oper = Visit(E->getSubExpr());
mlir::Location loc = CGF.getLoc(E->getExprLoc());
auto operVecTy = mlir::cast<cir::VectorType>(oper.getType());
Expand Down
14 changes: 12 additions & 2 deletions clang/lib/CIR/CodeGen/CIRGenTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -670,8 +670,18 @@ mlir::Type CIRGenTypes::convertType(QualType T) {
case Type::ExtVector:
case Type::Vector: {
const VectorType *V = cast<VectorType>(Ty);
auto ElementType = convertTypeForMem(V->getElementType());
ResultType = cir::VectorType::get(ElementType, V->getNumElements());
// Boolean vectors use an integer as storage type, matching traditional
// CodeGen. For N bool elements, storage is iM where M = max(N, 8).
if (V->isExtVectorBoolType()) {
uint64_t numElements = V->getNumElements();
// Pad to at least one byte (8 bits)
uint64_t storageBits = std::max<uint64_t>(numElements, 8);
ResultType = cir::IntType::get(Builder.getContext(), storageBits,
/*isSigned=*/false);
} else {
auto ElementType = convertTypeForMem(V->getElementType());
ResultType = cir::VectorType::get(ElementType, V->getNumElements());
}
break;
}
case Type::ConstantMatrix: {
Expand Down
Loading
Loading