[clang] [HLSL] Vector vector standard conversions (PR #71098)
Chris B via cfe-commits
cfe-commits at lists.llvm.org
Tue Nov 7 06:58:13 PST 2023
https://github.com/llvm-beanz updated https://github.com/llvm/llvm-project/pull/71098
>From 6bf40beff47c6bfcc73ce4c5d75bd47b52e6959c Mon Sep 17 00:00:00 2001
From: Chris Bieneman <chris.bieneman at me.com>
Date: Wed, 1 Nov 2023 12:18:43 -0500
Subject: [PATCH] [HLSL] Vector vector standard conversions
HLSL supports vector truncation and element conversions as part of
standard conversion sequences. The vector truncation conversion is a C++
second conversion in the conversion sequence. If a vector truncation is
in a conversion sequence an element conversion may occur after it before
the standard C++ third conversion.
Vector element conversions can be boolean conversions, floating point or
integral conversions or promotions.
[HLSL Draft
Specification](https://microsoft.github.io/hlsl-specs/specs/hlsl.pdf)
../clang/test/CodeGenHLSL/BasicFeatures/standard_conversion_sequences.hl
sl
../clang/test/SemaHLSL/BuiltIns/vector-constructors-erros.hlsl
../clang/test/SemaHLSL/standard_conversion_sequences.hlsl
---
clang/include/clang/AST/OperationKinds.def | 3 +
.../clang/Basic/DiagnosticSemaKinds.td | 3 +
clang/include/clang/Sema/Overload.h | 12 +-
clang/lib/AST/Expr.cpp | 1 +
clang/lib/AST/ExprConstant.cpp | 2 +
clang/lib/CodeGen/CGExpr.cpp | 2 +
clang/lib/CodeGen/CGExprAgg.cpp | 2 +
clang/lib/CodeGen/CGExprComplex.cpp | 1 +
clang/lib/CodeGen/CGExprConstant.cpp | 1 +
clang/lib/CodeGen/CGExprScalar.cpp | 23 +-
clang/lib/Edit/RewriteObjCFoundationAPI.cpp | 4 +
clang/lib/Sema/SemaChecking.cpp | 11 +-
clang/lib/Sema/SemaExprCXX.cpp | 84 ++++++
clang/lib/Sema/SemaInit.cpp | 2 +-
clang/lib/Sema/SemaOverload.cpp | 253 +++++++++++-------
clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | 3 +-
.../standard_conversion_sequences.hlsl | 119 ++++++++
.../BuiltIns/vector-constructors-erros.hlsl | 2 +-
.../standard_conversion_sequences.hlsl | 92 +++++++
19 files changed, 510 insertions(+), 110 deletions(-)
create mode 100644 clang/test/CodeGenHLSL/BasicFeatures/standard_conversion_sequences.hlsl
create mode 100644 clang/test/SemaHLSL/standard_conversion_sequences.hlsl
diff --git a/clang/include/clang/AST/OperationKinds.def b/clang/include/clang/AST/OperationKinds.def
index 8dd98730dff7426..e497fe4d1f93ff4 100644
--- a/clang/include/clang/AST/OperationKinds.def
+++ b/clang/include/clang/AST/OperationKinds.def
@@ -361,6 +361,9 @@ CAST_OPERATION(AddressSpaceConversion)
// Convert an integer initializer to an OpenCL sampler.
CAST_OPERATION(IntToOCLSampler)
+// Truncate a vector type (HLSL only).
+CAST_OPERATION(VectorTruncation)
+
//===- Binary Operations -------------------------------------------------===//
// Operators listed in order of precedence.
// Note that additions to this should also update the StmtVisitor class,
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 4614324babb1c91..8ae509168cf17f6 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12004,6 +12004,9 @@ def err_hlsl_pointers_unsupported : Error<
def err_hlsl_operator_unsupported : Error<
"the '%select{&|*|->}0' operator is unsupported in HLSL">;
+def warn_hlsl_impcast_vector_truncation : Warning<
+ "implicit conversion truncates vector: %0 to %1">, InGroup<Conversion>;
+
// Layout randomization diagnostics.
def err_non_designated_init_used : Error<
"a randomized struct can only be initialized with a designated initializer">;
diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h
index a97968dc7b20967..0d4aaa5ff7c766b 100644
--- a/clang/include/clang/Sema/Overload.h
+++ b/clang/include/clang/Sema/Overload.h
@@ -192,6 +192,9 @@ class Sema;
/// C-only conversion between pointers with incompatible types
ICK_Incompatible_Pointer_Conversion,
+ /// HLSL vector truncation.
+ ICK_HLSL_Vector_Truncation,
+
/// The number of conversion kinds
ICK_Num_Conversion_Kinds,
};
@@ -271,6 +274,12 @@ class Sema;
/// pointer-to-member conversion, or boolean conversion.
ImplicitConversionKind Second : 8;
+ /// Element - Between the second and third conversion a vector or matrix
+ /// element conversion may occur. If this is not ICK_Identity this
+ /// conversion is applied element-wise to each element in the vector or
+ /// matrix.
+ ImplicitConversionKind Element : 8;
+
/// Third - The third conversion can be a qualification conversion
/// or a function conversion.
ImplicitConversionKind Third : 8;
@@ -357,7 +366,8 @@ class Sema;
void setAsIdentityConversion();
bool isIdentityConversion() const {
- return Second == ICK_Identity && Third == ICK_Identity;
+ return Second == ICK_Identity && Element == ICK_Identity &&
+ Third == ICK_Identity;
}
ImplicitConversionRank getRank() const;
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 74a9c49a795b4fc..778abd81c94ad47 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -1898,6 +1898,7 @@ bool CastExpr::CastConsistency() const {
case CK_FixedPointToIntegral:
case CK_IntegralToFixedPoint:
case CK_MatrixCast:
+ case CK_VectorTruncation:
assert(!getType()->isBooleanType() && "unheralded conversion to bool");
goto CheckNoBasePath;
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index e16fec6109e744e..ea60ef06b3c46a6 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -13888,6 +13888,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_FixedPointCast:
case CK_IntegralToFixedPoint:
case CK_MatrixCast:
+ case CK_VectorTruncation:
llvm_unreachable("invalid cast kind for integral value");
case CK_BitCast:
@@ -14726,6 +14727,7 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_FixedPointToIntegral:
case CK_IntegralToFixedPoint:
case CK_MatrixCast:
+ case CK_VectorTruncation:
llvm_unreachable("invalid cast kind for complex value");
case CK_LValueToRValue:
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index be30d23a309720f..c1130daf6f43f14 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -4839,6 +4839,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
case CK_FixedPointToIntegral:
case CK_IntegralToFixedPoint:
case CK_MatrixCast:
+ case CK_VectorTruncation:
return EmitUnsupportedLValue(E, "unexpected cast lvalue");
case CK_Dependent:
@@ -4966,6 +4967,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
return MakeAddrLValue(V, E->getType(), LV.getBaseInfo(),
CGM.getTBAAInfoForSubobject(LV, E->getType()));
}
+
case CK_ZeroToOCLOpaqueType:
llvm_unreachable("NULL to OpenCL opaque type lvalue cast is not valid");
}
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index 810b28f25fa18bf..f9278133e5ddc6b 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -930,6 +930,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
case CK_BuiltinFnToFnPtr:
case CK_ZeroToOCLOpaqueType:
case CK_MatrixCast:
+ case CK_VectorTruncation:
case CK_IntToOCLSampler:
case CK_FloatingToFixedPoint:
@@ -1454,6 +1455,7 @@ static bool castPreservesZero(const CastExpr *CE) {
case CK_MatrixCast:
case CK_NonAtomicToAtomic:
case CK_AtomicToNonAtomic:
+ case CK_VectorTruncation:
return true;
case CK_BaseToDerivedMemberPointer:
diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp
index f3cbd1d0451ebe4..45862701d59bb4a 100644
--- a/clang/lib/CodeGen/CGExprComplex.cpp
+++ b/clang/lib/CodeGen/CGExprComplex.cpp
@@ -556,6 +556,7 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastKind CK, Expr *Op,
case CK_FixedPointToIntegral:
case CK_IntegralToFixedPoint:
case CK_MatrixCast:
+ case CK_VectorTruncation:
llvm_unreachable("invalid cast kind for complex value");
case CK_FloatingRealToComplex:
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index 69616dcc07efe1f..c8ef290f1e6384a 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -1225,6 +1225,7 @@ class ConstExprEmitter :
case CK_IntegralToFixedPoint:
case CK_ZeroToOCLOpaqueType:
case CK_MatrixCast:
+ case CK_VectorTruncation:
return nullptr;
}
llvm_unreachable("Invalid CastKind");
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 1a7a3f97bb779a0..b48b329fd2c5a39 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -610,6 +610,8 @@ class ScalarExprEmitter
llvm::Value *EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
bool isInc, bool isPre);
+ llvm::Value *EmitVectorElementConversion(QualType SrcType, QualType DstType,
+ llvm::Value *Src);
Value *VisitUnaryAddrOf(const UnaryOperator *E) {
if (isa<MemberPointerType>(E->getType())) // never sugared
@@ -1422,6 +1424,9 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
return Builder.CreateVectorSplat(NumElements, Src, "splat");
}
+ if (SrcType->isExtVectorType() && DstType->isExtVectorType())
+ return EmitVectorElementConversion(SrcType, DstType, Src);
+
if (SrcType->isMatrixType() && DstType->isMatrixType())
return EmitScalarCast(Src, SrcType, DstType, SrcTy, DstTy, Opts);
@@ -1701,10 +1706,14 @@ Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
}
Value *ScalarExprEmitter::VisitConvertVectorExpr(ConvertVectorExpr *E) {
- QualType SrcType = E->getSrcExpr()->getType(),
- DstType = E->getType();
+ QualType SrcType = E->getSrcExpr()->getType(), DstType = E->getType();
+ Value *Src = CGF.EmitScalarExpr(E->getSrcExpr());
+ return EmitVectorElementConversion(SrcType, DstType, Src);
+}
- Value *Src = CGF.EmitScalarExpr(E->getSrcExpr());
+llvm::Value *ScalarExprEmitter::EmitVectorElementConversion(QualType SrcType,
+ QualType DstType,
+ Value *Src) {
SrcType = CGF.getContext().getCanonicalType(SrcType);
DstType = CGF.getContext().getCanonicalType(DstType);
@@ -2476,6 +2485,14 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
case CK_IntToOCLSampler:
return CGF.CGM.createOpenCLIntToSamplerConversion(E, CGF);
+ case CK_VectorTruncation: {
+ assert(DestTy->isVectorType() && "Expected dest type to be vector type");
+ Value *Vec = Visit(const_cast<Expr *>(E));
+ SmallVector<int, 16> Mask;
+ Mask.insert(Mask.begin(), DestTy->getAs<VectorType>()->getNumElements(), 0);
+ return Builder.CreateShuffleVector(Vec, Mask, "trunc");
+ }
+
} // end of switch
llvm_unreachable("unknown scalar cast");
diff --git a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
index adb34eba4970306..d42532cc15d27e1 100644
--- a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
+++ b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
@@ -1087,6 +1087,10 @@ static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
case CK_BooleanToSignedIntegral:
llvm_unreachable("OpenCL-specific cast in Objective-C?");
+ case CK_VectorTruncation:
+ llvm_unreachable("HLSL-specific cast in Objective-C?");
+ break;
+
case CK_FloatingToFixedPoint:
case CK_FixedPointToFloating:
case CK_FixedPointCast:
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index ae588db02bbe722..2e73d655b092785 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -15421,11 +15421,18 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
if (S.SourceMgr.isInSystemMacro(CC))
return;
return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_vector_scalar);
+ } else if (S.getLangOpts().HLSL &&
+ Target->getAs<VectorType>()->getNumElements() <
+ Source->getAs<VectorType>()->getNumElements()) {
+ // Diagnose vector truncation but don't return. We may also want to
+ // diagnose an element conversion.
+ DiagnoseImpCast(S, E, T, CC, diag::warn_hlsl_impcast_vector_truncation);
}
// If the vector cast is cast between two vectors of the same size, it is
- // a bitcast, not a conversion.
- if (S.Context.getTypeSize(Source) == S.Context.getTypeSize(Target))
+ // a bitcast, not a conversion, except under HLSL where it is a conversion.
+ if (!S.getLangOpts().HLSL &&
+ S.Context.getTypeSize(Source) == S.Context.getTypeSize(Target))
return;
Source = cast<VectorType>(Source)->getElementType().getTypePtr();
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index c07462aa2444403..7f8190c974c5f99 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -4727,6 +4727,20 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
CK_ZeroToOCLOpaqueType,
From->getValueKind()).get();
break;
+ case ICK_HLSL_Vector_Truncation: {
+ // Note: HLSL vectors are ExtVectors. Since this truncates a vector to a
+ // smaller vector, this can only operate on arguments where the source and
+ // destination types are ExtVectors.
+ auto *FromVec = From->getType()->castAs<ExtVectorType>();
+ auto *ToVec = ToType->castAs<ExtVectorType>();
+ QualType ElType = FromVec->getElementType();
+ QualType TruncTy =
+ Context.getExtVectorType(ElType, ToVec->getNumElements());
+ From = ImpCastExprToType(From, TruncTy, CK_VectorTruncation,
+ From->getValueKind())
+ .get();
+ break;
+ }
case ICK_Lvalue_To_Rvalue:
case ICK_Array_To_Pointer:
@@ -4739,6 +4753,76 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
llvm_unreachable("Improper second standard conversion");
}
+ if (SCS.Element != ICK_Identity) {
+ // if SCS.Element is not ICK_Identity the To and From types must be HLSL
+ // vectors or matrices. HLSL matrices aren't yet supported so this code only
+ // handles vectors for now.
+
+ assert(From->getType()->isVectorType() && ToType->isVectorType() &&
+ "Element conversion is only supported for vector types.");
+ assert(From->getType()->getAs<VectorType>()->getNumElements() ==
+ ToType->getAs<VectorType>()->getNumElements() &&
+ "Element conversion is only supported for vectors with the same "
+ "element counts.");
+ QualType FromElTy = From->getType()->getAs<VectorType>()->getElementType();
+ unsigned NumElts = ToType->getAs<VectorType>()->getNumElements();
+ switch (SCS.Element) {
+ case ICK_Identity:
+ // Nothing to do.
+ break;
+ case ICK_Boolean_Conversion:
+ // Perform half-to-boolean conversion via float.
+ if (FromElTy->isHalfType()) {
+ QualType FPExtType = Context.getExtVectorType(FromElTy, NumElts);
+ From = ImpCastExprToType(From, FPExtType, CK_FloatingCast).get();
+ FromType = FPExtType;
+ }
+
+ From =
+ ImpCastExprToType(From, ToType, ScalarTypeToBooleanCastKind(FromElTy),
+ VK_PRValue,
+ /*BasePath=*/nullptr, CCK)
+ .get();
+ break;
+ case ICK_Integral_Promotion:
+ case ICK_Integral_Conversion:
+ if (ToType->isBooleanType()) {
+ assert(FromType->castAs<EnumType>()->getDecl()->isFixed() &&
+ SCS.Second == ICK_Integral_Promotion &&
+ "only enums with fixed underlying type can promote to bool");
+ From = ImpCastExprToType(From, ToType, CK_IntegralToBoolean, VK_PRValue,
+ /*BasePath=*/nullptr, CCK)
+ .get();
+ } else {
+ From = ImpCastExprToType(From, ToType, CK_IntegralCast, VK_PRValue,
+ /*BasePath=*/nullptr, CCK)
+ .get();
+ }
+ break;
+
+ case ICK_Floating_Promotion:
+ case ICK_Floating_Conversion:
+ From = ImpCastExprToType(From, ToType, CK_FloatingCast, VK_PRValue,
+ /*BasePath=*/nullptr, CCK)
+ .get();
+ break;
+ case ICK_Floating_Integral:
+ if (ToType->isRealFloatingType())
+ From =
+ ImpCastExprToType(From, ToType, CK_IntegralToFloating, VK_PRValue,
+ /*BasePath=*/nullptr, CCK)
+ .get();
+ else
+ From =
+ ImpCastExprToType(From, ToType, CK_FloatingToIntegral, VK_PRValue,
+ /*BasePath=*/nullptr, CCK)
+ .get();
+ break;
+ default:
+ llvm_unreachable("Improper element standard conversion");
+ }
+ }
+
switch (SCS.Third) {
case ICK_Identity:
// Nothing to do.
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 80b51b09bf5445f..9b90c38a32eb2d4 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -6427,7 +6427,7 @@ void InitializationSequence::InitializeFrom(Sema &S,
// For HLSL ext vector types we allow list initialization behavior for C++
// constructor syntax. This is accomplished by converting initialization
// arguments an InitListExpr late.
- if (S.getLangOpts().HLSL && DestType->isExtVectorType() &&
+ if (S.getLangOpts().HLSL && Args.size() > 1 && DestType->isExtVectorType() &&
(SourceType.isNull() ||
!Context.hasSameUnqualifiedType(SourceType, DestType))) {
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index f97e244120612e3..758ef85a0e67ae5 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -123,43 +123,21 @@ CompareDerivedToBaseConversions(Sema &S, SourceLocation Loc,
/// GetConversionRank - Retrieve the implicit conversion rank
/// corresponding to the given implicit conversion kind.
ImplicitConversionRank clang::GetConversionRank(ImplicitConversionKind Kind) {
- static const ImplicitConversionRank
- Rank[] = {
- ICR_Exact_Match,
- ICR_Exact_Match,
- ICR_Exact_Match,
- ICR_Exact_Match,
- ICR_Exact_Match,
- ICR_Exact_Match,
- ICR_Promotion,
- ICR_Promotion,
- ICR_Promotion,
- ICR_Conversion,
- ICR_Conversion,
- ICR_Conversion,
- ICR_Conversion,
- ICR_Conversion,
- ICR_Conversion,
- ICR_Conversion,
- ICR_Conversion,
- ICR_Conversion,
- ICR_Conversion,
- ICR_Conversion,
- ICR_Conversion,
- ICR_OCL_Scalar_Widening,
- ICR_Complex_Real_Conversion,
- ICR_Conversion,
- ICR_Conversion,
- ICR_Writeback_Conversion,
- ICR_Exact_Match, // NOTE(gbiv): This may not be completely right --
- // it was omitted by the patch that added
- // ICK_Zero_Event_Conversion
- ICR_Exact_Match, // NOTE(ctopper): This may not be completely right --
- // it was omitted by the patch that added
- // ICK_Zero_Queue_Conversion
- ICR_C_Conversion,
- ICR_C_Conversion_Extension
- };
+ static const ImplicitConversionRank Rank[] = {
+ ICR_Exact_Match, ICR_Exact_Match, ICR_Exact_Match, ICR_Exact_Match,
+ ICR_Exact_Match, ICR_Exact_Match, ICR_Promotion, ICR_Promotion,
+ ICR_Promotion, ICR_Conversion, ICR_Conversion, ICR_Conversion,
+ ICR_Conversion, ICR_Conversion, ICR_Conversion, ICR_Conversion,
+ ICR_Conversion, ICR_Conversion, ICR_Conversion, ICR_Conversion,
+ ICR_Conversion, ICR_OCL_Scalar_Widening, ICR_Complex_Real_Conversion,
+ ICR_Conversion, ICR_Conversion, ICR_Writeback_Conversion,
+ ICR_Exact_Match, // NOTE(gbiv): This may not be completely right --
+ // it was omitted by the patch that added
+ // ICK_Zero_Event_Conversion
+ ICR_Exact_Match, // NOTE(ctopper): This may not be completely right --
+ // it was omitted by the patch that added
+ // ICK_Zero_Queue_Conversion
+ ICR_C_Conversion, ICR_C_Conversion_Extension, ICR_C_Conversion};
static_assert(std::size(Rank) == (int)ICK_Num_Conversion_Kinds);
return Rank[(int)Kind];
}
@@ -167,38 +145,37 @@ ImplicitConversionRank clang::GetConversionRank(ImplicitConversionKind Kind) {
/// GetImplicitConversionName - Return the name of this kind of
/// implicit conversion.
static const char* GetImplicitConversionName(ImplicitConversionKind Kind) {
- static const char* const Name[] = {
- "No conversion",
- "Lvalue-to-rvalue",
- "Array-to-pointer",
- "Function-to-pointer",
- "Function pointer conversion",
- "Qualification",
- "Integral promotion",
- "Floating point promotion",
- "Complex promotion",
- "Integral conversion",
- "Floating conversion",
- "Complex conversion",
- "Floating-integral conversion",
- "Pointer conversion",
- "Pointer-to-member conversion",
- "Boolean conversion",
- "Compatible-types conversion",
- "Derived-to-base conversion",
- "Vector conversion",
- "SVE Vector conversion",
- "RVV Vector conversion",
- "Vector splat",
- "Complex-real conversion",
- "Block Pointer conversion",
- "Transparent Union Conversion",
- "Writeback conversion",
- "OpenCL Zero Event Conversion",
- "OpenCL Zero Queue Conversion",
- "C specific type conversion",
- "Incompatible pointer conversion"
- };
+ static const char *const Name[] = {"No conversion",
+ "Lvalue-to-rvalue",
+ "Array-to-pointer",
+ "Function-to-pointer",
+ "Function pointer conversion",
+ "Qualification",
+ "Integral promotion",
+ "Floating point promotion",
+ "Complex promotion",
+ "Integral conversion",
+ "Floating conversion",
+ "Complex conversion",
+ "Floating-integral conversion",
+ "Pointer conversion",
+ "Pointer-to-member conversion",
+ "Boolean conversion",
+ "Compatible-types conversion",
+ "Derived-to-base conversion",
+ "Vector conversion",
+ "SVE Vector conversion",
+ "RVV Vector conversion",
+ "Vector splat",
+ "Complex-real conversion",
+ "Block Pointer conversion",
+ "Transparent Union Conversion",
+ "Writeback conversion",
+ "OpenCL Zero Event Conversion",
+ "OpenCL Zero Queue Conversion",
+ "C specific type conversion",
+ "Incompatible pointer conversion",
+ "HLSL vector truncation"};
static_assert(std::size(Name) == (int)ICK_Num_Conversion_Kinds);
return Name[Kind];
}
@@ -208,6 +185,7 @@ static const char* GetImplicitConversionName(ImplicitConversionKind Kind) {
void StandardConversionSequence::setAsIdentityConversion() {
First = ICK_Identity;
Second = ICK_Identity;
+ Element = ICK_Identity;
Third = ICK_Identity;
DeprecatedStringLiteralToCharPtr = false;
QualificationIncludesObjCLifetime = false;
@@ -1841,13 +1819,86 @@ bool Sema::IsFunctionConversion(QualType FromType, QualType ToType,
return true;
}
+/// Determine whether the conversion from FromType to ToType is a valid
+/// floating point conversion.
+///
+static bool IsFloatingPointConversion(Sema &S, QualType FromType,
+ QualType ToType) {
+ if (!FromType->isRealFloatingType() || !ToType->isRealFloatingType())
+ return false;
+ // FIXME: disable conversions between long double, __ibm128 and __float128
+ // if their representation is different until there is back end support
+ // We of course allow this conversion if long double is really double.
+
+ // Conversions between bfloat16 and float16 are currently not supported.
+ if ((FromType->isBFloat16Type() &&
+ (ToType->isFloat16Type() || ToType->isHalfType())) ||
+ (ToType->isBFloat16Type() &&
+ (FromType->isFloat16Type() || FromType->isHalfType())))
+ return false;
+
+ // Conversions between IEEE-quad and IBM-extended semantics are not
+ // permitted.
+ const llvm::fltSemantics &FromSem = S.Context.getFloatTypeSemantics(FromType);
+ const llvm::fltSemantics &ToSem = S.Context.getFloatTypeSemantics(ToType);
+ if ((&FromSem == &llvm::APFloat::PPCDoubleDouble() &&
+ &ToSem == &llvm::APFloat::IEEEquad()) ||
+ (&FromSem == &llvm::APFloat::IEEEquad() &&
+ &ToSem == &llvm::APFloat::PPCDoubleDouble()))
+ return false;
+ return true;
+}
+
+static bool IsVectorElementConversion(Sema &S, QualType FromType,
+ QualType ToType,
+ ImplicitConversionKind &ICK, Expr *From) {
+ if (S.Context.hasSameUnqualifiedType(FromType, ToType))
+ return true;
+
+ if (IsFloatingPointConversion(S, FromType, ToType)) {
+ ICK = ICK_Floating_Conversion;
+ return true;
+ }
+
+ if (S.IsFloatingPointPromotion(FromType, ToType)) {
+ ICK = ICK_Floating_Promotion;
+ return true;
+ }
+
+ if (ToType->isBooleanType() && FromType->isArithmeticType()) {
+ ICK = ICK_Boolean_Conversion;
+ return true;
+ }
+
+ if (FromType->isIntegralOrUnscopedEnumerationType() &&
+ ToType->isIntegralType(S.Context)) {
+ ICK = ICK_Integral_Conversion;
+ return true;
+ }
+
+ if (S.IsIntegralPromotion(From, FromType, ToType)) {
+ ICK = ICK_Integral_Promotion;
+ return true;
+ }
+
+ if ((FromType->isRealFloatingType() && ToType->isIntegralType(S.Context)) ||
+ (FromType->isIntegralOrUnscopedEnumerationType() &&
+ ToType->isRealFloatingType())) {
+ ICK = ICK_Floating_Integral;
+ return true;
+ }
+
+ return false;
+}
+
/// Determine whether the conversion from FromType to ToType is a valid
/// vector conversion.
///
/// \param ICK Will be set to the vector conversion kind, if this is a vector
/// conversion.
static bool IsVectorConversion(Sema &S, QualType FromType, QualType ToType,
- ImplicitConversionKind &ICK, Expr *From,
+ ImplicitConversionKind &ICK,
+ ImplicitConversionKind &ElConv, Expr *From,
bool InOverloadResolution, bool CStyle) {
// We need at least one of these types to be a vector type to have a vector
// conversion.
@@ -1860,10 +1911,28 @@ static bool IsVectorConversion(Sema &S, QualType FromType, QualType ToType,
// There are no conversions between extended vector types, only identity.
if (ToType->isExtVectorType()) {
- // There are no conversions between extended vector types other than the
- // identity conversion.
- if (FromType->isExtVectorType())
+ if (FromType->isExtVectorType()) {
+ // HLSL allows implicit truncation of vector types.
+ if (S.getLangOpts().HLSL) {
+ unsigned FromElts = FromType->getAs<VectorType>()->getNumElements();
+ unsigned ToElts = ToType->getAs<VectorType>()->getNumElements();
+ if (FromElts < ToElts)
+ return false;
+ if (FromElts == ToElts)
+ ICK = ICK_Identity;
+ else
+ ICK = ICK_HLSL_Vector_Truncation;
+
+ QualType FromElTy = FromType->getAs<VectorType>()->getElementType();
+ QualType ToElTy = ToType->getAs<VectorType>()->getElementType();
+ if (S.Context.hasSameUnqualifiedType(FromElTy, ToElTy))
+ return true;
+ return IsVectorElementConversion(S, FromElTy, ToElTy, ElConv, From);
+ }
+ // There are no conversions between extended vector types other than the
+ // identity conversion.
return false;
+ }
// Vector splat from any arithmetic type to a vector.
if (FromType->isArithmeticType()) {
@@ -2069,6 +2138,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
// conversion.
bool IncompatibleObjC = false;
ImplicitConversionKind SecondICK = ICK_Identity;
+ ImplicitConversionKind ElementICK = ICK_Identity;
if (S.Context.hasSameUnqualifiedType(FromType, ToType)) {
// The unqualified versions of the types are the same: there's no
// conversion to do.
@@ -2107,29 +2177,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
// Complex-real conversions (C99 6.3.1.7)
SCS.Second = ICK_Complex_Real;
FromType = ToType.getUnqualifiedType();
- } else if (FromType->isRealFloatingType() && ToType->isRealFloatingType()) {
- // FIXME: disable conversions between long double, __ibm128 and __float128
- // if their representation is different until there is back end support
- // We of course allow this conversion if long double is really double.
-
- // Conversions between bfloat16 and float16 are currently not supported.
- if ((FromType->isBFloat16Type() &&
- (ToType->isFloat16Type() || ToType->isHalfType())) ||
- (ToType->isBFloat16Type() &&
- (FromType->isFloat16Type() || FromType->isHalfType())))
- return false;
-
- // Conversions between IEEE-quad and IBM-extended semantics are not
- // permitted.
- const llvm::fltSemantics &FromSem =
- S.Context.getFloatTypeSemantics(FromType);
- const llvm::fltSemantics &ToSem = S.Context.getFloatTypeSemantics(ToType);
- if ((&FromSem == &llvm::APFloat::PPCDoubleDouble() &&
- &ToSem == &llvm::APFloat::IEEEquad()) ||
- (&FromSem == &llvm::APFloat::IEEEquad() &&
- &ToSem == &llvm::APFloat::PPCDoubleDouble()))
- return false;
-
+ } else if (IsFloatingPointConversion(S, FromType, ToType)) {
// Floating point conversions (C++ 4.8).
SCS.Second = ICK_Floating_Conversion;
FromType = ToType.getUnqualifiedType();
@@ -2156,18 +2204,18 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
InOverloadResolution, FromType)) {
// Pointer to member conversions (4.11).
SCS.Second = ICK_Pointer_Member;
- } else if (IsVectorConversion(S, FromType, ToType, SecondICK, From,
- InOverloadResolution, CStyle)) {
+ } else if (IsVectorConversion(S, FromType, ToType, SecondICK, ElementICK,
+ From, InOverloadResolution, CStyle)) {
SCS.Second = SecondICK;
+ SCS.Element = ElementICK;
FromType = ToType.getUnqualifiedType();
} else if (!S.getLangOpts().CPlusPlus &&
S.Context.typesAreCompatible(ToType, FromType)) {
// Compatible conversions (Clang extension for C function overloading)
SCS.Second = ICK_Compatible_Conversion;
FromType = ToType.getUnqualifiedType();
- } else if (IsTransparentUnionStandardConversion(S, From, ToType,
- InOverloadResolution,
- SCS, CStyle)) {
+ } else if (IsTransparentUnionStandardConversion(
+ S, From, ToType, InOverloadResolution, SCS, CStyle)) {
SCS.Second = ICK_TransparentUnionConversion;
FromType = ToType;
} else if (tryAtomicConversion(S, From, ToType, InOverloadResolution, SCS,
@@ -5027,6 +5075,7 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
: (RefConv & Sema::ReferenceConversions::ObjC)
? ICK_Compatible_Conversion
: ICK_Identity;
+ ICS.Standard.Element = ICK_Identity;
// FIXME: As a speculative fix to a defect introduced by CWG2352, we rank
// a reference binding that performs a non-top-level qualification
// conversion as a qualification conversion, not as an identity conversion.
@@ -5947,6 +5996,7 @@ static bool CheckConvertedConstantConversions(Sema &S,
case ICK_Zero_Event_Conversion:
case ICK_C_Only_Conversion:
case ICK_Incompatible_Pointer_Conversion:
+ case ICK_HLSL_Vector_Truncation:
return false;
case ICK_Lvalue_To_Rvalue:
@@ -6205,6 +6255,7 @@ ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
static void dropPointerConversion(StandardConversionSequence &SCS) {
if (SCS.Second == ICK_Pointer_Conversion) {
SCS.Second = ICK_Identity;
+ SCS.Element = ICK_Identity;
SCS.Third = ICK_Identity;
SCS.ToTypePtrs[2] = SCS.ToTypePtrs[1] = SCS.ToTypePtrs[0];
}
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 7e431f7e598c4cb..c90423784a3425e 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -520,7 +520,8 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
// Various C++ casts that are not handled yet.
case CK_ToUnion:
case CK_MatrixCast:
- case CK_VectorSplat: {
+ case CK_VectorSplat:
+ case CK_VectorTruncation: {
QualType resultType = CastE->getType();
if (CastE->isGLValue())
resultType = getContext().getPointerType(resultType);
diff --git a/clang/test/CodeGenHLSL/BasicFeatures/standard_conversion_sequences.hlsl b/clang/test/CodeGenHLSL/BasicFeatures/standard_conversion_sequences.hlsl
new file mode 100644
index 000000000000000..85b8eed4dafbe5d
--- /dev/null
+++ b/clang/test/CodeGenHLSL/BasicFeatures/standard_conversion_sequences.hlsl
@@ -0,0 +1,119 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
+
+// CHECK-LABEL: f3_to_d4
+// CHECK: [[f3:%.*]] = alloca <3 x float>
+// CHECK: [[d4:%.*]] = alloca <4 x double>
+// CHECK: store <3 x float> <float 1.000000e+00, float 1.000000e+00, float 1.000000e+00>, ptr [[f3]]
+// CHECK: [[vecf3:%.*]] = load <3 x float>, ptr [[f3]]
+// CHECK: [[vecf4:%.*]] = shufflevector <3 x float> [[vecf3]], <3 x float> poison, <4 x i32> <i32 0, i32 1, i32 2, i32 0>
+// CHECK: [[vecd4:%.*]] = fpext <4 x float> [[vecf4]] to <4 x double>
+// CHECK: store <4 x double> [[vecd4]], ptr [[d4]]
+void f3_to_d4() {
+ vector<float,3> f3 = 1.0;
+ vector<double,4> d4 = f3.xyzx;
+}
+
+// CHECK-LABEL: f3_to_f2
+// CHECK: [[f3:%.*]] = alloca <3 x float>
+// CHECK: [[f2:%.*]] = alloca <2 x float>
+// CHECK: store <3 x float> <float 2.000000e+00, float 2.000000e+00, float 2.000000e+00>, ptr [[f3]]
+// CHECK: [[vecf3:%.*]] = load <3 x float>, ptr [[f3]]
+// CHECK: [[vecf2:%.*]] = shufflevector <3 x float> [[vecf3]], <3 x float> poison, <2 x i32> zeroinitializer
+// CHECK: store <2 x float> [[vecf2]], ptr [[f2]]
+void f3_to_f2() {
+ vector<float,3> f3 = 2.0;
+ vector<float,2> f2 = f3;
+}
+
+// CHECK-LABEL: d4_to_f2
+// CHECK: [[d4:%.*]] = alloca <4 x double>
+// CHECK: [[f2:%.*]] = alloca <2 x float>
+// CHECK: store <4 x double> <double 3.000000e+00, double 3.000000e+00, double 3.000000e+00, double 3.000000e+00>, ptr [[d4]]
+// CHECK: [[vecd4:%.*]] = load <4 x double>, ptr [[d4]]
+// CHECK: [[vecd2:%.*]] = shufflevector <4 x double> [[vecd4]], <4 x double> poison, <2 x i32> zeroinitializer
+// CHECK: [[vecf2:%.*]] = fptrunc <2 x double> [[vecd2]] to <2 x float>
+// CHECK: store <2 x float> [[vecf2]], ptr [[f2]]
+void d4_to_f2() {
+ vector<double,4> d4 = 3.0;
+ vector<float,2> f2 = d4;
+}
+
+// CHECK-LABEL: f2_to_i2
+// CHECK: [[f2:%.*]] = alloca <2 x float>
+// CHECK: [[i2:%.*]] = alloca <2 x i32>
+// CHECK: store <2 x float> <float 4.000000e+00, float 4.000000e+00>, ptr [[f2]]
+// CHECK: [[vecf2:%.*]] = load <2 x float>, ptr [[f2]]
+// CHECK: [[veci2:%.*]] = fptosi <2 x float> [[vecf2]] to <2 x i32>
+// CHECK: store <2 x i32> [[veci2]], ptr [[i2]]
+void f2_to_i2() {
+ vector<float,2> f2 = 4.0;
+ vector<int,2> i2 = f2;
+}
+
+// CHECK-LABEL: d4_to_i2
+// CHECK: [[f4:%.*]] = alloca <4 x double>
+// CHECK: [[i2:%.*]] = alloca <2 x i32>
+// CHECK: store <4 x double> <double 5.000000e+00, double 5.000000e+00, double 5.000000e+00, double 5.000000e+00>, ptr [[d4]]
+// CHECK: [[vecd4:%.*]] = load <4 x double>, ptr [[d4]]
+// CHECK: [[vecd2:%.*]] = shufflevector <4 x double> [[vecd4]], <4 x double> poison, <2 x i32> zeroinitializer
+// CHECK: [[veci2]] = fptosi <2 x double> [[vecd2]] to <2 x i32>
+// CHECK: store <2 x i32> [[veci2]], ptr [[i2]]
+void d4_to_i2() {
+ vector<double,4> d4 = 5.0;
+ vector<int,2> i2 = d4;
+}
+
+// CHECK-LABEL: d4_to_l4
+// CHECK: [[d4:%.*]] = alloca <4 x double>
+// CHECK: [[l4:%.*]] = alloca <4 x i64>
+// CHECK: store <4 x double> <double 6.000000e+00, double 6.000000e+00, double 6.000000e+00, double 6.000000e+00>, ptr [[d4]]
+// CHECK: [[vecd4:%.*]] = load <4 x double>, ptr [[d4]]
+// CHECK: [[vecl4:%.*]] = fptosi <4 x double> [[vecd4]] to <4 x i64>
+// CHECK: store <4 x i64> [[vecl4]], ptr [[l4]]
+void d4_to_l4() {
+ vector<double,4> d4 = 6.0;
+ vector<long,4> l4 = d4;
+}
+
+
+// CHECK-LABEL: l4_to_i2
+// CHECK: [[l4:%.*]] = alloca <4 x i64>
+// CHECK: [[i2:%.*]] = alloca <2 x i32>
+// CHECK: store <4 x i64> <i64 7, i64 7, i64 7, i64 7>, ptr [[l4]]
+// CHECK: [[vecl4:%.*]] = load <4 x i64>, ptr [[l4]]
+// CHECK: [[vecl2:%.*]] = shufflevector <4 x i64> [[vecl4]], <4 x i64> poison, <2 x i32> zeroinitializer
+// CHECK: [[veci2:%.*]] = trunc <2 x i64> [[vecl2]] to <2 x i32>
+// CHECK: store <2 x i32> [[veci2]], ptr [[i2]]
+void l4_to_i2() {
+ vector<long, 4> l4 = 7;
+ vector<int,2> i2 = l4;
+}
+
+// CHECK-LABEL: i2_to_b2
+// CHECK: [[l2:%.*]] = alloca <2 x i32>
+// CHECK: [[b2:%.*]] = alloca i8
+// CHECK: store <2 x i32> <i32 8, i32 8>, ptr [[i2]]
+// CHECK: [[veci2:%.*]] = load <2 x i32>, ptr [[i2]]
+// CHECK: [[vecb2:%.*]] = icmp ne <2 x i32> [[veci2]], zeroinitializer
+// CHECK: [[vecb8:%.*]] = shufflevector <2 x i1> [[vecb2]], <2 x i1> poison, <8 x i32> <i32 0, i32 1, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>
+// CHECK: [[i8:%.*]] = bitcast <8 x i1> [[vecb8]] to i8
+// CHECK: store i8 [[i8]], ptr [[b2]]
+void i2_to_b2() {
+ vector<int, 2> i2 = 8;
+ vector<bool, 2> b2 = i2;
+}
+
+// CHECK-LABEL: d4_to_b2
+// CHECK: [[d4:%.*]] = alloca <4 x double>
+// CHECK: [[b2:%.*]] = alloca i8
+// CHECK: store <4 x double> <double 9.000000e+00, double 9.000000e+00, double 9.000000e+00, double 9.000000e+00>, ptr [[d4]]
+// CHECK: [[vecd4:%.*]] = load <4 x double>, ptr [[d4]]
+// CHECK: [[vecd2:%.*]] = shufflevector <4 x double> [[vecd4]], <4 x double> poison, <2 x i32> zeroinitializer
+// CHECK: [[vecb2:%.*]] = fcmp une <2 x double> [[vecd2]], zeroinitializer
+// CHECK: [[vecb8:%.*]] = shufflevector <2 x i1> [[vecb2]], <2 x i1> poison, <8 x i32> <i32 0, i32 1, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>
+// CHECK: [[i8:%.*]] = bitcast <8 x i1> [[vecb8]] to i8
+// CHECK: store i8 [[i8]], ptr [[b2]]
+void d4_to_b2() {
+ vector<double,4> d4 = 9.0;
+ vector<bool, 2> b2 = d4;
+}
diff --git a/clang/test/SemaHLSL/BuiltIns/vector-constructors-erros.hlsl b/clang/test/SemaHLSL/BuiltIns/vector-constructors-erros.hlsl
index 73b5a192793e0cb..7f6bdc7e67836b7 100644
--- a/clang/test/SemaHLSL/BuiltIns/vector-constructors-erros.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/vector-constructors-erros.hlsl
@@ -18,5 +18,5 @@ void entry() {
S s;
float2 GettingStrange = float2(s, s); // expected-error{{no viable conversion from 'S' to 'float'}} expected-error{{no viable conversion from 'S' to 'float'}}
S2 s2;
- float2 EvenStranger = float2(s2); // expected-error{{no viable conversion from 'S2' to 'float'}} expected-error{{too few elements in vector initialization (expected 2 elements, have 1)}}
+ float2 EvenStranger = float2(s2); // expected-error{{cannot convert 'S2' to 'float2' (vector of 2 'float' values) without a conversion operator}}
}
diff --git a/clang/test/SemaHLSL/standard_conversion_sequences.hlsl b/clang/test/SemaHLSL/standard_conversion_sequences.hlsl
new file mode 100644
index 000000000000000..ca9f2a372c02619
--- /dev/null
+++ b/clang/test/SemaHLSL/standard_conversion_sequences.hlsl
@@ -0,0 +1,92 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -Wconversion -verify -o - %s
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -Wno-conversion -DNO_ERR -ast-dump %s | FileCheck %s
+
+void test() {
+
+ // CHECK: VarDecl {{.*}} used f3 'vector<float, 3>':'float __attribute__((ext_vector_type(3)))' cinit
+ // CHECK-NEXt: ImplicitCastExpr {{.*}} 'vector<float, 3>':'float __attribute__((ext_vector_type(3)))' <VectorSplat>
+ // CHECK-NEXt: ImplicitCastExpr {{.*}} 'float' <FloatingCast>
+ // CHECK-NEXt: FloatingLiteral {{.*}} 'double' 1.000000e+00
+ vector<float,3> f3 = 1.0; // No warning for splatting to a vector from a literal.
+
+
+ // CHECK: VarDecl {{.*}} used d4 'vector<double, 4>':'double __attribute__((ext_vector_type(4)))' cinit
+ // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<double, 4>':'double __attribute__((ext_vector_type(4)))' <FloatingCast>
+ // CHECK-NEXT: ExtVectorElementExpr {{.*}} 'float __attribute__((ext_vector_type(4)))' xyzx
+ // CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 3>':'float __attribute__((ext_vector_type(3)))' lvalue Var {{.*}} 'f3' 'vector<float, 3>':'float __attribute__((ext_vector_type(3)))'
+ vector<double,4> d4 = f3.xyzx; // No warnings for promotion or explicit extension.
+
+ // CHECK: VarDecl {{.*}} used f2 'vector<float, 2>':'float __attribute__((ext_vector_type(2)))' cinit
+ // CHECK-NEXT: ImplicitCastExpr {{.*}} 'float __attribute__((ext_vector_type(2)))' <VectorTruncation>
+ // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<float, 3>':'float __attribute__((ext_vector_type(3)))' <LValueToRValue>
+ // CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 3>':'float __attribute__((ext_vector_type(3)))' lvalue Var {{.*}} 'f3' 'vector<float, 3>':'float __attribute__((ext_vector_type(3)))'
+ // expected-warning@#f2{{implicit conversion truncates vector: 'vector<float, 3>' (vector of 3 'float' values) to 'float __attribute__((ext_vector_type(2)))' (vector of 2 'float' values)}}
+ vector<float,2> f2 = f3; // #f2
+
+ // CHECK: VarDecl {{.*}} f2_2 'vector<float, 2>':'float __attribute__((ext_vector_type(2)))' cinit
+ // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<float, 2>':'float __attribute__((ext_vector_type(2)))' <FloatingCast>
+ // CHECK-NEXT: ImplicitCastExpr {{.*}} 'double __attribute__((ext_vector_type(2)))' <VectorTruncation>
+ // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<double, 4>':'double __attribute__((ext_vector_type(4)))' <LValueToRValue>
+ // CHECK-NEXT: DeclRefExpr {{.*}} 'vector<double, 4>':'double __attribute__((ext_vector_type(4)))' lvalue Var {{.*}} 'd4' 'vector<double, 4>':'double __attribute__((ext_vector_type(4)))'
+ // expected-warning@#f2_2{{implicit conversion truncates vector: 'vector<double, 4>' (vector of 4 'double' values) to 'vector<float, 2>' (vector of 2 'float' values)}}
+ // expected-warning@#f2_2{{implicit conversion loses floating-point precision: 'vector<double, 4>' (vector of 4 'double' values) to 'vector<float, 2>' (vector of 2 'float' values)}}
+ vector<float,2> f2_2 = d4; // #f2_2
+
+ // CHECK: VarDecl {{.*}} i2 'vector<int, 2>':'int __attribute__((ext_vector_type(2)))' cinit
+ // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int, 2>':'int __attribute__((ext_vector_type(2)))' <FloatingToIntegral>
+ // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<float, 2>':'float __attribute__((ext_vector_type(2)))' <LValueToRValue>
+ // CHECK-NEXT: DeclRefExpr {{.*}} 'vector<float, 2>':'float __attribute__((ext_vector_type(2)))' lvalue Var {{.*}} 'f2' 'vector<float, 2>':'float __attribute__((ext_vector_type(2)))'
+ // expected-warning@#i2{{mplicit conversion turns floating-point number into integer: 'vector<float, 2>' (vector of 2 'float' values) to 'vector<int, 2>' (vector of 2 'int' values)}}
+ vector<int,2> i2 = f2; // #i2
+
+ // CHECK: VarDecl {{.*}} i2_2 'vector<int, 2>':'int __attribute__((ext_vector_type(2)))' cinit
+ // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int, 2>':'int __attribute__((ext_vector_type(2)))' <FloatingToIntegral>
+ // CHECK-NEXT: ImplicitCastExpr {{.*}} 'double __attribute__((ext_vector_type(2)))' <VectorTruncation>
+ // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<double, 4>':'double __attribute__((ext_vector_type(4)))' <LValueToRValue>
+ // CHECK-NEXT: DeclRefExpr {{.*}} 'vector<double, 4>':'double __attribute__((ext_vector_type(4)))' lvalue Var {{.*}} 'd4' 'vector<double, 4>':'double __attribute__((ext_vector_type(4)))'
+ // expected-warning@#i2_2{{implicit conversion truncates vector: 'vector<double, 4>' (vector of 4 'double' values) to 'vector<int, 2>' (vector of 2 'int' values)}}
+ // expected-warning@#i2_2{{implicit conversion turns floating-point number into integer: 'vector<double, 4>' (vector of 4 'double' values) to 'vector<int, 2>' (vector of 2 'int' values)}}
+ vector<int,2> i2_2 = d4; // #i2_2
+
+
+ // CHECK: VarDecl {{.*}} used i64_4 'vector<long, 4>':'long __attribute__((ext_vector_type(4)))' cinit
+ // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<long, 4>':'long __attribute__((ext_vector_type(4)))' <FloatingToIntegral>
+ // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<double, 4>':'double __attribute__((ext_vector_type(4)))' <LValueToRValue>
+ // CHECK-NEXT: DeclRefExpr {{.*}} 'vector<double, 4>':'double __attribute__((ext_vector_type(4)))' lvalue Var {{.*}} 'd4' 'vector<double, 4>':'double __attribute__((ext_vector_type(4)))'
+ // expected-warning@#i64_4{{implicit conversion turns floating-point number into integer: 'vector<double, 4>' (vector of 4 'double' values) to 'vector<long, 4>' (vector of 4 'long' values)}}
+ vector<long,4> i64_4 = d4; // #i64_4
+
+ // CHECK: VarDecl {{.*}} used i2_3 'vector<int, 2>':'int __attribute__((ext_vector_type(2)))' cinit
+ // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int, 2>':'int __attribute__((ext_vector_type(2)))' <IntegralCast>
+ // CHECK-NEXT: ImplicitCastExpr {{.*}} 'long __attribute__((ext_vector_type(2)))' <VectorTruncation>
+ // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<long, 4>':'long __attribute__((ext_vector_type(4)))' <LValueToRValue>
+ // CHECK-NEXT: DeclRefExpr {{.*}} 'vector<long, 4>':'long __attribute__((ext_vector_type(4)))' lvalue Var {{.*}} 'i64_4' 'vector<long, 4>':'long __attribute__((ext_vector_type(4)))'
+ // expected-warning@#i2_3{{implicit conversion loses integer precision: 'vector<long, 4>' (vector of 4 'long' values) to 'vector<int, 2>' (vector of 2 'int' values)}}
+ // expected-warning@#i2_3{{implicit conversion truncates vector: 'vector<long, 4>' (vector of 4 'long' values) to 'vector<int, 2>' (vector of 2 'int' values)}}
+ vector<int,2> i2_3 = i64_4; // #i2_3
+
+ //CHECK: VarDecl {{.*}} b2 'vector<bool, 2>':'bool __attribute__((ext_vector_type(2)))' cinit
+ //CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<bool, 2>':'bool __attribute__((ext_vector_type(2)))' <IntegralToBoolean>
+ //CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int, 2>':'int __attribute__((ext_vector_type(2)))' <LValueToRValue>
+ //CHECK-NEXT: DeclRefExpr {{.*}} 'vector<int, 2>':'int __attribute__((ext_vector_type(2)))' lvalue Var {{.*}} 'i2_3' 'vector<int, 2>':'int __attribute__((ext_vector_type(2)))'
+ vector<bool, 2> b2 = i2_3; // No warning for integer to bool conversion.
+
+ // CHECK: VarDecl {{.*}} b2_2 'vector<bool, 2>':'bool __attribute__((ext_vector_type(2)))' cinit
+ // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<bool, 2>':'bool __attribute__((ext_vector_type(2)))' <FloatingToBoolean>
+ // CHECK-NEXT: ImplicitCastExpr {{.*}} 'double __attribute__((ext_vector_type(2)))' <VectorTruncation>
+ // CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<double, 4>':'double __attribute__((ext_vector_type(4)))' <LValueToRValue>
+ // CHECK-NEXT: DeclRefExpr {{.*}} 'vector<double, 4>':'double __attribute__((ext_vector_type(4)))' lvalue Var {{.*}} 'd4' 'vector<double, 4>':'double __attribute__((ext_vector_type(4)))'
+ // expected-warning@#b2_2{{implicit conversion truncates vector: 'vector<double, 4>' (vector of 4 'double' values) to 'vector<bool, 2>' (vector of 2 'bool' values)}}
+ // expected-warning@#b2_2{{implicit conversion turns floating-point number into integer: 'vector<double, 4>' (vector of 4 'double' values) to 'vector<bool, 2>' (vector of 2 'bool' values)}}
+ vector<bool, 2> b2_2 = d4; // #b2_2
+}
+
+#ifndef NO_ERR
+
+void illegal() {
+ // vector extension is illegal
+ vector<float,3> f3 = 1.0;
+ vector<float,4> f4 = f3; // expected-error{{cannot initialize a variable of type 'vector<[...], 4>' with an lvalue of type 'vector<[...], 3>'}}
+}
+
+#endif
More information about the cfe-commits
mailing list