Skip to content

Commit 5a929a4

Browse files
authored
[Clang] Support using boolean vectors in ternary operators (#154145)
Summary: It's extremely common to conditionally blend two vectors. Previously this was done with mask registers, which is what the normal ternary code generation does when used on a vector. However, since Clang 15 we have supported boolean vector types in the compiler. These are useful in general for checking the mask registers, but are currently limited because they do not map to an LLVM-IR select instruction. This patch simply relaxes these checks, which are technically forbidden by the OpenCL standard. However, general vector support should be able to handle these. We already support this for Arm SVE types, so this should be make more consistent with the clang vector type.
1 parent 29067ac commit 5a929a4

File tree

7 files changed

+183
-207
lines changed

7 files changed

+183
-207
lines changed

clang/docs/LanguageExtensions.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,16 @@ The size and alignment are both the number of bits rounded up to the next power
657657
of two, but the alignment is at most the maximum vector alignment of the
658658
target.
659659

660+
A boolean vector can be used in a ternary `?:` operator to select vector
661+
elements of a different type.
662+
663+
.. code-block:: c++
664+
665+
typedef int int4 __attribute__((ext_vector_type(4)));
666+
typedef bool bool4 __attribute__((ext_vector_type(4)));
667+
668+
int4 blend(bool4 cond, int4 a, int4 b) { return cond ? a : b; }
669+
660670

661671
Vector Literals
662672
---------------

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,12 +137,14 @@ Non-comprehensive list of changes in this release
137137
- ``__builtin_elementwise_max`` and ``__builtin_elementwise_min`` functions for integer types can
138138
now be used in constant expressions.
139139

140+
- A vector of booleans is now a valid condition for the ternary ``?:`` operator.
141+
This binds to a simple vector select operation.
142+
140143
- Use of ``__has_feature`` to detect the ``ptrauth_qualifier`` and ``ptrauth_intrinsics``
141144
features has been deprecated, and is restricted to the arm64e target only. The
142145
correct method to check for these features is to test for the ``__PTRAUTH__``
143146
macro.
144147

145-
146148
New Compiler Flags
147149
------------------
148150
- New option ``-fno-sanitize-annotate-debug-info-traps`` added to disable emitting trap reasons into the debug info when compiling with trapping UBSan (e.g. ``-fsanitize-trap=undefined``).

clang/lib/CodeGen/CGExprScalar.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5558,8 +5558,8 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
55585558

55595559
// OpenCL: If the condition is a vector, we can treat this condition like
55605560
// the select function.
5561-
if ((CGF.getLangOpts().OpenCL && condExpr->getType()->isVectorType()) ||
5562-
condExpr->getType()->isExtVectorType()) {
5561+
if (CGF.getLangOpts().OpenCL && (condExpr->getType()->isVectorType() ||
5562+
condExpr->getType()->isExtVectorType())) {
55635563
CGF.incrementProfileCounter(E);
55645564

55655565
llvm::Value *CondV = CGF.EmitScalarExpr(condExpr);
@@ -5608,9 +5608,16 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
56085608

56095609
llvm::Type *CondType = ConvertType(condExpr->getType());
56105610
auto *VecTy = cast<llvm::VectorType>(CondType);
5611-
llvm::Value *ZeroVec = llvm::Constant::getNullValue(VecTy);
56125611

5613-
CondV = Builder.CreateICmpNE(CondV, ZeroVec, "vector_cond");
5612+
if (VecTy->getElementType()->isIntegerTy(1))
5613+
return Builder.CreateSelect(CondV, LHS, RHS, "vector_select");
5614+
5615+
// OpenCL uses the MSB of the mask vector.
5616+
llvm::Value *ZeroVec = llvm::Constant::getNullValue(VecTy);
5617+
if (condExpr->getType()->isExtVectorType())
5618+
CondV = Builder.CreateICmpSLT(CondV, ZeroVec, "vector_cond");
5619+
else
5620+
CondV = Builder.CreateICmpNE(CondV, ZeroVec, "vector_cond");
56145621
return Builder.CreateSelect(CondV, LHS, RHS, "vector_select");
56155622
}
56165623

clang/lib/Sema/SemaExpr.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8434,9 +8434,11 @@ static bool checkVectorResult(Sema &S, QualType CondTy, QualType VecResTy,
84348434
QualType CVE = CV->getElementType();
84358435
QualType RVE = RV->getElementType();
84368436

8437-
if (S.Context.getTypeSize(CVE) != S.Context.getTypeSize(RVE)) {
8437+
// Boolean vectors are permitted outside of OpenCL mode.
8438+
if (S.Context.getTypeSize(CVE) != S.Context.getTypeSize(RVE) &&
8439+
(!CVE->isBooleanType() || S.LangOpts.OpenCL)) {
84388440
S.Diag(QuestionLoc, diag::err_conditional_vector_element_size)
8439-
<< CondTy << VecResTy;
8441+
<< CondTy << VecResTy;
84408442
return true;
84418443
}
84428444

clang/lib/Sema/SemaExprCXX.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5753,10 +5753,12 @@ QualType Sema::CheckVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS,
57535753
return {};
57545754
}
57555755

5756+
// Boolean vectors are permitted outside of OpenCL mode.
57565757
if (Context.getTypeSize(ResultElementTy) !=
5757-
Context.getTypeSize(CondElementTy)) {
5758-
Diag(QuestionLoc, diag::err_conditional_vector_element_size) << CondType
5759-
<< ResultType;
5758+
Context.getTypeSize(CondElementTy) &&
5759+
(!CondElementTy->isBooleanType() || LangOpts.OpenCL)) {
5760+
Diag(QuestionLoc, diag::err_conditional_vector_element_size)
5761+
<< CondType << ResultType;
57605762
return {};
57615763
}
57625764

clang/test/CodeGenCXX/aarch64-sve-vector-conditional-op.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@
1010
// CHECK-LABEL: @_Z9cond_boolu10__SVBool_tS_(
1111
// CHECK-NEXT: entry:
1212
// CHECK-NEXT: [[CMP:%.*]] = icmp ult <vscale x 16 x i1> [[A:%.*]], [[B:%.*]]
13-
// CHECK-NEXT: [[VECTOR_COND:%.*]] = icmp ne <vscale x 16 x i1> [[CMP]], zeroinitializer
14-
// CHECK-NEXT: [[VECTOR_SELECT:%.*]] = select <vscale x 16 x i1> [[VECTOR_COND]], <vscale x 16 x i1> [[A]], <vscale x 16 x i1> [[B]]
13+
// CHECK-NEXT: [[VECTOR_SELECT:%.*]] = select <vscale x 16 x i1> [[CMP]], <vscale x 16 x i1> [[A]], <vscale x 16 x i1> [[B]]
1514
// CHECK-NEXT: ret <vscale x 16 x i1> [[VECTOR_SELECT]]
1615
//
1716
svbool_t cond_bool(svbool_t a, svbool_t b) {

0 commit comments

Comments
 (0)