Skip to content

Commit 40625f3

Browse files
committed
[CIR] Add support for ExtVectorBoolType element assignment, comparisons, and logical NOT
This commit implements three previously missing operations for ExtVectorBoolType: 1. Element assignment (v[i] = value): Converts the packed integer representation to a padded vector, performs the element insertion, and converts back to integer form while preserving padding bits. 2. Vector comparisons (==, !=, etc.): Extracts actual elements from padded storage using shufflevector, performs element-wise comparison, then pads the result back to storage size with undef for padding bits. 3. Logical NOT (!v): Implemented as element-wise comparison with zero vector, following the same extract-operate-pad pattern as other comparisons. All operations follow the ExtVectorBoolType storage model where N bool elements are stored in an integer padded to at least 8 bits (1 byte). The implementation: - Bitcasts the integer storage to <P x i1> vector (P = padded storage size) - Uses shufflevector to extract <N x i1> (actual elements) - Performs the operation on actual elements - Uses shufflevector to pad result back to <P x i1> (undef for padding) - Bitcasts back to integer storage This approach ensures padding bits remain undefined/unchanged and mirrors how LLVM CodeGen handles these operations. Test Plan: - Added comprehensive tests for element assignment, comparisons, and logical NOT - Tests verify both CIR output and LLVM lowering - All existing CIR CodeGen tests pass (395 tests, 380 passed, 14 unsupported, 1 expected fail) - Specific vector tests pass: vector.cpp, vectype.cpp, vectype-issized.c, vectype-ext.cpp The implementation closely follows CodeGen patterns in CGExprScalar.cpp and CGExpr.cpp, maintaining consistency with the original implementation approach. ghstack-source-id: a9c5e91 Pull-Request: #2004
1 parent c620112 commit 40625f3

File tree

3 files changed

+280
-20
lines changed

3 files changed

+280
-20
lines changed

clang/lib/CIR/CodeGen/CIRGenExpr.cpp

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -902,22 +902,57 @@ void CIRGenFunction::emitStoreThroughLValue(RValue Src, LValue Dst,
902902
bool isInit) {
903903
if (!Dst.isSimple()) {
904904
if (Dst.isVectorElt()) {
905+
mlir::Location loc = Dst.getVectorPointer().getLoc();
906+
mlir::Value vector = builder.createLoad(loc, Dst.getVectorAddress());
907+
mlir::Value srcVal = Src.getScalarVal();
908+
905909
// Check if this is an ExtVectorBoolType element assignment
906910
QualType vectorType = Dst.getType();
907911
if (const auto *vecTy = vectorType->getAs<clang::VectorType>()) {
908912
if (vecTy->isExtVectorBoolType()) {
909-
llvm_unreachable(
910-
"NYI: ExtVectorBoolType element assignment (requires bit "
911-
"manipulation to set/clear individual bits in integer storage)");
913+
// ExtVectorBoolType is stored as an integer (!cir.int<u, N>) in CIR.
914+
// To set an element, we need to:
915+
// 1. Bitcast iN -> <N x !cir.int<u, 1>> where N is the STORAGE size
916+
// (padded to at least 8)
917+
// 2. Insert element at the actual index (0 to numElements-1)
918+
// 3. Bitcast <N x !cir.int<u, 1>> -> iN
919+
// The padding bits (numElements to N-1) are preserved through the
920+
// operation.
921+
922+
uint64_t numElements = vecTy->getNumElements();
923+
// Storage is padded to at least 8 bits (1 byte)
924+
uint64_t storageBits = std::max<uint64_t>(numElements, 8);
925+
926+
// Use !cir.int<u, 1> instead of !cir.bool for vector elements
927+
auto i1Ty = cir::IntType::get(builder.getContext(), 1, false);
928+
// Create vector with storage size (padded), not actual element count
929+
auto vecI1Ty = cir::VectorType::get(i1Ty, storageBits);
930+
931+
// Bitcast integer storage to vector of i1 (with padding)
932+
vector = builder.createBitcast(loc, vector, vecI1Ty);
933+
934+
// Insert the element (cast bool to i1 if needed)
935+
if (srcVal.getType() != i1Ty) {
936+
srcVal = cir::CastOp::create(builder, loc, i1Ty,
937+
cir::CastKind::bool_to_int, srcVal);
938+
}
939+
// Insert at the actual index - padding bits remain unchanged
940+
vector = cir::VecInsertOp::create(builder, loc, vector, srcVal,
941+
Dst.getVectorIdx());
942+
943+
// Bitcast back to integer storage
944+
vector = builder.createBitcast(
945+
loc, vector, Dst.getVectorAddress().getElementType());
946+
947+
builder.createStore(loc, vector, Dst.getVectorAddress());
948+
return;
912949
}
913950
}
914951

915952
// Read/modify/write the vector, inserting the new element
916-
mlir::Location loc = Dst.getVectorPointer().getLoc();
917-
mlir::Value Vector = builder.createLoad(loc, Dst.getVectorAddress());
918-
Vector = cir::VecInsertOp::create(builder, loc, Vector,
919-
Src.getScalarVal(), Dst.getVectorIdx());
920-
builder.createStore(loc, Vector, Dst.getVectorAddress());
953+
vector = cir::VecInsertOp::create(builder, loc, vector, srcVal,
954+
Dst.getVectorIdx());
955+
builder.createStore(loc, vector, Dst.getVectorAddress());
921956
return;
922957
}
923958

clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp

Lines changed: 107 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,16 +1003,67 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
10031003
Builder.createCompare(CGF.getLoc(E->getExprLoc()), kind, lhs, rhs);
10041004
} else if (!LHSTy->isAnyComplexType() && !RHSTy->isAnyComplexType()) {
10051005
BinOpInfo BOInfo = emitBinOps(E);
1006-
mlir::Value LHS = BOInfo.LHS;
1007-
mlir::Value RHS = BOInfo.RHS;
1006+
mlir::Value lhs = BOInfo.LHS;
1007+
mlir::Value rhs = BOInfo.RHS;
10081008

10091009
if (LHSTy->isVectorType()) {
10101010
// Check for ExtVectorBoolType which uses integer storage, not vector
10111011
if (const auto *vecTy = LHSTy->getAs<clang::VectorType>()) {
10121012
if (vecTy->isExtVectorBoolType()) {
1013-
llvm_unreachable(
1014-
"NYI: ExtVectorBoolType comparison operations (requires "
1015-
"element-wise comparison on packed integer representation)");
1013+
// ExtVectorBoolType is stored as an integer (!cir.int<u, N>) in
1014+
// CIR. To compare elements, we need to:
1015+
// 1. Bitcast iN -> <P x !cir.int<u, 1>> where P is the STORAGE size
1016+
// (padded to at least 8)
1017+
// 2. Shuffle to extract actual elements <P x i1> -> <N x i1>
1018+
// 3. Perform vector comparison on actual elements
1019+
// 4. Shuffle result back <N x i1> -> <P x i1> (pad with undef)
1020+
// 5. Bitcast result back to iN
1021+
1022+
uint64_t numElements = vecTy->getNumElements();
1023+
// Storage is padded to at least 8 bits (1 byte)
1024+
uint64_t storageBits = std::max<uint64_t>(numElements, 8);
1025+
1026+
// Use !cir.int<u, 1> instead of !cir.bool for vector elements
1027+
auto i1Ty = cir::IntType::get(Builder.getContext(), 1, false);
1028+
// Create vector types: padded storage size and actual element count
1029+
auto paddedVecTy = cir::VectorType::get(i1Ty, storageBits);
1030+
auto actualVecTy = cir::VectorType::get(i1Ty, numElements);
1031+
1032+
// Bitcast integer storage to padded vector of i1 for both operands
1033+
lhs =
1034+
Builder.createBitcast(CGF.getLoc(BOInfo.Loc), lhs, paddedVecTy);
1035+
rhs =
1036+
Builder.createBitcast(CGF.getLoc(BOInfo.Loc), rhs, paddedVecTy);
1037+
1038+
// Extract actual elements using shuffle (indices 0 to
1039+
// numElements-1)
1040+
llvm::SmallVector<int64_t> extractIndices(numElements);
1041+
for (uint64_t i = 0; i < numElements; ++i)
1042+
extractIndices[i] = i;
1043+
lhs = Builder.createVecShuffle(CGF.getLoc(BOInfo.Loc), lhs, lhs,
1044+
extractIndices);
1045+
rhs = Builder.createVecShuffle(CGF.getLoc(BOInfo.Loc), rhs, rhs,
1046+
extractIndices);
1047+
1048+
// Perform element-wise comparison on actual elements
1049+
cir::CmpOpKind kind = ClangCmpToCIRCmp(E->getOpcode());
1050+
Result = cir::VecCmpOp::create(Builder, CGF.getLoc(BOInfo.Loc),
1051+
actualVecTy, kind, lhs, rhs);
1052+
1053+
// Pad result back to storage size using shuffle
1054+
llvm::SmallVector<int64_t> padIndices(storageBits);
1055+
for (uint64_t i = 0; i < numElements; ++i)
1056+
padIndices[i] = i;
1057+
for (uint64_t i = numElements; i < storageBits; ++i)
1058+
padIndices[i] = -1; // undef for padding bits
1059+
Result = Builder.createVecShuffle(CGF.getLoc(BOInfo.Loc), Result,
1060+
Result, padIndices);
1061+
1062+
// Bitcast back to integer storage
1063+
Result = Builder.createBitcast(CGF.getLoc(BOInfo.Loc), Result,
1064+
CGF.convertType(E->getType()));
1065+
return emitScalarConversion(Result, CGF.getContext().BoolTy,
1066+
E->getType(), E->getExprLoc());
10161067
}
10171068
}
10181069

@@ -1036,13 +1087,13 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
10361087

10371088
// Unsigned integers and pointers.
10381089
if (CGF.CGM.getCodeGenOpts().StrictVTablePointers &&
1039-
mlir::isa<cir::PointerType>(LHS.getType()) &&
1040-
mlir::isa<cir::PointerType>(RHS.getType())) {
1090+
mlir::isa<cir::PointerType>(lhs.getType()) &&
1091+
mlir::isa<cir::PointerType>(rhs.getType())) {
10411092
llvm_unreachable("NYI");
10421093
}
10431094

10441095
cir::CmpOpKind Kind = ClangCmpToCIRCmp(E->getOpcode());
1045-
Result = Builder.createCompare(CGF.getLoc(BOInfo.Loc), Kind, LHS, RHS);
1096+
Result = Builder.createCompare(CGF.getLoc(BOInfo.Loc), Kind, lhs, rhs);
10461097
}
10471098
} else { // Complex Comparison: can only be an equality comparison.
10481099
assert(0 && "not implemented");
@@ -2119,9 +2170,54 @@ mlir::Value ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *E) {
21192170
// Check for ExtVectorBoolType which uses integer storage, not vector
21202171
if (const auto *vecTy = E->getType()->getAs<clang::VectorType>()) {
21212172
if (vecTy->isExtVectorBoolType()) {
2122-
llvm_unreachable(
2123-
"NYI: ExtVectorBoolType logical NOT (requires handling padding "
2124-
"bits in integer storage to ensure correct element-wise negation)");
2173+
// ExtVectorBoolType is stored as an integer (!cir.int<u, N>) in CIR.
2174+
// Logical NOT is implemented as comparison with zero: !v == (v == 0)
2175+
// 1. Get the operand (already in integer form)
2176+
// 2. Bitcast iN -> <P x !cir.int<u, 1>> where P is the STORAGE size
2177+
// (padded to at least 8)
2178+
// 3. Shuffle to extract actual elements <P x i1> -> <N x i1>
2179+
// 4. Compare with zero vector
2180+
// 5. Shuffle result back <N x i1> -> <P x i1> (pad with undef)
2181+
// 6. Bitcast result back to iN
2182+
2183+
mlir::Value oper = Visit(E->getSubExpr());
2184+
mlir::Location loc = CGF.getLoc(E->getExprLoc());
2185+
2186+
uint64_t numElements = vecTy->getNumElements();
2187+
// Storage is padded to at least 8 bits (1 byte)
2188+
uint64_t storageBits = std::max<uint64_t>(numElements, 8);
2189+
2190+
// Use !cir.int<u, 1> instead of !cir.bool for vector elements
2191+
auto i1Ty = cir::IntType::get(Builder.getContext(), 1, false);
2192+
// Create vector types: padded storage size and actual element count
2193+
auto paddedVecTy = cir::VectorType::get(i1Ty, storageBits);
2194+
auto actualVecTy = cir::VectorType::get(i1Ty, numElements);
2195+
2196+
// Bitcast integer storage to padded vector of i1
2197+
oper = Builder.createBitcast(loc, oper, paddedVecTy);
2198+
2199+
// Extract actual elements using shuffle (indices 0 to numElements-1)
2200+
llvm::SmallVector<int64_t> extractIndices(numElements);
2201+
for (uint64_t i = 0; i < numElements; ++i)
2202+
extractIndices[i] = i;
2203+
oper = Builder.createVecShuffle(loc, oper, oper, extractIndices);
2204+
2205+
// Create zero vector and compare with actual elements
2206+
mlir::Value zeroVec = Builder.getNullValue(actualVecTy, loc);
2207+
mlir::Value result = cir::VecCmpOp::create(
2208+
Builder, loc, actualVecTy, cir::CmpOpKind::eq, oper, zeroVec);
2209+
2210+
// Pad result back to storage size using shuffle
2211+
llvm::SmallVector<int64_t> padIndices(storageBits);
2212+
for (uint64_t i = 0; i < numElements; ++i)
2213+
padIndices[i] = i;
2214+
for (uint64_t i = numElements; i < storageBits; ++i)
2215+
padIndices[i] = -1; // undef for padding bits
2216+
result = Builder.createVecShuffle(loc, result, result, padIndices);
2217+
2218+
// Bitcast back to integer storage
2219+
return Builder.createBitcast(loc, result,
2220+
CGF.convertType(E->getType()));
21252221
}
21262222
}
21272223

clang/test/CIR/CodeGen/extvector-bool.cpp

Lines changed: 130 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,19 @@
22
// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR
33
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll
44
// RUN: FileCheck --input-file=%t.ll %s --check-prefix=LLVM
5-
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.og.ll
5+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.og.ll -DDISABLE_ELEMENT_ASSIGN_TEST
66
// RUN: FileCheck --input-file=%t.og.ll %s --check-prefix=OGCG
7+
//
8+
// NOTE: Element assignment test (test_element_assign) is excluded from OGCG
9+
// testing due to a bug in classic CodeGen (clang/lib/CodeGen/CGExpr.cpp:2585-2587).
10+
// Classic CodeGen calls VecTy->getScalarType() on an IntegerType before bitcasting
11+
// to VectorType for ExtVectorBoolType, causing assertion failure. CIR correctly
12+
// performs the bitcast first. This is a justifiable divergence fixing a bug.
13+
// Bug verified: classic CodeGen crashes with assertion when compiling element assignment.
14+
//
15+
// The OGCG tests below verify that CIR's LLVM lowering for comparisons and logical
16+
// NOT matches classic CodeGen's output, demonstrating consistency where classic
17+
// CodeGen works correctly.
718

819
// Test basic ext_vector_type with bool elements
920
typedef bool bool4 __attribute__((ext_vector_type(4)));
@@ -204,3 +215,121 @@ void test_read_elements() {
204215
// CIR: cir.binop(and,{{.*}}){{.*}}!u8i
205216
bool e3 = v[3];
206217
}
218+
219+
#ifndef DISABLE_ELEMENT_ASSIGN_TEST
220+
// Test element assignment (v[2] = true)
221+
// NOTE: This test is disabled for classic CodeGen due to a bug in CGExpr.cpp:2585-2587
222+
// where VecTy->getScalarType() is called on an integer type before bitcasting to vector.
223+
// CIR-LABEL: cir.func {{.*}}@_Z{{.*}}test_element_assignv
224+
void test_element_assign() {
225+
bool4 v = {true, false, true, false};
226+
// CIR: cir.load{{.*}}!u8i
227+
// CIR: cir.cast bitcast{{.*}}!u8i -> !cir.vector<!cir.int<u, 1> x 8>
228+
// CIR: cir.cast bool_to_int{{.*}}!cir.bool -> !cir.int<u, 1>
229+
// CIR: cir.vec.insert
230+
// CIR: cir.cast bitcast{{.*}}!cir.vector<!cir.int<u, 1> x 8> -> !u8i
231+
// CIR: cir.store{{.*}}!u8i, !cir.ptr<!u8i>
232+
v[2] = true;
233+
234+
// LLVM-LABEL: define {{.*}}@_Z{{.*}}test_element_assignv
235+
// LLVM: %[[VEC_LOAD:.*]] = load i8
236+
// LLVM: %[[VEC_BITCAST:.*]] = bitcast i8 %[[VEC_LOAD]] to <8 x i1>
237+
// LLVM: %[[VEC_INSERT:.*]] = insertelement <8 x i1> %[[VEC_BITCAST]], i1 true, i32 2
238+
// LLVM: %[[VEC_BITCAST_BACK:.*]] = bitcast <8 x i1> %[[VEC_INSERT]] to i8
239+
// LLVM: store i8 %[[VEC_BITCAST_BACK]]
240+
}
241+
#endif
242+
243+
// Test comparison operations (a == b, a != b)
244+
// CIR-LABEL: cir.func {{.*}}@_Z{{.*}}test_comparisonv
245+
void test_comparison() {
246+
bool4 a = {true, false, true, false};
247+
bool4 b = {false, true, true, false};
248+
249+
// Test equality
250+
// CIR: cir.load{{.*}}!u8i
251+
// CIR: cir.load{{.*}}!u8i
252+
// CIR: cir.cast bitcast{{.*}}!u8i -> !cir.vector<!cir.int<u, 1> x 8>
253+
// CIR: cir.cast bitcast{{.*}}!u8i -> !cir.vector<!cir.int<u, 1> x 8>
254+
// CIR: cir.vec.shuffle{{.*}}!cir.vector<!cir.int<u, 1> x 8>{{.*}}!cir.vector<!cir.int<u, 1> x 4>
255+
// CIR: cir.vec.shuffle{{.*}}!cir.vector<!cir.int<u, 1> x 8>{{.*}}!cir.vector<!cir.int<u, 1> x 4>
256+
// CIR: cir.vec.cmp(eq,{{.*}}!cir.vector<!cir.int<u, 1> x 4>
257+
// CIR: cir.vec.shuffle{{.*}}!cir.vector<!cir.int<u, 1> x 4>{{.*}}!cir.vector<!cir.int<u, 1> x 8>
258+
// CIR: cir.cast bitcast{{.*}}!cir.vector<!cir.int<u, 1> x 8> -> !u8i
259+
bool4 c = a == b;
260+
261+
// Test inequality
262+
// CIR: cir.load{{.*}}!u8i
263+
// CIR: cir.load{{.*}}!u8i
264+
// CIR: cir.cast bitcast{{.*}}!u8i -> !cir.vector<!cir.int<u, 1> x 8>
265+
// CIR: cir.cast bitcast{{.*}}!u8i -> !cir.vector<!cir.int<u, 1> x 8>
266+
// CIR: cir.vec.shuffle{{.*}}!cir.vector<!cir.int<u, 1> x 8>{{.*}}!cir.vector<!cir.int<u, 1> x 4>
267+
// CIR: cir.vec.shuffle{{.*}}!cir.vector<!cir.int<u, 1> x 8>{{.*}}!cir.vector<!cir.int<u, 1> x 4>
268+
// CIR: cir.vec.cmp(ne,{{.*}}!cir.vector<!cir.int<u, 1> x 4>
269+
// CIR: cir.vec.shuffle{{.*}}!cir.vector<!cir.int<u, 1> x 4>{{.*}}!cir.vector<!cir.int<u, 1> x 8>
270+
// CIR: cir.cast bitcast{{.*}}!cir.vector<!cir.int<u, 1> x 8> -> !u8i
271+
bool4 d = a != b;
272+
273+
// LLVM-LABEL: define {{.*}}@_Z{{.*}}test_comparisonv
274+
// LLVM: %[[A_LOAD:.*]] = load i8
275+
// LLVM: %[[B_LOAD:.*]] = load i8
276+
// LLVM: %[[A_BITCAST:.*]] = bitcast i8 %[[A_LOAD]] to <8 x i1>
277+
// LLVM: %[[B_BITCAST:.*]] = bitcast i8 %[[B_LOAD]] to <8 x i1>
278+
// LLVM: %[[A_EXTRACT:.*]] = shufflevector <8 x i1> %[[A_BITCAST]], <8 x i1> %[[A_BITCAST]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
279+
// LLVM: %[[B_EXTRACT:.*]] = shufflevector <8 x i1> %[[B_BITCAST]], <8 x i1> %[[B_BITCAST]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
280+
// LLVM: %[[VEC_CMP:.*]] = icmp eq <4 x i1> %[[A_EXTRACT]], %[[B_EXTRACT]]
281+
// LLVM: %[[RESULT_PAD:.*]] = shufflevector <4 x i1> %[[VEC_CMP]], <4 x i1> %[[VEC_CMP]]
282+
// LLVM: %[[RESULT_BITCAST:.*]] = bitcast <8 x i1> %[[RESULT_PAD]] to i8
283+
// LLVM: store i8 %[[RESULT_BITCAST]]
284+
// LLVM: %[[A_LOAD2:.*]] = load i8
285+
// LLVM: %[[B_LOAD2:.*]] = load i8
286+
// LLVM: %[[A_BITCAST2:.*]] = bitcast i8 %[[A_LOAD2]] to <8 x i1>
287+
// LLVM: %[[B_BITCAST2:.*]] = bitcast i8 %[[B_LOAD2]] to <8 x i1>
288+
// LLVM: %[[A_EXTRACT2:.*]] = shufflevector <8 x i1> %[[A_BITCAST2]], <8 x i1> %[[A_BITCAST2]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
289+
// LLVM: %[[B_EXTRACT2:.*]] = shufflevector <8 x i1> %[[B_BITCAST2]], <8 x i1> %[[B_BITCAST2]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
290+
// LLVM: %[[VEC_CMP2:.*]] = icmp ne <4 x i1> %[[A_EXTRACT2]], %[[B_EXTRACT2]]
291+
// LLVM: %[[RESULT_PAD2:.*]] = shufflevector <4 x i1> %[[VEC_CMP2]], <4 x i1> %[[VEC_CMP2]]
292+
// LLVM: %[[RESULT_BITCAST2:.*]] = bitcast <8 x i1> %[[RESULT_PAD2]] to i8
293+
// LLVM: store i8 %[[RESULT_BITCAST2]]
294+
295+
// OGCG-LABEL: define {{.*}}@_Z{{.*}}test_comparisonv
296+
// OGCG: bitcast i8 {{.*}} to <8 x i1>
297+
// OGCG: shufflevector <8 x i1> {{.*}}, <8 x i1> poison, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
298+
// OGCG: bitcast i8 {{.*}} to <8 x i1>
299+
// OGCG: shufflevector <8 x i1> {{.*}}, <8 x i1> poison, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
300+
// OGCG: icmp eq <4 x i1>
301+
// OGCG: shufflevector <4 x i1> {{.*}}, <4 x i1> poison, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 poison, i32 poison, i32 poison, i32 poison>
302+
// OGCG: bitcast <8 x i1> {{.*}} to i8
303+
// OGCG: icmp ne <4 x i1>
304+
}
305+
306+
// Test logical NOT (!v)
307+
// CIR-LABEL: cir.func {{.*}}@_Z{{.*}}test_logical_notv
308+
void test_logical_not() {
309+
bool4 v = {true, false, true, false};
310+
311+
// CIR: cir.load{{.*}}!u8i
312+
// CIR: cir.cast bitcast{{.*}}!u8i -> !cir.vector<!cir.int<u, 1> x 8>
313+
// CIR: cir.vec.shuffle{{.*}}!cir.vector<!cir.int<u, 1> x 8>{{.*}}!cir.vector<!cir.int<u, 1> x 4>
314+
// CIR: cir.const #cir.zero : !cir.vector<!cir.int<u, 1> x 4>
315+
// CIR: cir.vec.cmp(eq,{{.*}}!cir.vector<!cir.int<u, 1> x 4>
316+
// CIR: cir.vec.shuffle{{.*}}!cir.vector<!cir.int<u, 1> x 4>{{.*}}!cir.vector<!cir.int<u, 1> x 8>
317+
// CIR: cir.cast bitcast{{.*}}!cir.vector<!cir.int<u, 1> x 8> -> !u8i
318+
bool4 n = !v;
319+
320+
// LLVM-LABEL: define {{.*}}@_Z{{.*}}test_logical_notv
321+
// LLVM: %[[VEC_LOAD:.*]] = load i8
322+
// LLVM: %[[VEC_BITCAST:.*]] = bitcast i8 %[[VEC_LOAD]] to <8 x i1>
323+
// LLVM: %[[VEC_EXTRACT:.*]] = shufflevector <8 x i1> %[[VEC_BITCAST]], <8 x i1> %[[VEC_BITCAST]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
324+
// LLVM: icmp eq <4 x i1> %[[VEC_EXTRACT]], zeroinitializer
325+
// LLVM: shufflevector <4 x i1>
326+
// LLVM: bitcast <8 x i1> %{{.*}} to i8
327+
// LLVM: store i8 %{{.*}}
328+
329+
// OGCG-LABEL: define {{.*}}@_Z{{.*}}test_logical_notv
330+
// OGCG: bitcast i8 {{.*}} to <8 x i1>
331+
// OGCG: shufflevector <8 x i1> {{.*}}, <8 x i1> poison, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
332+
// OGCG: icmp eq <4 x i1> {{.*}}, zeroinitializer
333+
// OGCG: shufflevector <4 x i1> {{.*}}, <4 x i1> poison, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 poison, i32 poison, i32 poison, i32 poison>
334+
// OGCG: bitcast <8 x i1> {{.*}} to i8
335+
}

0 commit comments

Comments
 (0)