[clang] [HLSL] `constexpr` vector element conversions (PR #195173)
Chris B via cfe-commits
cfe-commits at lists.llvm.org
Wed May 27 15:52:46 PDT 2026
https://github.com/llvm-beanz updated https://github.com/llvm/llvm-project/pull/195173
>From 5c806c3eade44b4ba5bd0758b0e9dc8a28ce8ece Mon Sep 17 00:00:00 2001
From: Chris Bieneman <chris.bieneman at me.com>
Date: Thu, 30 Apr 2026 15:16:54 -0500
Subject: [PATCH 1/6] [HLSL] `constexpr` vector element conversions
This PR updates the constant expression evaluators to support HLSL's
element-wise vector element conversions. These conversions allow
element-by-element conversion of a vector from one type to another
vector of the same dimension.
Fixes #163437
../clang/test/SemaHLSL/Types/BuiltinVector/VectorCastConstantExpr.hlsl
../clang/test/SemaHLSL/Types/BuiltinVector/VectorCastConstantExpr.hlsl
---
clang/lib/AST/ByteCode/Compiler.cpp | 56 ++++++++++++++++
clang/lib/AST/ByteCode/Compiler.h | 1 +
clang/lib/AST/ExprConstant.cpp | 25 ++++++++
.../BuiltinVector/VectorCastConstantExpr.hlsl | 64 +++++++++++++++++++
4 files changed, 146 insertions(+)
create mode 100644 clang/test/SemaHLSL/Types/BuiltinVector/VectorCastConstantExpr.hlsl
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 626068ce9eee5..6f0fdcc31ce2c 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -376,6 +376,8 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *E) {
case CK_FloatingCast: {
// HLSL uses CK_FloatingCast to cast between vectors.
+ if (E->getType()->isVectorType())
+ return this->emitVectorElementwiseCast(E);
if (!SubExpr->getType()->isFloatingType() ||
!E->getType()->isFloatingType())
return false;
@@ -386,6 +388,8 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *E) {
}
case CK_IntegralToFloating: {
+ if (E->getType()->isVectorType())
+ return this->emitVectorElementwiseCast(E);
if (!E->getType()->isRealFloatingType())
return false;
if (!this->visit(SubExpr))
@@ -396,6 +400,8 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *E) {
}
case CK_FloatingToBoolean: {
+ if (E->getType()->isVectorType())
+ return this->emitVectorElementwiseCast(E);
if (!SubExpr->getType()->isRealFloatingType() ||
!E->getType()->isBooleanType())
return false;
@@ -407,6 +413,8 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *E) {
}
case CK_FloatingToIntegral: {
+ if (E->getType()->isVectorType())
+ return this->emitVectorElementwiseCast(E);
if (!E->getType()->isIntegralOrEnumerationType())
return false;
if (!this->visit(SubExpr))
@@ -554,6 +562,8 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *E) {
}
case CK_IntegralToBoolean:
case CK_FixedPointToBoolean: {
+ if (E->getType()->isVectorType())
+ return this->emitVectorElementwiseCast(E);
// HLSL uses this to cast to one-element vectors.
OptPrimType FromT = classify(SubExpr->getType());
if (!FromT)
@@ -568,6 +578,8 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *E) {
case CK_BooleanToSignedIntegral:
case CK_IntegralCast: {
+ if (E->getCastKind() == CK_IntegralCast && E->getType()->isVectorType())
+ return this->emitVectorElementwiseCast(E);
OptPrimType FromT = classify(SubExpr->getType());
OptPrimType ToT = classify(E->getType());
if (!FromT || !ToT)
@@ -8111,6 +8123,50 @@ bool Compiler<Emitter>::emitBuiltinBitCast(const CastExpr *E) {
return true;
}
+/// Cast each element of a source vector to the corresponding element type of a
+/// destination vector using a scalar primitive cast. A pointer to the
+/// destination must be on top of the interpreter stack when \p Initializing is
+/// true; otherwise a new local is allocated for the result.
+template <class Emitter>
+bool Compiler<Emitter>::emitVectorElementwiseCast(const CastExpr *E) {
+ const Expr *SubExpr = E->getSubExpr();
+ assert(SubExpr->getType()->isVectorType() && "expected vector source type");
+ assert(E->getType()->isVectorType() && "expected vector destination type");
+
+ const auto *DstVTy = E->getType()->getAs<VectorType>();
+ unsigned NumElts = DstVTy->getNumElements();
+ PrimType SrcElemT = classifyVectorElementType(SubExpr->getType());
+ PrimType DstElemT = classifyVectorElementType(E->getType());
+ QualType DstElemType = DstVTy->getElementType();
+
+ if (!Initializing) {
+ UnsignedOrNone LocalIndex = allocateLocal(E);
+ if (!LocalIndex)
+ return false;
+ if (!this->emitGetPtrLocal(*LocalIndex, E))
+ return false;
+ }
+
+ unsigned SrcOffset =
+ allocateLocalPrimitive(SubExpr, PT_Ptr, /*IsConst=*/true);
+ if (!this->visit(SubExpr))
+ return false;
+ if (!this->emitSetLocal(PT_Ptr, SrcOffset, E))
+ return false;
+
+ for (unsigned I = 0; I < NumElts; ++I) {
+ if (!this->emitGetLocal(PT_Ptr, SrcOffset, E))
+ return false;
+ if (!this->emitArrayElemPop(SrcElemT, I, E))
+ return false;
+ if (!this->emitPrimCast(SrcElemT, DstElemT, DstElemType, E))
+ return false;
+ if (!this->emitInitElem(DstElemT, I, E))
+ return false;
+ }
+ return true;
+}
+
/// Replicate a scalar value into every scalar element of an aggregate.
/// The scalar is stored in a local at \p SrcOffset and a pointer to the
/// destination must be on top of the interpreter stack. Each element receives
diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h
index de6ea524897a0..3626fd62f7f1f 100644
--- a/clang/lib/AST/ByteCode/Compiler.h
+++ b/clang/lib/AST/ByteCode/Compiler.h
@@ -415,6 +415,7 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
bool emitComplexBoolCast(const Expr *E);
bool emitComplexComparison(const Expr *LHS, const Expr *RHS,
const BinaryOperator *E);
+ bool emitVectorElementwiseCast(const CastExpr *E);
bool emitRecordDestructionPop(const Record *R, SourceInfo Loc);
bool emitDestructionPop(const Descriptor *Desc, SourceInfo Loc);
bool emitDummyPtr(const DeclTy &D, const Expr *E);
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 1a4c962801077..f92e04666413a 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -11772,6 +11772,31 @@ bool VectorExprEvaluator::VisitCastExpr(const CastExpr *E) {
return false;
return Success(ResultEls, E);
}
+ case CK_IntegralToFloating:
+ case CK_FloatingToIntegral:
+ case CK_IntegralCast:
+ case CK_FloatingCast:
+ case CK_FloatingToBoolean:
+ case CK_IntegralToBoolean: {
+ // These casts apply element-wise when the source is a vector type.
+ assert(SETy->isVectorType() && "expected vector source type");
+ APValue SrcVal;
+ if (!EvaluateVector(SE, SrcVal, Info))
+ return Error(E);
+
+ assert(SrcVal.getVectorLength() == NElts);
+ QualType SrcEltTy = SETy->castAs<VectorType>()->getElementType();
+ QualType DstEltTy = VTy->getElementType();
+ const FPOptions FPO = E->getFPFeaturesInEffect(Info.Ctx.getLangOpts());
+
+ SmallVector<APValue, 4> ResultEls(NElts);
+ for (unsigned I = 0; I < NElts; ++I) {
+ if (!handleScalarCast(Info, FPO, E, SrcEltTy, DstEltTy,
+ SrcVal.getVectorElt(I), ResultEls[I]))
+ return false;
+ }
+ return Success(ResultEls, E);
+ }
default:
return ExprEvaluatorBaseTy::VisitCastExpr(E);
}
diff --git a/clang/test/SemaHLSL/Types/BuiltinVector/VectorCastConstantExpr.hlsl b/clang/test/SemaHLSL/Types/BuiltinVector/VectorCastConstantExpr.hlsl
new file mode 100644
index 0000000000000..a2fee7f80ec08
--- /dev/null
+++ b/clang/test/SemaHLSL/Types/BuiltinVector/VectorCastConstantExpr.hlsl
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -finclude-default-header -std=hlsl202x -verify %s
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -finclude-default-header -std=hlsl202x -fexperimental-new-constant-interpreter -verify %s
+
+// expected-no-diagnostics
+
+// Tests for constexpr evaluation of element-wise vector casts.
+
+export void fn() {
+ // CK_IntegralToFloating: int4 -> float4
+ constexpr float4 ItF = (float4)int4(1, 2, 3, 4);
+ _Static_assert(ItF.x == 1.0f, "");
+ _Static_assert(ItF.y == 2.0f, "");
+ _Static_assert(ItF.z == 3.0f, "");
+ _Static_assert(ItF.w == 4.0f, "");
+
+ // CK_FloatingToIntegral: float4 -> int4 (truncation toward zero)
+ constexpr int4 FtI = (int4)float4(1.9f, 2.1f, -3.9f, -4.1f);
+ _Static_assert(FtI.x == 1, "");
+ _Static_assert(FtI.y == 2, "");
+ _Static_assert(FtI.z == -3, "");
+ _Static_assert(FtI.w == -4, "");
+
+ // CK_IntegralCast: int4 -> uint4
+ constexpr uint4 IC = (uint4)int4(1, 2, 3, 4);
+ _Static_assert(IC.x == 1u, "");
+ _Static_assert(IC.y == 2u, "");
+ _Static_assert(IC.z == 3u, "");
+ _Static_assert(IC.w == 4u, "");
+
+ // CK_FloatingCast: float4 -> double4
+ constexpr double4 FC = (double4)float4(1.0f, 2.0f, 3.0f, 4.0f);
+ _Static_assert(FC.x == 1.0, "");
+ _Static_assert(FC.y == 2.0, "");
+ _Static_assert(FC.z == 3.0, "");
+ _Static_assert(FC.w == 4.0, "");
+
+ // CK_IntegralToBoolean: int4 -> bool4
+ constexpr bool4 ItB = (bool4)int4(1, 0, -1, 2);
+ _Static_assert(ItB.x == true, "");
+ _Static_assert(ItB.y == false, "");
+ _Static_assert(ItB.z == true, "");
+ _Static_assert(ItB.w == true, "");
+
+ // CK_FloatingToBoolean: float4 -> bool4
+ constexpr bool4 FtB = (bool4)float4(1.0f, 0.0f, -1.0f, 2.0f);
+ _Static_assert(FtB.x == true, "");
+ _Static_assert(FtB.y == false, "");
+ _Static_assert(FtB.z == true, "");
+ _Static_assert(FtB.w == true, "");
+
+ // Bool source: CK_IntegralToFloating with bool4 -> float4
+ constexpr float4 BtF = (float4)bool4(true, false, true, false);
+ _Static_assert(BtF.x == 1.0f, "");
+ _Static_assert(BtF.y == 0.0f, "");
+ _Static_assert(BtF.z == 1.0f, "");
+ _Static_assert(BtF.w == 0.0f, "");
+
+ // Bool source: CK_IntegralCast with bool4 -> int4
+ constexpr int4 BtI = (int4)bool4(true, false, true, false);
+ _Static_assert(BtI.x == 1, "");
+ _Static_assert(BtI.y == 0, "");
+ _Static_assert(BtI.z == 1, "");
+ _Static_assert(BtI.w == 0, "");
+}
>From f4188ab66fa3f3c5d87547d3122db957e2acc223 Mon Sep 17 00:00:00 2001
From: Chris Bieneman <chris.bieneman at me.com>
Date: Mon, 11 May 2026 10:54:37 -0500
Subject: [PATCH 2/6] Updates based on PR feedback
---
clang/lib/AST/ByteCode/Compiler.cpp | 43 ++++++-------------
clang/lib/AST/ByteCode/Compiler.h | 1 +
.../Language/ConstexprVectorCasts.hlsl | 24 +++++++++++
3 files changed, 37 insertions(+), 31 deletions(-)
create mode 100644 clang/test/SemaHLSL/Language/ConstexprVectorCasts.hlsl
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 6f0fdcc31ce2c..e0410ceeeb97c 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -576,10 +576,11 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *E) {
return this->emitCast(*FromT, classifyPrim(E), E);
}
- case CK_BooleanToSignedIntegral:
- case CK_IntegralCast: {
- if (E->getCastKind() == CK_IntegralCast && E->getType()->isVectorType())
+ case CK_IntegralCast:
+ if (E->getType()->isVectorType())
return this->emitVectorElementwiseCast(E);
+ [[fallthrough]];
+ case CK_BooleanToSignedIntegral: {
OptPrimType FromT = classify(SubExpr->getType());
OptPrimType ToT = classify(E->getType());
if (!FromT || !ToT)
@@ -4358,12 +4359,10 @@ bool Compiler<Emitter>::VisitAddrLabelExpr(const AddrLabelExpr *E) {
}
template <class Emitter>
-bool Compiler<Emitter>::VisitConvertVectorExpr(const ConvertVectorExpr *E) {
- assert(Initializing);
+bool Compiler<Emitter>::emitVectorConversion(const Expr *Src, const Expr *E) {
const auto *VT = E->getType()->castAs<VectorType>();
QualType ElemType = VT->getElementType();
PrimType ElemT = classifyPrim(ElemType);
- const Expr *Src = E->getSrcExpr();
QualType SrcType = Src->getType();
PrimType SrcElemT = classifyVectorElementType(SrcType);
@@ -4392,10 +4391,15 @@ bool Compiler<Emitter>::VisitConvertVectorExpr(const ConvertVectorExpr *E) {
if (!this->emitInitElem(ElemT, I, E))
return false;
}
-
return true;
}
+template <class Emitter>
+bool Compiler<Emitter>::VisitConvertVectorExpr(const ConvertVectorExpr *E) {
+ assert(Initializing);
+ return emitVectorConversion(E->getSrcExpr(), E);
+}
+
template <class Emitter>
bool Compiler<Emitter>::VisitShuffleVectorExpr(const ShuffleVectorExpr *E) {
// FIXME: Unary shuffle with mask not currently supported.
@@ -8133,12 +8137,6 @@ bool Compiler<Emitter>::emitVectorElementwiseCast(const CastExpr *E) {
assert(SubExpr->getType()->isVectorType() && "expected vector source type");
assert(E->getType()->isVectorType() && "expected vector destination type");
- const auto *DstVTy = E->getType()->getAs<VectorType>();
- unsigned NumElts = DstVTy->getNumElements();
- PrimType SrcElemT = classifyVectorElementType(SubExpr->getType());
- PrimType DstElemT = classifyVectorElementType(E->getType());
- QualType DstElemType = DstVTy->getElementType();
-
if (!Initializing) {
UnsignedOrNone LocalIndex = allocateLocal(E);
if (!LocalIndex)
@@ -8147,24 +8145,7 @@ bool Compiler<Emitter>::emitVectorElementwiseCast(const CastExpr *E) {
return false;
}
- unsigned SrcOffset =
- allocateLocalPrimitive(SubExpr, PT_Ptr, /*IsConst=*/true);
- if (!this->visit(SubExpr))
- return false;
- if (!this->emitSetLocal(PT_Ptr, SrcOffset, E))
- return false;
-
- for (unsigned I = 0; I < NumElts; ++I) {
- if (!this->emitGetLocal(PT_Ptr, SrcOffset, E))
- return false;
- if (!this->emitArrayElemPop(SrcElemT, I, E))
- return false;
- if (!this->emitPrimCast(SrcElemT, DstElemT, DstElemType, E))
- return false;
- if (!this->emitInitElem(DstElemT, I, E))
- return false;
- }
- return true;
+ return emitVectorConversion(SubExpr, E);
}
/// Replicate a scalar value into every scalar element of an aggregate.
diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h
index 3626fd62f7f1f..257e2716ce7d0 100644
--- a/clang/lib/AST/ByteCode/Compiler.h
+++ b/clang/lib/AST/ByteCode/Compiler.h
@@ -427,6 +427,7 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
bool emitHLSLAggregateSplat(PrimType SrcT, unsigned SrcOffset,
QualType DestType, const Expr *E);
+ bool emitVectorConversion(const Expr *Src, const Expr *E);
/// A scalar element extracted during HLSL aggregate flattening.
struct HLSLFlatElement {
diff --git a/clang/test/SemaHLSL/Language/ConstexprVectorCasts.hlsl b/clang/test/SemaHLSL/Language/ConstexprVectorCasts.hlsl
new file mode 100644
index 0000000000000..e69a714bdbfad
--- /dev/null
+++ b/clang/test/SemaHLSL/Language/ConstexprVectorCasts.hlsl
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-compute -finclude-default-header -fnative-int16-type -fnative-half-type -fexperimental-new-constant-interpreter -verify=expected,both %s
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-compute -finclude-default-header -fnative-int16-type -fnative-half-type -verify=ref,both %s
+
+const float3 F;
+
+struct S {
+ float V;
+};
+
+[numthreads(1,1,1)]
+void main () {
+ S Vals[] = {1,2,3}; // expected-note {{declared here}}
+ constexpr int3 I = false ? (float3)Vals : Vals[0].V.xxx; // #conversions
+ // both-warning@#conversions {{implicit conversion turns floating-point number into integer: 'float3' (aka 'vector<float, 3>') to 'vector<int, 3>' (vector of 3 'int' values)}}
+ // both-warning@#conversions {{implicit conversion turns floating-point number into integer: 'vector<float, 3>' (vector of 3 'float' values) to 'vector<int, 3>' (vector of 3 'int' values)}}
+ // both-error@#conversions {{constexpr variable 'I' must be initialized by a constant expression}}
+ // expected-note@#conversions {{read of non-constexpr variable 'Vals' is not allowed in a constant expression}}
+
+ constexpr float2 F2 = {4800000, -4800000};
+ constexpr vector<int16_t,2> I16 = F2; // #range
+ // both-warning@#range {{implicit conversion turns floating-point number into integer: 'const float2' (aka 'const vector<float, 2>') to 'vector<int16_t, 2>' (vector of 2 'int16_t' values)}}
+ // both-error@#range {{constexpr variable 'I16' must be initialized by a constant expression}}
+ // both-note@#range {{value 4.8E+6 is outside the range of representable values of type 'int16_t' (aka 'short')}}
+}
>From 33aeafc5bc8bde3b96207dea592f83cd66fea7bb Mon Sep 17 00:00:00 2001
From: Chris Bieneman <chris.bieneman at me.com>
Date: Mon, 11 May 2026 11:11:41 -0500
Subject: [PATCH 3/6] Oops. Forgot to save before pushing.
../clang/test/SemaHLSL/Language/ConstexprVectorCasts.hlsl
---
clang/test/SemaHLSL/Language/ConstexprVectorCasts.hlsl | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/clang/test/SemaHLSL/Language/ConstexprVectorCasts.hlsl b/clang/test/SemaHLSL/Language/ConstexprVectorCasts.hlsl
index e69a714bdbfad..fbacb44931c99 100644
--- a/clang/test/SemaHLSL/Language/ConstexprVectorCasts.hlsl
+++ b/clang/test/SemaHLSL/Language/ConstexprVectorCasts.hlsl
@@ -20,5 +20,6 @@ void main () {
constexpr vector<int16_t,2> I16 = F2; // #range
// both-warning@#range {{implicit conversion turns floating-point number into integer: 'const float2' (aka 'const vector<float, 2>') to 'vector<int16_t, 2>' (vector of 2 'int16_t' values)}}
// both-error@#range {{constexpr variable 'I16' must be initialized by a constant expression}}
- // both-note@#range {{value 4.8E+6 is outside the range of representable values of type 'int16_t' (aka 'short')}}
+ // ref-note@#range {{value 4.8E+6 is outside the range of representable values of type 'int16_t' (aka 'short')}}
+ // expected-note@#range {{value 4.8E+6 is outside the range of representable values of type 'vector<int16_t, 2>' (vector of 2 'int16_t' values)}}
}
>From 06e65b507d81a7fff6e679c29a7e932146a6f952 Mon Sep 17 00:00:00 2001
From: Chris Bieneman <chris.bieneman at me.com>
Date: Mon, 11 May 2026 13:08:37 -0500
Subject: [PATCH 4/6] Forgot to include this file in my last push
---
clang/lib/AST/ExprConstant.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index f92e04666413a..3a7a67838879f 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -11793,7 +11793,7 @@ bool VectorExprEvaluator::VisitCastExpr(const CastExpr *E) {
for (unsigned I = 0; I < NElts; ++I) {
if (!handleScalarCast(Info, FPO, E, SrcEltTy, DstEltTy,
SrcVal.getVectorElt(I), ResultEls[I]))
- return false;
+ return Error(E);
}
return Success(ResultEls, E);
}
>From 3be9052e258e48beaf70833a41b454d45fefa45d Mon Sep 17 00:00:00 2001
From: Chris Bieneman <chris.bieneman at me.com>
Date: Wed, 13 May 2026 18:38:38 -0500
Subject: [PATCH 5/6] Cleanup based on PR feedback
---
clang/lib/AST/ByteCode/Compiler.cpp | 42 ++++++++++-------------------
1 file changed, 14 insertions(+), 28 deletions(-)
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index e0410ceeeb97c..343b569346807 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -377,7 +377,7 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *E) {
case CK_FloatingCast: {
// HLSL uses CK_FloatingCast to cast between vectors.
if (E->getType()->isVectorType())
- return this->emitVectorElementwiseCast(E);
+ return this->emitVectorConversion(E->getSubExpr(), E);
if (!SubExpr->getType()->isFloatingType() ||
!E->getType()->isFloatingType())
return false;
@@ -389,7 +389,7 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *E) {
case CK_IntegralToFloating: {
if (E->getType()->isVectorType())
- return this->emitVectorElementwiseCast(E);
+ return this->emitVectorConversion(E->getSubExpr(), E);
if (!E->getType()->isRealFloatingType())
return false;
if (!this->visit(SubExpr))
@@ -401,7 +401,7 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *E) {
case CK_FloatingToBoolean: {
if (E->getType()->isVectorType())
- return this->emitVectorElementwiseCast(E);
+ return this->emitVectorConversion(E->getSubExpr(), E);
if (!SubExpr->getType()->isRealFloatingType() ||
!E->getType()->isBooleanType())
return false;
@@ -414,7 +414,7 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *E) {
case CK_FloatingToIntegral: {
if (E->getType()->isVectorType())
- return this->emitVectorElementwiseCast(E);
+ return this->emitVectorConversion(E->getSubExpr(), E);
if (!E->getType()->isIntegralOrEnumerationType())
return false;
if (!this->visit(SubExpr))
@@ -563,7 +563,7 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *E) {
case CK_IntegralToBoolean:
case CK_FixedPointToBoolean: {
if (E->getType()->isVectorType())
- return this->emitVectorElementwiseCast(E);
+ return this->emitVectorConversion(E->getSubExpr(), E);
// HLSL uses this to cast to one-element vectors.
OptPrimType FromT = classify(SubExpr->getType());
if (!FromT)
@@ -578,7 +578,7 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *E) {
case CK_IntegralCast:
if (E->getType()->isVectorType())
- return this->emitVectorElementwiseCast(E);
+ return this->emitVectorConversion(E->getSubExpr(), E);
[[fallthrough]];
case CK_BooleanToSignedIntegral: {
OptPrimType FromT = classify(SubExpr->getType());
@@ -4366,6 +4366,14 @@ bool Compiler<Emitter>::emitVectorConversion(const Expr *Src, const Expr *E) {
QualType SrcType = Src->getType();
PrimType SrcElemT = classifyVectorElementType(SrcType);
+ if (!Initializing) {
+ UnsignedOrNone LocalIndex = allocateLocal(E);
+ if (!LocalIndex)
+ return false;
+ if (!this->emitGetPtrLocal(*LocalIndex, E))
+ return false;
+ }
+
unsigned SrcOffset =
this->allocateLocalPrimitive(Src, PT_Ptr, /*IsConst=*/true);
if (!this->visit(Src))
@@ -4396,7 +4404,6 @@ bool Compiler<Emitter>::emitVectorConversion(const Expr *Src, const Expr *E) {
template <class Emitter>
bool Compiler<Emitter>::VisitConvertVectorExpr(const ConvertVectorExpr *E) {
- assert(Initializing);
return emitVectorConversion(E->getSrcExpr(), E);
}
@@ -8127,27 +8134,6 @@ bool Compiler<Emitter>::emitBuiltinBitCast(const CastExpr *E) {
return true;
}
-/// Cast each element of a source vector to the corresponding element type of a
-/// destination vector using a scalar primitive cast. A pointer to the
-/// destination must be on top of the interpreter stack when \p Initializing is
-/// true; otherwise a new local is allocated for the result.
-template <class Emitter>
-bool Compiler<Emitter>::emitVectorElementwiseCast(const CastExpr *E) {
- const Expr *SubExpr = E->getSubExpr();
- assert(SubExpr->getType()->isVectorType() && "expected vector source type");
- assert(E->getType()->isVectorType() && "expected vector destination type");
-
- if (!Initializing) {
- UnsignedOrNone LocalIndex = allocateLocal(E);
- if (!LocalIndex)
- return false;
- if (!this->emitGetPtrLocal(*LocalIndex, E))
- return false;
- }
-
- return emitVectorConversion(SubExpr, E);
-}
-
/// Replicate a scalar value into every scalar element of an aggregate.
/// The scalar is stored in a local at \p SrcOffset and a pointer to the
/// destination must be on top of the interpreter stack. Each element receives
>From 785b72e97a6072d13d5c2159bf27b36f22eeca35 Mon Sep 17 00:00:00 2001
From: Chris B <cbieneman at microsoft.com>
Date: Wed, 27 May 2026 17:52:35 -0500
Subject: [PATCH 6/6] Update clang/lib/AST/ByteCode/Compiler.h
Co-authored-by: Deric C. <cheung.deric at gmail.com>
---
clang/lib/AST/ByteCode/Compiler.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h
index 257e2716ce7d0..ce5548f557152 100644
--- a/clang/lib/AST/ByteCode/Compiler.h
+++ b/clang/lib/AST/ByteCode/Compiler.h
@@ -415,7 +415,6 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
bool emitComplexBoolCast(const Expr *E);
bool emitComplexComparison(const Expr *LHS, const Expr *RHS,
const BinaryOperator *E);
- bool emitVectorElementwiseCast(const CastExpr *E);
bool emitRecordDestructionPop(const Record *R, SourceInfo Loc);
bool emitDestructionPop(const Descriptor *Desc, SourceInfo Loc);
bool emitDummyPtr(const DeclTy &D, const Expr *E);
More information about the cfe-commits
mailing list