Skip to content

Commit 1fda661

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 1eb65a6 commit 1fda661

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

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

clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp

Lines changed: 107 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,16 +1079,67 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
10791079
Builder.createCompare(CGF.getLoc(E->getExprLoc()), kind, lhs, rhs);
10801080
} else if (!LHSTy->isAnyComplexType() && !RHSTy->isAnyComplexType()) {
10811081
BinOpInfo BOInfo = emitBinOps(E);
1082-
mlir::Value LHS = BOInfo.LHS;
1083-
mlir::Value RHS = BOInfo.RHS;
1082+
mlir::Value lhs = BOInfo.LHS;
1083+
mlir::Value rhs = BOInfo.RHS;
10841084

10851085
if (LHSTy->isVectorType()) {
10861086
// Check for ExtVectorBoolType which uses integer storage, not vector
10871087
if (const auto *vecTy = LHSTy->getAs<clang::VectorType>()) {
10881088
if (vecTy->isExtVectorBoolType()) {
1089-
llvm_unreachable(
1090-
"NYI: ExtVectorBoolType comparison operations (requires "
1091-
"element-wise comparison on packed integer representation)");
1089+
// ExtVectorBoolType is stored as an integer (!cir.int<u, N>) in
1090+
// CIR. To compare elements, we need to:
1091+
// 1. Bitcast iN -> <P x !cir.int<u, 1>> where P is the STORAGE size
1092+
// (padded to at least 8)
1093+
// 2. Shuffle to extract actual elements <P x i1> -> <N x i1>
1094+
// 3. Perform vector comparison on actual elements
1095+
// 4. Shuffle result back <N x i1> -> <P x i1> (pad with undef)
1096+
// 5. Bitcast result back to iN
1097+
1098+
uint64_t numElements = vecTy->getNumElements();
1099+
// Storage is padded to at least 8 bits (1 byte)
1100+
uint64_t storageBits = std::max<uint64_t>(numElements, 8);
1101+
1102+
// Use !cir.int<u, 1> instead of !cir.bool for vector elements
1103+
auto i1Ty = cir::IntType::get(Builder.getContext(), 1, false);
1104+
// Create vector types: padded storage size and actual element count
1105+
auto paddedVecTy = cir::VectorType::get(i1Ty, storageBits);
1106+
auto actualVecTy = cir::VectorType::get(i1Ty, numElements);
1107+
1108+
// Bitcast integer storage to padded vector of i1 for both operands
1109+
lhs =
1110+
Builder.createBitcast(CGF.getLoc(BOInfo.Loc), lhs, paddedVecTy);
1111+
rhs =
1112+
Builder.createBitcast(CGF.getLoc(BOInfo.Loc), rhs, paddedVecTy);
1113+
1114+
// Extract actual elements using shuffle (indices 0 to
1115+
// numElements-1)
1116+
llvm::SmallVector<int64_t> extractIndices(numElements);
1117+
for (uint64_t i = 0; i < numElements; ++i)
1118+
extractIndices[i] = i;
1119+
lhs = Builder.createVecShuffle(CGF.getLoc(BOInfo.Loc), lhs, lhs,
1120+
extractIndices);
1121+
rhs = Builder.createVecShuffle(CGF.getLoc(BOInfo.Loc), rhs, rhs,
1122+
extractIndices);
1123+
1124+
// Perform element-wise comparison on actual elements
1125+
cir::CmpOpKind kind = ClangCmpToCIRCmp(E->getOpcode());
1126+
Result = cir::VecCmpOp::create(Builder, CGF.getLoc(BOInfo.Loc),
1127+
actualVecTy, kind, lhs, rhs);
1128+
1129+
// Pad result back to storage size using shuffle
1130+
llvm::SmallVector<int64_t> padIndices(storageBits);
1131+
for (uint64_t i = 0; i < numElements; ++i)
1132+
padIndices[i] = i;
1133+
for (uint64_t i = numElements; i < storageBits; ++i)
1134+
padIndices[i] = -1; // undef for padding bits
1135+
Result = Builder.createVecShuffle(CGF.getLoc(BOInfo.Loc), Result,
1136+
Result, padIndices);
1137+
1138+
// Bitcast back to integer storage
1139+
Result = Builder.createBitcast(CGF.getLoc(BOInfo.Loc), Result,
1140+
CGF.convertType(E->getType()));
1141+
return emitScalarConversion(Result, CGF.getContext().BoolTy,
1142+
E->getType(), E->getExprLoc());
10921143
}
10931144
}
10941145

@@ -1112,13 +1163,13 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
11121163

11131164
// Unsigned integers and pointers.
11141165
if (CGF.CGM.getCodeGenOpts().StrictVTablePointers &&
1115-
mlir::isa<cir::PointerType>(LHS.getType()) &&
1116-
mlir::isa<cir::PointerType>(RHS.getType())) {
1166+
mlir::isa<cir::PointerType>(lhs.getType()) &&
1167+
mlir::isa<cir::PointerType>(rhs.getType())) {
11171168
llvm_unreachable("NYI");
11181169
}
11191170

11201171
cir::CmpOpKind Kind = ClangCmpToCIRCmp(E->getOpcode());
1121-
Result = Builder.createCompare(CGF.getLoc(BOInfo.Loc), Kind, LHS, RHS);
1172+
Result = Builder.createCompare(CGF.getLoc(BOInfo.Loc), Kind, lhs, rhs);
11221173
}
11231174
} else { // Complex Comparison: can only be an equality comparison.
11241175
assert(0 && "not implemented");
@@ -2302,9 +2353,54 @@ mlir::Value ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *E) {
23022353
// Check for ExtVectorBoolType which uses integer storage, not vector
23032354
if (const auto *vecTy = E->getType()->getAs<clang::VectorType>()) {
23042355
if (vecTy->isExtVectorBoolType()) {
2305-
llvm_unreachable(
2306-
"NYI: ExtVectorBoolType logical NOT (requires handling padding "
2307-
"bits in integer storage to ensure correct element-wise negation)");
2356+
// ExtVectorBoolType is stored as an integer (!cir.int<u, N>) in CIR.
2357+
// Logical NOT is implemented as comparison with zero: !v == (v == 0)
2358+
// 1. Get the operand (already in integer form)
2359+
// 2. Bitcast iN -> <P x !cir.int<u, 1>> where P is the STORAGE size
2360+
// (padded to at least 8)
2361+
// 3. Shuffle to extract actual elements <P x i1> -> <N x i1>
2362+
// 4. Compare with zero vector
2363+
// 5. Shuffle result back <N x i1> -> <P x i1> (pad with undef)
2364+
// 6. Bitcast result back to iN
2365+
2366+
mlir::Value oper = Visit(E->getSubExpr());
2367+
mlir::Location loc = CGF.getLoc(E->getExprLoc());
2368+
2369+
uint64_t numElements = vecTy->getNumElements();
2370+
// Storage is padded to at least 8 bits (1 byte)
2371+
uint64_t storageBits = std::max<uint64_t>(numElements, 8);
2372+
2373+
// Use !cir.int<u, 1> instead of !cir.bool for vector elements
2374+
auto i1Ty = cir::IntType::get(Builder.getContext(), 1, false);
2375+
// Create vector types: padded storage size and actual element count
2376+
auto paddedVecTy = cir::VectorType::get(i1Ty, storageBits);
2377+
auto actualVecTy = cir::VectorType::get(i1Ty, numElements);
2378+
2379+
// Bitcast integer storage to padded vector of i1
2380+
oper = Builder.createBitcast(loc, oper, paddedVecTy);
2381+
2382+
// Extract actual elements using shuffle (indices 0 to numElements-1)
2383+
llvm::SmallVector<int64_t> extractIndices(numElements);
2384+
for (uint64_t i = 0; i < numElements; ++i)
2385+
extractIndices[i] = i;
2386+
oper = Builder.createVecShuffle(loc, oper, oper, extractIndices);
2387+
2388+
// Create zero vector and compare with actual elements
2389+
mlir::Value zeroVec = Builder.getNullValue(actualVecTy, loc);
2390+
mlir::Value result = cir::VecCmpOp::create(
2391+
Builder, loc, actualVecTy, cir::CmpOpKind::eq, oper, zeroVec);
2392+
2393+
// Pad result back to storage size using shuffle
2394+
llvm::SmallVector<int64_t> padIndices(storageBits);
2395+
for (uint64_t i = 0; i < numElements; ++i)
2396+
padIndices[i] = i;
2397+
for (uint64_t i = numElements; i < storageBits; ++i)
2398+
padIndices[i] = -1; // undef for padding bits
2399+
result = Builder.createVecShuffle(loc, result, result, padIndices);
2400+
2401+
// Bitcast back to integer storage
2402+
return Builder.createBitcast(loc, result,
2403+
CGF.convertType(E->getType()));
23082404
}
23092405
}
23102406

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)