[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
https://github.com/zygoloid closed https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
DaMatrix wrote: @zygoloid can you commit this? I don't have write access to the repository. https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
https://github.com/zygoloid approved this pull request. Thanks, LGTM https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
https://github.com/DaMatrix updated https://github.com/llvm/llvm-project/pull/66894 >From 38647e8b00194a59a31eed92b04b229fe24802b6 Mon Sep 17 00:00:00 2001 From: DaPorkchop_ Date: Sun, 13 Aug 2023 22:39:12 +0200 Subject: [PATCH 1/2] [clang] Implement constexpr bit_cast for vectors --- .../include/clang/Basic/DiagnosticASTKinds.td | 3 + clang/lib/AST/ExprConstant.cpp| 269 -- clang/lib/CodeGen/CGExprConstant.cpp | 3 + clang/test/CodeGen/const-init.c | 9 +- .../constexpr-builtin-bit-cast-fp80.cpp | 48 .../SemaCXX/constexpr-builtin-bit-cast.cpp| 44 +++ 6 files changed, 278 insertions(+), 98 deletions(-) create mode 100644 clang/test/SemaCXX/constexpr-builtin-bit-cast-fp80.cpp diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td index b70cf1071d865da..85acce12dac7173 100644 --- a/clang/include/clang/Basic/DiagnosticASTKinds.td +++ b/clang/include/clang/Basic/DiagnosticASTKinds.td @@ -326,6 +326,9 @@ def note_constexpr_bit_cast_invalid_type : Note< "%select{type|member}1 is not allowed in a constant expression">; def note_constexpr_bit_cast_invalid_subtype : Note< "invalid type %0 is a %select{member|base}1 of %2">; +def note_constexpr_bit_cast_invalid_vector : Note< + "bit_cast involving type %0 is not allowed in a constant expression; " + "element size %1 * element count %2 is not a multiple of the byte size %3">; def note_constexpr_bit_cast_indet_dest : Note< "indeterminate value can only initialize an object of type 'unsigned char'" "%select{, 'char',|}1 or 'std::byte'; %0 is invalid">; diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 6b47b8a1256477d..adf73f0ec39f8a9 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -2732,53 +2732,6 @@ static bool truncateBitfieldValue(EvalInfo , const Expr *E, return true; } -static bool EvalAndBitcastToAPInt(EvalInfo , const Expr *E, - llvm::APInt ) { - APValue SVal; - if (!Evaluate(SVal, Info, E)) -return false; - if (SVal.isInt()) { -Res = SVal.getInt(); -return true; - } - if (SVal.isFloat()) { -Res = SVal.getFloat().bitcastToAPInt(); -return true; - } - if (SVal.isVector()) { -QualType VecTy = E->getType(); -unsigned VecSize = Info.Ctx.getTypeSize(VecTy); -QualType EltTy = VecTy->castAs()->getElementType(); -unsigned EltSize = Info.Ctx.getTypeSize(EltTy); -bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian(); -Res = llvm::APInt::getZero(VecSize); -for (unsigned i = 0; i < SVal.getVectorLength(); i++) { - APValue = SVal.getVectorElt(i); - llvm::APInt EltAsInt; - if (Elt.isInt()) { -EltAsInt = Elt.getInt(); - } else if (Elt.isFloat()) { -EltAsInt = Elt.getFloat().bitcastToAPInt(); - } else { -// Don't try to handle vectors of anything other than int or float -// (not sure if it's possible to hit this case). -Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); -return false; - } - unsigned BaseEltSize = EltAsInt.getBitWidth(); - if (BigEndian) -Res |= EltAsInt.zextOrTrunc(VecSize).rotr(i*EltSize+BaseEltSize); - else -Res |= EltAsInt.zextOrTrunc(VecSize).rotl(i*EltSize); -} -return true; - } - // Give up if the input isn't an int, float, or vector. For example, we - // reject "(v4i16)(intptr_t)". - Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); - return false; -} - /// Perform the given integer operation, which is known to need at most BitWidth /// bits, and check for overflow in the original type (if that type was not an /// unsigned type). @@ -7011,10 +6964,11 @@ class APValueToBufferConverter { return visitArray(Val, Ty, Offset); case APValue::Struct: return visitRecord(Val, Ty, Offset); +case APValue::Vector: + return visitVector(Val, Ty, Offset); case APValue::ComplexInt: case APValue::ComplexFloat: -case APValue::Vector: case APValue::FixedPoint: // FIXME: We should support these. @@ -7101,6 +7055,72 @@ class APValueToBufferConverter { return true; } + bool visitVector(const APValue , QualType Ty, CharUnits Offset) { +const VectorType *VTy = Ty->castAs(); +QualType EltTy = VTy->getElementType(); +unsigned NElts = VTy->getNumElements(); +unsigned EltSize = +VTy->isExtVectorBoolType() ? 1 : Info.Ctx.getTypeSize(EltTy); + +if ((NElts * EltSize) % Info.Ctx.getCharWidth() != 0) { + // The vector's size in bits is not a multiple of the target's byte size, + // so its layout is unspecified. For now, we'll simply treat these cases + // as unsupported (this should only be possible with OpenCL bool vectors + // whose element count isn't a multiple of the byte size). +
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
https://github.com/DaMatrix updated https://github.com/llvm/llvm-project/pull/66894 >From 72f63b695c9ebd9c7032c4b754ff7965c28fad5c Mon Sep 17 00:00:00 2001 From: DaPorkchop_ Date: Sun, 13 Aug 2023 22:39:12 +0200 Subject: [PATCH 1/2] [clang] Implement constexpr bit_cast for vectors --- .../include/clang/Basic/DiagnosticASTKinds.td | 3 + clang/lib/AST/ExprConstant.cpp| 269 -- clang/lib/CodeGen/CGExprConstant.cpp | 3 + clang/test/CodeGen/const-init.c | 9 +- .../constexpr-builtin-bit-cast-fp80.cpp | 48 .../SemaCXX/constexpr-builtin-bit-cast.cpp| 44 +++ 6 files changed, 278 insertions(+), 98 deletions(-) create mode 100644 clang/test/SemaCXX/constexpr-builtin-bit-cast-fp80.cpp diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td index d2656310e79c9b8..3f06e18783dd558 100644 --- a/clang/include/clang/Basic/DiagnosticASTKinds.td +++ b/clang/include/clang/Basic/DiagnosticASTKinds.td @@ -326,6 +326,9 @@ def note_constexpr_bit_cast_invalid_type : Note< "%select{type|member}1 is not allowed in a constant expression">; def note_constexpr_bit_cast_invalid_subtype : Note< "invalid type %0 is a %select{member|base}1 of %2">; +def note_constexpr_bit_cast_invalid_vector : Note< + "bit_cast involving type %0 is not allowed in a constant expression; " + "element size %1 * element count %2 is not a multiple of the byte size %3">; def note_constexpr_bit_cast_indet_dest : Note< "indeterminate value can only initialize an object of type 'unsigned char'" "%select{, 'char',|}1 or 'std::byte'; %0 is invalid">; diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 5a33e918db8e8c0..bb8222caec8c7de 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -2732,53 +2732,6 @@ static bool truncateBitfieldValue(EvalInfo , const Expr *E, return true; } -static bool EvalAndBitcastToAPInt(EvalInfo , const Expr *E, - llvm::APInt ) { - APValue SVal; - if (!Evaluate(SVal, Info, E)) -return false; - if (SVal.isInt()) { -Res = SVal.getInt(); -return true; - } - if (SVal.isFloat()) { -Res = SVal.getFloat().bitcastToAPInt(); -return true; - } - if (SVal.isVector()) { -QualType VecTy = E->getType(); -unsigned VecSize = Info.Ctx.getTypeSize(VecTy); -QualType EltTy = VecTy->castAs()->getElementType(); -unsigned EltSize = Info.Ctx.getTypeSize(EltTy); -bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian(); -Res = llvm::APInt::getZero(VecSize); -for (unsigned i = 0; i < SVal.getVectorLength(); i++) { - APValue = SVal.getVectorElt(i); - llvm::APInt EltAsInt; - if (Elt.isInt()) { -EltAsInt = Elt.getInt(); - } else if (Elt.isFloat()) { -EltAsInt = Elt.getFloat().bitcastToAPInt(); - } else { -// Don't try to handle vectors of anything other than int or float -// (not sure if it's possible to hit this case). -Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); -return false; - } - unsigned BaseEltSize = EltAsInt.getBitWidth(); - if (BigEndian) -Res |= EltAsInt.zextOrTrunc(VecSize).rotr(i*EltSize+BaseEltSize); - else -Res |= EltAsInt.zextOrTrunc(VecSize).rotl(i*EltSize); -} -return true; - } - // Give up if the input isn't an int, float, or vector. For example, we - // reject "(v4i16)(intptr_t)". - Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); - return false; -} - /// Perform the given integer operation, which is known to need at most BitWidth /// bits, and check for overflow in the original type (if that type was not an /// unsigned type). @@ -7011,10 +6964,11 @@ class APValueToBufferConverter { return visitArray(Val, Ty, Offset); case APValue::Struct: return visitRecord(Val, Ty, Offset); +case APValue::Vector: + return visitVector(Val, Ty, Offset); case APValue::ComplexInt: case APValue::ComplexFloat: -case APValue::Vector: case APValue::FixedPoint: // FIXME: We should support these. @@ -7101,6 +7055,72 @@ class APValueToBufferConverter { return true; } + bool visitVector(const APValue , QualType Ty, CharUnits Offset) { +const VectorType *VTy = Ty->castAs(); +QualType EltTy = VTy->getElementType(); +unsigned NElts = VTy->getNumElements(); +unsigned EltSize = +VTy->isExtVectorBoolType() ? 1 : Info.Ctx.getTypeSize(EltTy); + +if ((NElts * EltSize) % Info.Ctx.getCharWidth() != 0) { + // The vector's size in bits is not a multiple of the target's byte size, + // so its layout is unspecified. For now, we'll simply treat these cases + // as unsupported (this should only be possible with OpenCL bool vectors + // whose element count isn't a multiple of the byte size). +
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -140,11 +140,12 @@ void g28(void) { typedef short v12i16 __attribute((vector_size(24))); typedef long double v2f80 __attribute((vector_size(24))); // CHECK: @g28.a = internal global <1 x i64> - // CHECK: @g28.b = internal global <12 x i16> - // CHECK: @g28.c = internal global <2 x x86_fp80> , align 32 + // @g28.b = internal global <12 x i16> + // @g28.c = internal global <2 x x86_fp80> , align 32 static v1i64 a = (v1i64)10LL; - static v12i16 b = (v12i16)(v2f80){1,2}; - static v2f80 c = (v2f80)(v12i16){0,0,0,-32768,16383,0,0,0,0,-32768,16384,0}; + //FIXME: support constant bitcast between vectors of x86_fp80 + //static v12i16 b = (v12i16)(v2f80){1,2}; + //static v2f80 c = (v2f80)(v12i16){0,0,0,-32768,16383,0,0,0,0,-32768,16384,0}; zygoloid wrote: Perhaps you could add a C++ testcass with the variable declared `constexpr`. https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -140,11 +140,12 @@ void g28(void) { typedef short v12i16 __attribute((vector_size(24))); typedef long double v2f80 __attribute((vector_size(24))); // CHECK: @g28.a = internal global <1 x i64> - // CHECK: @g28.b = internal global <12 x i16> - // CHECK: @g28.c = internal global <2 x x86_fp80> , align 32 + // @g28.b = internal global <12 x i16> + // @g28.c = internal global <2 x x86_fp80> , align 32 static v1i64 a = (v1i64)10LL; - static v12i16 b = (v12i16)(v2f80){1,2}; - static v2f80 c = (v2f80)(v12i16){0,0,0,-32768,16383,0,0,0,0,-32768,16384,0}; + //FIXME: support constant bitcast between vectors of x86_fp80 + //static v12i16 b = (v12i16)(v2f80){1,2}; + //static v2f80 c = (v2f80)(v12i16){0,0,0,-32768,16383,0,0,0,0,-32768,16384,0}; DaMatrix wrote: So, on further investigation, it looks like the diagnostic isn't being emitted at all because the constant evaluation code is called with an `EvalInfo` which has diagnostics disabled, and is never called again. https://github.com/llvm/llvm-project/blob/72f63b695c9ebd9c7032c4b754ff7965c28fad5c/clang/lib/AST/Expr.cpp#L3486 https://github.com/llvm/llvm-project/blob/72f63b695c9ebd9c7032c4b754ff7965c28fad5c/clang/lib/AST/ExprConstant.cpp#L15483-L15485 And once it's been evaluted with no diagnostic, an `diag::err_init_element_not_constant` is emitted which triggers an error and so it never gets evaluated again with diagnostics enabled. https://github.com/llvm/llvm-project/blob/72f63b695c9ebd9c7032c4b754ff7965c28fad5c/clang/lib/Sema/SemaDecl.cpp#L12510-L12514 What should I do here? This feels like a weakness of the code in Sema; any changes I make here are going to break a bunch of tests which expect no diagnostics to be output in these cases. https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -140,11 +140,12 @@ void g28(void) { typedef short v12i16 __attribute((vector_size(24))); typedef long double v2f80 __attribute((vector_size(24))); // CHECK: @g28.a = internal global <1 x i64> - // CHECK: @g28.b = internal global <12 x i16> - // CHECK: @g28.c = internal global <2 x x86_fp80> , align 32 + // @g28.b = internal global <12 x i16> + // @g28.c = internal global <2 x x86_fp80> , align 32 static v1i64 a = (v1i64)10LL; - static v12i16 b = (v12i16)(v2f80){1,2}; - static v2f80 c = (v2f80)(v12i16){0,0,0,-32768,16383,0,0,0,0,-32768,16384,0}; + //FIXME: support constant bitcast between vectors of x86_fp80 + //static v12i16 b = (v12i16)(v2f80){1,2}; + //static v2f80 c = (v2f80)(v12i16){0,0,0,-32768,16383,0,0,0,0,-32768,16384,0}; DaMatrix wrote: Interestingly, uncommenting these lines doesn't cause any diagnostic messages to be generated, only an error stating `error: initializer element is not a compile-time constant`. I'll see if I can get the diagnostic to be output and change the messages as suggested. https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -140,11 +140,12 @@ void g28(void) { typedef short v12i16 __attribute((vector_size(24))); typedef long double v2f80 __attribute((vector_size(24))); // CHECK: @g28.a = internal global <1 x i64> - // CHECK: @g28.b = internal global <12 x i16> - // CHECK: @g28.c = internal global <2 x x86_fp80> , align 32 + // @g28.b = internal global <12 x i16> + // @g28.c = internal global <2 x x86_fp80> , align 32 static v1i64 a = (v1i64)10LL; - static v12i16 b = (v12i16)(v2f80){1,2}; - static v2f80 c = (v2f80)(v12i16){0,0,0,-32768,16383,0,0,0,0,-32768,16384,0}; + //FIXME: support constant bitcast between vectors of x86_fp80 + //static v12i16 b = (v12i16)(v2f80){1,2}; + //static v2f80 c = (v2f80)(v12i16){0,0,0,-32768,16383,0,0,0,0,-32768,16384,0}; zygoloid wrote: Please add some test coverage that we properly diagnose this situation. I think we'll produce a diagnostic mentioning `bit_cast`, which is probably not what we want here. Maybe the simplest thing to do to fix that would be to replace `bit_cast` with `bit cast` in all the diagnostics. That seems at least as good for the `std::bit_cast` / `__builtin_bit_cast` case, and better for the vector cast case. https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
https://github.com/zygoloid commented: Thanks, this looks good to me other than a small test coverage (see comment) / diagnostic wording issue. (For future reference, please don't force-push to PR branches; that makes it much harder for your reviewer to see what's changed since their last review and can cause github to lose track of comments. See https://llvm.org/docs/GitHub.html#updating-pull-requests) https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
https://github.com/zygoloid edited https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
https://github.com/DaMatrix updated https://github.com/llvm/llvm-project/pull/66894 >From 72f63b695c9ebd9c7032c4b754ff7965c28fad5c Mon Sep 17 00:00:00 2001 From: DaPorkchop_ Date: Sun, 13 Aug 2023 22:39:12 +0200 Subject: [PATCH] [clang] Implement constexpr bit_cast for vectors --- .../include/clang/Basic/DiagnosticASTKinds.td | 3 + clang/lib/AST/ExprConstant.cpp| 269 -- clang/lib/CodeGen/CGExprConstant.cpp | 3 + clang/test/CodeGen/const-init.c | 9 +- .../constexpr-builtin-bit-cast-fp80.cpp | 48 .../SemaCXX/constexpr-builtin-bit-cast.cpp| 44 +++ 6 files changed, 278 insertions(+), 98 deletions(-) create mode 100644 clang/test/SemaCXX/constexpr-builtin-bit-cast-fp80.cpp diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td index d2656310e79c9b8..3f06e18783dd558 100644 --- a/clang/include/clang/Basic/DiagnosticASTKinds.td +++ b/clang/include/clang/Basic/DiagnosticASTKinds.td @@ -326,6 +326,9 @@ def note_constexpr_bit_cast_invalid_type : Note< "%select{type|member}1 is not allowed in a constant expression">; def note_constexpr_bit_cast_invalid_subtype : Note< "invalid type %0 is a %select{member|base}1 of %2">; +def note_constexpr_bit_cast_invalid_vector : Note< + "bit_cast involving type %0 is not allowed in a constant expression; " + "element size %1 * element count %2 is not a multiple of the byte size %3">; def note_constexpr_bit_cast_indet_dest : Note< "indeterminate value can only initialize an object of type 'unsigned char'" "%select{, 'char',|}1 or 'std::byte'; %0 is invalid">; diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 5a33e918db8e8c0..bb8222caec8c7de 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -2732,53 +2732,6 @@ static bool truncateBitfieldValue(EvalInfo , const Expr *E, return true; } -static bool EvalAndBitcastToAPInt(EvalInfo , const Expr *E, - llvm::APInt ) { - APValue SVal; - if (!Evaluate(SVal, Info, E)) -return false; - if (SVal.isInt()) { -Res = SVal.getInt(); -return true; - } - if (SVal.isFloat()) { -Res = SVal.getFloat().bitcastToAPInt(); -return true; - } - if (SVal.isVector()) { -QualType VecTy = E->getType(); -unsigned VecSize = Info.Ctx.getTypeSize(VecTy); -QualType EltTy = VecTy->castAs()->getElementType(); -unsigned EltSize = Info.Ctx.getTypeSize(EltTy); -bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian(); -Res = llvm::APInt::getZero(VecSize); -for (unsigned i = 0; i < SVal.getVectorLength(); i++) { - APValue = SVal.getVectorElt(i); - llvm::APInt EltAsInt; - if (Elt.isInt()) { -EltAsInt = Elt.getInt(); - } else if (Elt.isFloat()) { -EltAsInt = Elt.getFloat().bitcastToAPInt(); - } else { -// Don't try to handle vectors of anything other than int or float -// (not sure if it's possible to hit this case). -Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); -return false; - } - unsigned BaseEltSize = EltAsInt.getBitWidth(); - if (BigEndian) -Res |= EltAsInt.zextOrTrunc(VecSize).rotr(i*EltSize+BaseEltSize); - else -Res |= EltAsInt.zextOrTrunc(VecSize).rotl(i*EltSize); -} -return true; - } - // Give up if the input isn't an int, float, or vector. For example, we - // reject "(v4i16)(intptr_t)". - Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); - return false; -} - /// Perform the given integer operation, which is known to need at most BitWidth /// bits, and check for overflow in the original type (if that type was not an /// unsigned type). @@ -7011,10 +6964,11 @@ class APValueToBufferConverter { return visitArray(Val, Ty, Offset); case APValue::Struct: return visitRecord(Val, Ty, Offset); +case APValue::Vector: + return visitVector(Val, Ty, Offset); case APValue::ComplexInt: case APValue::ComplexFloat: -case APValue::Vector: case APValue::FixedPoint: // FIXME: We should support these. @@ -7101,6 +7055,72 @@ class APValueToBufferConverter { return true; } + bool visitVector(const APValue , QualType Ty, CharUnits Offset) { +const VectorType *VTy = Ty->castAs(); +QualType EltTy = VTy->getElementType(); +unsigned NElts = VTy->getNumElements(); +unsigned EltSize = +VTy->isExtVectorBoolType() ? 1 : Info.Ctx.getTypeSize(EltTy); + +if ((NElts * EltSize) % Info.Ctx.getCharWidth() != 0) { + // The vector's size in bits is not a multiple of the target's byte size, + // so its layout is unspecified. For now, we'll simply treat these cases + // as unsupported (this should only be possible with OpenCL bool vectors + // whose element count isn't a multiple of the byte size). +
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -7098,6 +7052,69 @@ class APValueToBufferConverter { return true; } + bool visitVector(const APValue , QualType Ty, CharUnits Offset) { +const VectorType *VTy = Ty->castAs(); +QualType EltTy = VTy->getElementType(); +unsigned NElts = VTy->getNumElements(); +unsigned EltSize = +VTy->isExtVectorBoolType() ? 1 : Info.Ctx.getTypeSize(EltTy); + +if ((NElts * EltSize) % Info.Ctx.getCharWidth() != 0) { + // The vector's size in bits is not a multiple of the target's byte size, + // so its layout is unspecified. For now, we'll simply treat these cases + // as unsupported (this should only be possible with OpenCL bool vectors + // whose element count isn't a multiple of the byte size). + Info.FFDiag(BCE->getBeginLoc(), + diag::note_constexpr_bit_cast_invalid_vector) + << Ty.getCanonicalType() << EltSize << NElts + << Info.Ctx.getCharWidth(); + return false; +} + +if (VTy->isExtVectorBoolType()) { + // Special handling for OpenCL bool vectors: + // Since these vectors are stored as packed bits, but we can't write + // individual bits to the BitCastBuffer, we'll buffer all of the elements + // together into an appropriately sized APInt and write them all out at + // once. Because we don't accept vectors where NElts * EltSize isn't a + // multiple of the char size, there will be no padding space, so we don't + // have to worry about writing data which should have been left + // uninitialized. + bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian(); + + llvm::APInt Res = llvm::APInt::getZero(NElts); + for (unsigned I = 0; I < NElts; ++I) { +const llvm::APSInt = Val.getVectorElt(I).getInt(); +assert(EltAsInt.isUnsigned() && EltAsInt.getBitWidth() == 1 && + "bool vector element must be 1-bit unsigned integer!"); + +Res.insertBits(EltAsInt, BigEndian ? (NElts - I - 1) : I); + } + + SmallVector Bytes(NElts / 8); + llvm::StoreIntToMemory(Res, &*Bytes.begin(), NElts / 8); + Buffer.writeObject(Offset, Bytes); +} else { + // Iterate over each of the elements and write them out to the buffer at + // the appropriate offset. + CharUnits EltSizeChars = Info.Ctx.getTypeSizeInChars(EltTy); + + // Special handling for vectors of x86_fp80: use a size of exactly 80 bits + // because LLVM stores vector elements without padding + if (EltTy->isRealFloatingType() && + (EltTy) == + ::x87DoubleExtended()) +EltSizeChars = Info.Ctx.toCharUnitsFromBits(80); zygoloid wrote: Oof. Yeah, that sounds like a good approach to me. https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -7098,6 +7052,69 @@ class APValueToBufferConverter { return true; } + bool visitVector(const APValue , QualType Ty, CharUnits Offset) { +const VectorType *VTy = Ty->castAs(); +QualType EltTy = VTy->getElementType(); +unsigned NElts = VTy->getNumElements(); +unsigned EltSize = +VTy->isExtVectorBoolType() ? 1 : Info.Ctx.getTypeSize(EltTy); + +if ((NElts * EltSize) % Info.Ctx.getCharWidth() != 0) { + // The vector's size in bits is not a multiple of the target's byte size, + // so its layout is unspecified. For now, we'll simply treat these cases + // as unsupported (this should only be possible with OpenCL bool vectors + // whose element count isn't a multiple of the byte size). + Info.FFDiag(BCE->getBeginLoc(), + diag::note_constexpr_bit_cast_invalid_vector) + << Ty.getCanonicalType() << EltSize << NElts + << Info.Ctx.getCharWidth(); + return false; +} + +if (VTy->isExtVectorBoolType()) { + // Special handling for OpenCL bool vectors: + // Since these vectors are stored as packed bits, but we can't write + // individual bits to the BitCastBuffer, we'll buffer all of the elements + // together into an appropriately sized APInt and write them all out at + // once. Because we don't accept vectors where NElts * EltSize isn't a + // multiple of the char size, there will be no padding space, so we don't + // have to worry about writing data which should have been left + // uninitialized. + bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian(); + + llvm::APInt Res = llvm::APInt::getZero(NElts); + for (unsigned I = 0; I < NElts; ++I) { +const llvm::APSInt = Val.getVectorElt(I).getInt(); +assert(EltAsInt.isUnsigned() && EltAsInt.getBitWidth() == 1 && + "bool vector element must be 1-bit unsigned integer!"); + +Res.insertBits(EltAsInt, BigEndian ? (NElts - I - 1) : I); + } + + SmallVector Bytes(NElts / 8); + llvm::StoreIntToMemory(Res, &*Bytes.begin(), NElts / 8); + Buffer.writeObject(Offset, Bytes); +} else { + // Iterate over each of the elements and write them out to the buffer at + // the appropriate offset. + CharUnits EltSizeChars = Info.Ctx.getTypeSizeInChars(EltTy); + + // Special handling for vectors of x86_fp80: use a size of exactly 80 bits + // because LLVM stores vector elements without padding + if (EltTy->isRealFloatingType() && + (EltTy) == + ::x87DoubleExtended()) +EltSizeChars = Info.Ctx.toCharUnitsFromBits(80); DaMatrix wrote: @nikic gave [an example](https://godbolt.org/z/rcev7Ps1a) in #68566 which shows that sometimes it doesn't, and pointed out that LLVM itself documents that vector types are represented without padding. Actually, [this example I just came up with](https://godbolt.org/z/hsdxhPrE8) shows how inconsistent it is, with LLVM storing vector elements at different offsets depending on how many elements are being written to and the current optimization level. Honestly, at this point I have no idea what's supposed to be correct, it seems like every time I think I've figured out which the "correct" format is something else pops up, and I don't really see much point in spending any more time trying to fix this code which only breaks on a vector format which nobody will ever actually use in practice. Can I just make it fail constant evaluation when the element type is `x86_fp80` and leave it at that? https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
https://github.com/zygoloid dismissed https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -138,13 +138,14 @@ void g27(void) { // PR8073 void g28(void) { typedef long long v1i64 __attribute((vector_size(8))); typedef short v12i16 __attribute((vector_size(24))); + typedef unsigned char v24u8 __attribute((vector_size(24))); typedef long double v2f80 __attribute((vector_size(24))); // CHECK: @g28.a = internal global <1 x i64> - // CHECK: @g28.b = internal global <12 x i16> + // CHECK: @g28.b = internal global <24 x i8> , align 32 zygoloid wrote: I think the correct output here would be: ```suggestion // CHECK: @g28.b = internal global <24 x i8> , align 32 ``` https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
https://github.com/zygoloid commented: Looks good, other than the handling of `x86_fp80`, which doesn't seem to match Clang's current runtime behavior. https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -138,13 +138,14 @@ void g27(void) { // PR8073 void g28(void) { typedef long long v1i64 __attribute((vector_size(8))); typedef short v12i16 __attribute((vector_size(24))); + typedef unsigned char v24u8 __attribute((vector_size(24))); typedef long double v2f80 __attribute((vector_size(24))); // CHECK: @g28.a = internal global <1 x i64> - // CHECK: @g28.b = internal global <12 x i16> + // CHECK: @g28.b = internal global <24 x i8> , align 32 // CHECK: @g28.c = internal global <2 x x86_fp80> , align 32 static v1i64 a = (v1i64)10LL; - static v12i16 b = (v12i16)(v2f80){1,2}; - static v2f80 c = (v2f80)(v12i16){0,0,0,-32768,16383,0,0,0,0,-32768,16384,0}; + static v24u8 b = (v24u8)(v2f80){1,2}; + static v2f80 c = (v2f80)(v12i16){0,0,0,-32768,16383,0,0,0,-32768,16384,0,0}; zygoloid wrote: I think `c` here was correct before. https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -7307,6 +7324,74 @@ class BufferToAPValueConverter { return ArrayValue; } + std::optional visit(const VectorType *VTy, CharUnits Offset) { +QualType EltTy = VTy->getElementType(); +unsigned NElts = VTy->getNumElements(); +unsigned EltSize = +VTy->isExtVectorBoolType() ? 1 : Info.Ctx.getTypeSize(EltTy); + +if ((NElts * EltSize) % Info.Ctx.getCharWidth() != 0) { + // The vector's size in bits is not a multiple of the target's byte size, + // so its layout is unspecified. For now, we'll simply treat these cases + // as unsupported (this should only be possible with OpenCL bool vectors + // whose element count isn't a multiple of the byte size). + Info.FFDiag(BCE->getBeginLoc(), + diag::note_constexpr_bit_cast_invalid_vector) + << QualType(VTy, 0) << EltSize << NElts << Info.Ctx.getCharWidth(); + return std::nullopt; +} + +SmallVector Elts; +Elts.reserve(NElts); +if (VTy->isExtVectorBoolType()) { + // Special handling for OpenCL bool vectors: + // Since these vectors are stored as packed bits, but we can't read + // individual bits from the BitCastBuffer, we'll buffer all of the + // elements together into an appropriately sized APInt and write them all + // out at once. Because we don't accept vectors where NElts * EltSize + // isn't a multiple of the char size, there will be no padding space, so + // we don't have to worry about reading any padding data which didn't + // actually need to be accessed. + bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian(); + + SmallVector Bytes; + Bytes.reserve(NElts / 8); + if (!Buffer.readObject(Offset, CharUnits::fromQuantity(NElts / 8), Bytes)) +return std::nullopt; + + APSInt SValInt(NElts, true); + llvm::LoadIntFromMemory(SValInt, &*Bytes.begin(), Bytes.size()); + + for (unsigned I = 0; I < NElts; ++I) { +llvm::APInt Elt = +SValInt.extractBits(1, (BigEndian ? NElts - I - 1 : I) * EltSize); +Elts.emplace_back( +APSInt(std::move(Elt), !EltTy->isSignedIntegerType())); + } +} else { + // Iterate over each of the elements and read them from the buffer at + // the appropriate offset. + CharUnits EltSizeChars = Info.Ctx.getTypeSizeInChars(EltTy); + + // Special handling for vectors of x86_fp80: use a size of exactly 80 bits + // because LLVM stores vector elements without padding + if (EltTy->isRealFloatingType() && + (EltTy) == + ::x87DoubleExtended()) +EltSizeChars = Info.Ctx.toCharUnitsFromBits(80); zygoloid wrote: (Same comment as above.) https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -7098,6 +7052,69 @@ class APValueToBufferConverter { return true; } + bool visitVector(const APValue , QualType Ty, CharUnits Offset) { +const VectorType *VTy = Ty->castAs(); +QualType EltTy = VTy->getElementType(); +unsigned NElts = VTy->getNumElements(); +unsigned EltSize = +VTy->isExtVectorBoolType() ? 1 : Info.Ctx.getTypeSize(EltTy); + +if ((NElts * EltSize) % Info.Ctx.getCharWidth() != 0) { + // The vector's size in bits is not a multiple of the target's byte size, + // so its layout is unspecified. For now, we'll simply treat these cases + // as unsupported (this should only be possible with OpenCL bool vectors + // whose element count isn't a multiple of the byte size). + Info.FFDiag(BCE->getBeginLoc(), + diag::note_constexpr_bit_cast_invalid_vector) + << Ty.getCanonicalType() << EltSize << NElts + << Info.Ctx.getCharWidth(); + return false; +} + +if (VTy->isExtVectorBoolType()) { + // Special handling for OpenCL bool vectors: + // Since these vectors are stored as packed bits, but we can't write + // individual bits to the BitCastBuffer, we'll buffer all of the elements + // together into an appropriately sized APInt and write them all out at + // once. Because we don't accept vectors where NElts * EltSize isn't a + // multiple of the char size, there will be no padding space, so we don't + // have to worry about writing data which should have been left + // uninitialized. + bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian(); + + llvm::APInt Res = llvm::APInt::getZero(NElts); + for (unsigned I = 0; I < NElts; ++I) { +const llvm::APSInt = Val.getVectorElt(I).getInt(); +assert(EltAsInt.isUnsigned() && EltAsInt.getBitWidth() == 1 && + "bool vector element must be 1-bit unsigned integer!"); + +Res.insertBits(EltAsInt, BigEndian ? (NElts - I - 1) : I); + } + + SmallVector Bytes(NElts / 8); + llvm::StoreIntToMemory(Res, &*Bytes.begin(), NElts / 8); + Buffer.writeObject(Offset, Bytes); +} else { + // Iterate over each of the elements and write them out to the buffer at + // the appropriate offset. + CharUnits EltSizeChars = Info.Ctx.getTypeSizeInChars(EltTy); + + // Special handling for vectors of x86_fp80: use a size of exactly 80 bits + // because LLVM stores vector elements without padding + if (EltTy->isRealFloatingType() && + (EltTy) == + ::x87DoubleExtended()) +EltSizeChars = Info.Ctx.toCharUnitsFromBits(80); zygoloid wrote: This doesn't seem correct: in [my investigation](https://godbolt.org/z/co8rxd5fe) it looks like LLVM stores vectors of `x86_fp80` with a stride of 12 (for x86) or 16 (for x86_64) bytes between elements -- the same layout as an array of `x86_fp80`, with 10 bytes of data followed by either 2 or 6 bytes of padding. Would it be correct to simply remove this special case and the matching one below? https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
https://github.com/zygoloid edited https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
https://github.com/DaMatrix updated https://github.com/llvm/llvm-project/pull/66894 >From 95c018c67b5ca10e86065fc3d0cb60f507626f34 Mon Sep 17 00:00:00 2001 From: DaPorkchop_ Date: Sun, 13 Aug 2023 22:39:12 +0200 Subject: [PATCH] [clang] Implement constexpr bit_cast for vectors --- .../include/clang/Basic/DiagnosticASTKinds.td | 3 + clang/lib/AST/ExprConstant.cpp| 263 +++--- clang/lib/CodeGen/CGExprConstant.cpp | 3 + clang/test/CodeGen/const-init.c | 7 +- .../constexpr-builtin-bit-cast-fp80.cpp | 38 +++ .../SemaCXX/constexpr-builtin-bit-cast.cpp| 44 +++ 6 files changed, 261 insertions(+), 97 deletions(-) create mode 100644 clang/test/SemaCXX/constexpr-builtin-bit-cast-fp80.cpp diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td index d2656310e79c9b8..3f06e18783dd558 100644 --- a/clang/include/clang/Basic/DiagnosticASTKinds.td +++ b/clang/include/clang/Basic/DiagnosticASTKinds.td @@ -326,6 +326,9 @@ def note_constexpr_bit_cast_invalid_type : Note< "%select{type|member}1 is not allowed in a constant expression">; def note_constexpr_bit_cast_invalid_subtype : Note< "invalid type %0 is a %select{member|base}1 of %2">; +def note_constexpr_bit_cast_invalid_vector : Note< + "bit_cast involving type %0 is not allowed in a constant expression; " + "element size %1 * element count %2 is not a multiple of the byte size %3">; def note_constexpr_bit_cast_indet_dest : Note< "indeterminate value can only initialize an object of type 'unsigned char'" "%select{, 'char',|}1 or 'std::byte'; %0 is invalid">; diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index a142ea7c47a4730..7f52916b8a5809c 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -2732,53 +2732,6 @@ static bool truncateBitfieldValue(EvalInfo , const Expr *E, return true; } -static bool EvalAndBitcastToAPInt(EvalInfo , const Expr *E, - llvm::APInt ) { - APValue SVal; - if (!Evaluate(SVal, Info, E)) -return false; - if (SVal.isInt()) { -Res = SVal.getInt(); -return true; - } - if (SVal.isFloat()) { -Res = SVal.getFloat().bitcastToAPInt(); -return true; - } - if (SVal.isVector()) { -QualType VecTy = E->getType(); -unsigned VecSize = Info.Ctx.getTypeSize(VecTy); -QualType EltTy = VecTy->castAs()->getElementType(); -unsigned EltSize = Info.Ctx.getTypeSize(EltTy); -bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian(); -Res = llvm::APInt::getZero(VecSize); -for (unsigned i = 0; i < SVal.getVectorLength(); i++) { - APValue = SVal.getVectorElt(i); - llvm::APInt EltAsInt; - if (Elt.isInt()) { -EltAsInt = Elt.getInt(); - } else if (Elt.isFloat()) { -EltAsInt = Elt.getFloat().bitcastToAPInt(); - } else { -// Don't try to handle vectors of anything other than int or float -// (not sure if it's possible to hit this case). -Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); -return false; - } - unsigned BaseEltSize = EltAsInt.getBitWidth(); - if (BigEndian) -Res |= EltAsInt.zextOrTrunc(VecSize).rotr(i*EltSize+BaseEltSize); - else -Res |= EltAsInt.zextOrTrunc(VecSize).rotl(i*EltSize); -} -return true; - } - // Give up if the input isn't an int, float, or vector. For example, we - // reject "(v4i16)(intptr_t)". - Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); - return false; -} - /// Perform the given integer operation, which is known to need at most BitWidth /// bits, and check for overflow in the original type (if that type was not an /// unsigned type). @@ -7008,10 +6961,11 @@ class APValueToBufferConverter { return visitArray(Val, Ty, Offset); case APValue::Struct: return visitRecord(Val, Ty, Offset); +case APValue::Vector: + return visitVector(Val, Ty, Offset); case APValue::ComplexInt: case APValue::ComplexFloat: -case APValue::Vector: case APValue::FixedPoint: // FIXME: We should support these. @@ -7098,6 +7052,69 @@ class APValueToBufferConverter { return true; } + bool visitVector(const APValue , QualType Ty, CharUnits Offset) { +const VectorType *VTy = Ty->castAs(); +QualType EltTy = VTy->getElementType(); +unsigned NElts = VTy->getNumElements(); +unsigned EltSize = +VTy->isExtVectorBoolType() ? 1 : Info.Ctx.getTypeSize(EltTy); + +if ((NElts * EltSize) % Info.Ctx.getCharWidth() != 0) { + // The vector's size in bits is not a multiple of the target's byte size, + // so its layout is unspecified. For now, we'll simply treat these cases + // as unsupported (this should only be possible with OpenCL bool vectors + // whose element count isn't a multiple of the byte size). +
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
https://github.com/DaMatrix updated https://github.com/llvm/llvm-project/pull/66894 >From f05f52ed4e74cf857bf07aef5dbd5d0861591a14 Mon Sep 17 00:00:00 2001 From: DaPorkchop_ Date: Sun, 13 Aug 2023 22:39:12 +0200 Subject: [PATCH] [clang] Implement constexpr bit_cast for vectors --- .../include/clang/Basic/DiagnosticASTKinds.td | 3 + clang/lib/AST/ExprConstant.cpp| 247 +++--- .../SemaCXX/constexpr-builtin-bit-cast.cpp| 61 + 3 files changed, 217 insertions(+), 94 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td index d2656310e79c9b8..3f06e18783dd558 100644 --- a/clang/include/clang/Basic/DiagnosticASTKinds.td +++ b/clang/include/clang/Basic/DiagnosticASTKinds.td @@ -326,6 +326,9 @@ def note_constexpr_bit_cast_invalid_type : Note< "%select{type|member}1 is not allowed in a constant expression">; def note_constexpr_bit_cast_invalid_subtype : Note< "invalid type %0 is a %select{member|base}1 of %2">; +def note_constexpr_bit_cast_invalid_vector : Note< + "bit_cast involving type %0 is not allowed in a constant expression; " + "element size %1 * element count %2 is not a multiple of the byte size %3">; def note_constexpr_bit_cast_indet_dest : Note< "indeterminate value can only initialize an object of type 'unsigned char'" "%select{, 'char',|}1 or 'std::byte'; %0 is invalid">; diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index a142ea7c47a4730..ad4d1dd12edb2e8 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -2732,53 +2732,6 @@ static bool truncateBitfieldValue(EvalInfo , const Expr *E, return true; } -static bool EvalAndBitcastToAPInt(EvalInfo , const Expr *E, - llvm::APInt ) { - APValue SVal; - if (!Evaluate(SVal, Info, E)) -return false; - if (SVal.isInt()) { -Res = SVal.getInt(); -return true; - } - if (SVal.isFloat()) { -Res = SVal.getFloat().bitcastToAPInt(); -return true; - } - if (SVal.isVector()) { -QualType VecTy = E->getType(); -unsigned VecSize = Info.Ctx.getTypeSize(VecTy); -QualType EltTy = VecTy->castAs()->getElementType(); -unsigned EltSize = Info.Ctx.getTypeSize(EltTy); -bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian(); -Res = llvm::APInt::getZero(VecSize); -for (unsigned i = 0; i < SVal.getVectorLength(); i++) { - APValue = SVal.getVectorElt(i); - llvm::APInt EltAsInt; - if (Elt.isInt()) { -EltAsInt = Elt.getInt(); - } else if (Elt.isFloat()) { -EltAsInt = Elt.getFloat().bitcastToAPInt(); - } else { -// Don't try to handle vectors of anything other than int or float -// (not sure if it's possible to hit this case). -Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); -return false; - } - unsigned BaseEltSize = EltAsInt.getBitWidth(); - if (BigEndian) -Res |= EltAsInt.zextOrTrunc(VecSize).rotr(i*EltSize+BaseEltSize); - else -Res |= EltAsInt.zextOrTrunc(VecSize).rotl(i*EltSize); -} -return true; - } - // Give up if the input isn't an int, float, or vector. For example, we - // reject "(v4i16)(intptr_t)". - Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); - return false; -} - /// Perform the given integer operation, which is known to need at most BitWidth /// bits, and check for overflow in the original type (if that type was not an /// unsigned type). @@ -7008,10 +6961,11 @@ class APValueToBufferConverter { return visitArray(Val, Ty, Offset); case APValue::Struct: return visitRecord(Val, Ty, Offset); +case APValue::Vector: + return visitVector(Val, Ty, Offset); case APValue::ComplexInt: case APValue::ComplexFloat: -case APValue::Vector: case APValue::FixedPoint: // FIXME: We should support these. @@ -7098,6 +7052,61 @@ class APValueToBufferConverter { return true; } + bool visitVector(const APValue , QualType Ty, CharUnits Offset) { +const VectorType *VTy = Ty->castAs(); +QualType EltTy = VTy->getElementType(); +unsigned NElts = VTy->getNumElements(); +unsigned EltSize = +VTy->isExtVectorBoolType() ? 1 : Info.Ctx.getTypeSize(EltTy); + +if ((NElts * EltSize) % Info.Ctx.getCharWidth() != 0) { + // The vector's size in bits is not a multiple of the target's byte size, + // so its layout is unspecified. For now, we'll simply treat these cases + // as unsupported (this should only be possible with OpenCL bool vectors + // whose element count isn't a multiple of the byte size). + Info.FFDiag(BCE->getBeginLoc(), + diag::note_constexpr_bit_cast_invalid_vector) + << Ty.getCanonicalType() << EltSize << NElts + << Info.Ctx.getCharWidth(); + return false; +} + +if (VTy->isExtVectorBoolType()) { +
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -7441,6 +7500,28 @@ static bool handleLValueToRValueBitCast(EvalInfo , APValue , return true; } +static bool handleLValueToRValueBitCast(EvalInfo , APValue , +APValue , +const CastExpr *BCE) { + assert(CHAR_BIT == 8 && Info.Ctx.getTargetInfo().getCharWidth() == 8 && + "no host or target supports non 8-bit chars"); + assert(SourceValue.isLValue() && + "LValueToRValueBitcast requires an lvalue operand!"); + + if (!checkBitCastConstexprEligibility(, Info.Ctx, BCE)) +return false; DaMatrix wrote: I did it this way so that `handleLValueToRValueBitCast` would be able to break out early to avoid copying the source LValue into an RValue if the expression wasn't eligible, but now that you mention it it doesn't make much sense to do an expensive check twice in order to optimize the exceptional path. Will remove this from `handleLValueToRValueBitCast`. https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -10517,41 +10598,19 @@ bool VectorExprEvaluator::VisitCastExpr(const CastExpr *E) { return Success(Elts, E); } case CK_BitCast: { -// Evaluate the operand into an APInt we can extract from. -llvm::APInt SValInt; -if (!EvalAndBitcastToAPInt(Info, SE, SValInt)) +APValue SVal; +if (!Evaluate(SVal, Info, SE)) return false; -// Extract the elements -QualType EltTy = VTy->getElementType(); -unsigned EltSize = Info.Ctx.getTypeSize(EltTy); -bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian(); -SmallVector Elts; -if (EltTy->isRealFloatingType()) { - const llvm::fltSemantics = Info.Ctx.getFloatTypeSemantics(EltTy); - unsigned FloatEltSize = EltSize; - if ( == ::x87DoubleExtended()) -FloatEltSize = 80; - for (unsigned i = 0; i < NElts; i++) { -llvm::APInt Elt; -if (BigEndian) - Elt = SValInt.rotl(i * EltSize + FloatEltSize).trunc(FloatEltSize); -else - Elt = SValInt.rotr(i * EltSize).trunc(FloatEltSize); -Elts.push_back(APValue(APFloat(Sem, Elt))); - } -} else if (EltTy->isIntegerType()) { - for (unsigned i = 0; i < NElts; i++) { -llvm::APInt Elt; -if (BigEndian) - Elt = SValInt.rotl(i*EltSize+EltSize).zextOrTrunc(EltSize); -else - Elt = SValInt.rotr(i*EltSize).zextOrTrunc(EltSize); -Elts.push_back(APValue(APSInt(Elt, !EltTy->isSignedIntegerType(; - } -} else { + +if (!SVal.isInt() && !SVal.isFloat() && !SVal.isVector()) + // Give up if the input isn't an int, float, or vector. For example, we + // reject "(v4i16)(intptr_t)". DaMatrix wrote: Well, `handleRValueToRValueBitCast` allows structs and arrays... I'll just improve the diagnostic message produced here instead. https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -10517,41 +10598,19 @@ bool VectorExprEvaluator::VisitCastExpr(const CastExpr *E) { return Success(Elts, E); } case CK_BitCast: { -// Evaluate the operand into an APInt we can extract from. -llvm::APInt SValInt; -if (!EvalAndBitcastToAPInt(Info, SE, SValInt)) +APValue SVal; +if (!Evaluate(SVal, Info, SE)) return false; -// Extract the elements -QualType EltTy = VTy->getElementType(); -unsigned EltSize = Info.Ctx.getTypeSize(EltTy); -bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian(); -SmallVector Elts; -if (EltTy->isRealFloatingType()) { - const llvm::fltSemantics = Info.Ctx.getFloatTypeSemantics(EltTy); - unsigned FloatEltSize = EltSize; - if ( == ::x87DoubleExtended()) -FloatEltSize = 80; - for (unsigned i = 0; i < NElts; i++) { -llvm::APInt Elt; -if (BigEndian) - Elt = SValInt.rotl(i * EltSize + FloatEltSize).trunc(FloatEltSize); -else - Elt = SValInt.rotr(i * EltSize).trunc(FloatEltSize); -Elts.push_back(APValue(APFloat(Sem, Elt))); - } -} else if (EltTy->isIntegerType()) { - for (unsigned i = 0; i < NElts; i++) { -llvm::APInt Elt; -if (BigEndian) - Elt = SValInt.rotl(i*EltSize+EltSize).zextOrTrunc(EltSize); -else - Elt = SValInt.rotr(i*EltSize).zextOrTrunc(EltSize); -Elts.push_back(APValue(APSInt(Elt, !EltTy->isSignedIntegerType(; - } -} else { + +if (!SVal.isInt() && !SVal.isFloat() && !SVal.isVector()) + // Give up if the input isn't an int, float, or vector. For example, we + // reject "(v4i16)(intptr_t)". zygoloid wrote: Do we need this check? I think `handleRValueToRValueBitCast` rejects the same cases, and produces a useful diagnostic when doing so. https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
https://github.com/zygoloid approved this pull request. Thanks, looks good. Just a couple of minor suggestions. https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -7441,6 +7500,28 @@ static bool handleLValueToRValueBitCast(EvalInfo , APValue , return true; } +static bool handleLValueToRValueBitCast(EvalInfo , APValue , +APValue , +const CastExpr *BCE) { + assert(CHAR_BIT == 8 && Info.Ctx.getTargetInfo().getCharWidth() == 8 && + "no host or target supports non 8-bit chars"); + assert(SourceValue.isLValue() && + "LValueToRValueBitcast requires an lvalue operand!"); + + if (!checkBitCastConstexprEligibility(, Info.Ctx, BCE)) +return false; zygoloid wrote: Can we avoid doing this twice (once here and again in `handleRValueToRValueBitCast`? It does a recursive walk of the source and destination types so isn't all that cheap. https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
https://github.com/zygoloid edited https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -7304,6 +7382,21 @@ class BufferToAPValueConverter { return ArrayValue; } + std::optional visit(const VectorType *Ty, CharUnits Offset) { +SmallVector Bytes; +if (!Buffer.readObject(Offset, Info.Ctx.getTypeSizeInChars(Ty), Bytes)) + return std::nullopt; zygoloid wrote: Hm, maybe we need to avoid generating an LLVM `bit_cast` here and go through memory instead? I think it's best to handle that in a separate PR. https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
https://github.com/DaMatrix updated https://github.com/llvm/llvm-project/pull/66894 >From f24c57fdd4e9cd3208c661d2f716c0251cff1c5e Mon Sep 17 00:00:00 2001 From: DaPorkchop_ Date: Sun, 13 Aug 2023 22:39:12 +0200 Subject: [PATCH] [clang] Implement constexpr bit_cast for vectors --- .../include/clang/Basic/DiagnosticASTKinds.td | 3 + clang/lib/AST/ExprConstant.cpp| 247 +++--- .../SemaCXX/constexpr-builtin-bit-cast.cpp| 61 + 3 files changed, 217 insertions(+), 94 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td index d2656310e79c9b8..3f06e18783dd558 100644 --- a/clang/include/clang/Basic/DiagnosticASTKinds.td +++ b/clang/include/clang/Basic/DiagnosticASTKinds.td @@ -326,6 +326,9 @@ def note_constexpr_bit_cast_invalid_type : Note< "%select{type|member}1 is not allowed in a constant expression">; def note_constexpr_bit_cast_invalid_subtype : Note< "invalid type %0 is a %select{member|base}1 of %2">; +def note_constexpr_bit_cast_invalid_vector : Note< + "bit_cast involving type %0 is not allowed in a constant expression; " + "element size %1 * element count %2 is not a multiple of the byte size %3">; def note_constexpr_bit_cast_indet_dest : Note< "indeterminate value can only initialize an object of type 'unsigned char'" "%select{, 'char',|}1 or 'std::byte'; %0 is invalid">; diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index a142ea7c47a4730..f7280095e89faee 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -2732,53 +2732,6 @@ static bool truncateBitfieldValue(EvalInfo , const Expr *E, return true; } -static bool EvalAndBitcastToAPInt(EvalInfo , const Expr *E, - llvm::APInt ) { - APValue SVal; - if (!Evaluate(SVal, Info, E)) -return false; - if (SVal.isInt()) { -Res = SVal.getInt(); -return true; - } - if (SVal.isFloat()) { -Res = SVal.getFloat().bitcastToAPInt(); -return true; - } - if (SVal.isVector()) { -QualType VecTy = E->getType(); -unsigned VecSize = Info.Ctx.getTypeSize(VecTy); -QualType EltTy = VecTy->castAs()->getElementType(); -unsigned EltSize = Info.Ctx.getTypeSize(EltTy); -bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian(); -Res = llvm::APInt::getZero(VecSize); -for (unsigned i = 0; i < SVal.getVectorLength(); i++) { - APValue = SVal.getVectorElt(i); - llvm::APInt EltAsInt; - if (Elt.isInt()) { -EltAsInt = Elt.getInt(); - } else if (Elt.isFloat()) { -EltAsInt = Elt.getFloat().bitcastToAPInt(); - } else { -// Don't try to handle vectors of anything other than int or float -// (not sure if it's possible to hit this case). -Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); -return false; - } - unsigned BaseEltSize = EltAsInt.getBitWidth(); - if (BigEndian) -Res |= EltAsInt.zextOrTrunc(VecSize).rotr(i*EltSize+BaseEltSize); - else -Res |= EltAsInt.zextOrTrunc(VecSize).rotl(i*EltSize); -} -return true; - } - // Give up if the input isn't an int, float, or vector. For example, we - // reject "(v4i16)(intptr_t)". - Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); - return false; -} - /// Perform the given integer operation, which is known to need at most BitWidth /// bits, and check for overflow in the original type (if that type was not an /// unsigned type). @@ -7008,10 +6961,11 @@ class APValueToBufferConverter { return visitArray(Val, Ty, Offset); case APValue::Struct: return visitRecord(Val, Ty, Offset); +case APValue::Vector: + return visitVector(Val, Ty, Offset); case APValue::ComplexInt: case APValue::ComplexFloat: -case APValue::Vector: case APValue::FixedPoint: // FIXME: We should support these. @@ -7098,6 +7052,61 @@ class APValueToBufferConverter { return true; } + bool visitVector(const APValue , QualType Ty, CharUnits Offset) { +const VectorType *VTy = Ty->castAs(); +QualType EltTy = VTy->getElementType(); +unsigned NElts = VTy->getNumElements(); +unsigned EltSize = +VTy->isExtVectorBoolType() ? 1 : Info.Ctx.getTypeSize(EltTy); + +if ((NElts * EltSize) % Info.Ctx.getCharWidth() != 0) { + // The vector's size in bits is not a multiple of the target's byte size, + // so its layout is unspecified. For now, we'll simply treat these cases + // as unsupported (this should only be possible with OpenCL bool vectors + // whose element count isn't a multiple of the byte size). + Info.FFDiag(BCE->getBeginLoc(), + diag::note_constexpr_bit_cast_invalid_vector) + << Ty.getCanonicalType() << EltSize << NElts + << Info.Ctx.getCharWidth(); + return false; +} + +if (VTy->isExtVectorBoolType()) { +
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
https://github.com/DaMatrix updated https://github.com/llvm/llvm-project/pull/66894 >From c05ee51f4d930014ac7ff4adb7232ecdaceec7f9 Mon Sep 17 00:00:00 2001 From: DaPorkchop_ Date: Sun, 13 Aug 2023 22:39:12 +0200 Subject: [PATCH] [clang] Implement constexpr bit_cast for vectors --- .../include/clang/Basic/DiagnosticASTKinds.td | 3 + clang/lib/AST/ExprConstant.cpp| 247 +++--- .../SemaCXX/constexpr-builtin-bit-cast.cpp| 61 + 3 files changed, 217 insertions(+), 94 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td index d2656310e79c9b8..3f06e18783dd558 100644 --- a/clang/include/clang/Basic/DiagnosticASTKinds.td +++ b/clang/include/clang/Basic/DiagnosticASTKinds.td @@ -326,6 +326,9 @@ def note_constexpr_bit_cast_invalid_type : Note< "%select{type|member}1 is not allowed in a constant expression">; def note_constexpr_bit_cast_invalid_subtype : Note< "invalid type %0 is a %select{member|base}1 of %2">; +def note_constexpr_bit_cast_invalid_vector : Note< + "bit_cast involving type %0 is not allowed in a constant expression; " + "element size %1 * element count %2 is not a multiple of the byte size %3">; def note_constexpr_bit_cast_indet_dest : Note< "indeterminate value can only initialize an object of type 'unsigned char'" "%select{, 'char',|}1 or 'std::byte'; %0 is invalid">; diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index fea06b97259fe31..fdfb2c3f4431ad4 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -2732,53 +2732,6 @@ static bool truncateBitfieldValue(EvalInfo , const Expr *E, return true; } -static bool EvalAndBitcastToAPInt(EvalInfo , const Expr *E, - llvm::APInt ) { - APValue SVal; - if (!Evaluate(SVal, Info, E)) -return false; - if (SVal.isInt()) { -Res = SVal.getInt(); -return true; - } - if (SVal.isFloat()) { -Res = SVal.getFloat().bitcastToAPInt(); -return true; - } - if (SVal.isVector()) { -QualType VecTy = E->getType(); -unsigned VecSize = Info.Ctx.getTypeSize(VecTy); -QualType EltTy = VecTy->castAs()->getElementType(); -unsigned EltSize = Info.Ctx.getTypeSize(EltTy); -bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian(); -Res = llvm::APInt::getZero(VecSize); -for (unsigned i = 0; i < SVal.getVectorLength(); i++) { - APValue = SVal.getVectorElt(i); - llvm::APInt EltAsInt; - if (Elt.isInt()) { -EltAsInt = Elt.getInt(); - } else if (Elt.isFloat()) { -EltAsInt = Elt.getFloat().bitcastToAPInt(); - } else { -// Don't try to handle vectors of anything other than int or float -// (not sure if it's possible to hit this case). -Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); -return false; - } - unsigned BaseEltSize = EltAsInt.getBitWidth(); - if (BigEndian) -Res |= EltAsInt.zextOrTrunc(VecSize).rotr(i*EltSize+BaseEltSize); - else -Res |= EltAsInt.zextOrTrunc(VecSize).rotl(i*EltSize); -} -return true; - } - // Give up if the input isn't an int, float, or vector. For example, we - // reject "(v4i16)(intptr_t)". - Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); - return false; -} - /// Perform the given integer operation, which is known to need at most BitWidth /// bits, and check for overflow in the original type (if that type was not an /// unsigned type). @@ -7005,10 +6958,11 @@ class APValueToBufferConverter { return visitArray(Val, Ty, Offset); case APValue::Struct: return visitRecord(Val, Ty, Offset); +case APValue::Vector: + return visitVector(Val, Ty, Offset); case APValue::ComplexInt: case APValue::ComplexFloat: -case APValue::Vector: case APValue::FixedPoint: // FIXME: We should support these. @@ -7095,6 +7049,61 @@ class APValueToBufferConverter { return true; } + bool visitVector(const APValue , QualType Ty, CharUnits Offset) { +const VectorType *VTy = Ty->castAs(); +QualType EltTy = VTy->getElementType(); +unsigned NElts = VTy->getNumElements(); +unsigned EltSize = +VTy->isExtVectorBoolType() ? 1 : Info.Ctx.getTypeSize(EltTy); + +if ((NElts * EltSize) % Info.Ctx.getCharWidth() != 0) { + // The vector's size in bits is not a multiple of the target's byte size, + // so its layout is unspecified. For now, we'll simply treat these cases + // as unsupported (this should only be possible with OpenCL bool vectors + // whose element count isn't a multiple of the byte size). + Info.FFDiag(BCE->getBeginLoc(), + diag::note_constexpr_bit_cast_invalid_vector) + << Ty.getCanonicalType() << EltSize << NElts + << Info.Ctx.getCharWidth(); + return false; +} + +if (VTy->isExtVectorBoolType()) { +
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -7304,6 +7382,21 @@ class BufferToAPValueConverter { return ArrayValue; } + std::optional visit(const VectorType *Ty, CharUnits Offset) { +SmallVector Bytes; +if (!Buffer.readObject(Offset, Info.Ctx.getTypeSizeInChars(Ty), Bytes)) + return std::nullopt; DaMatrix wrote: I've nearly got it working, except now we have another fun thing: pointing the `CK_BitCast` at my new implementation which tracks uninitialized padding bits prevents that test case in `const-init.c` from being constant-evaluated, so it proceeds to generate bitcode for it instead. Unfortunately, this doesn't work either because some bit casting code in LLVM itself seems to assume that a vector of `long double` is tightly packed, triggering this assertion: https://github.com/llvm/llvm-project/blob/8768741800aae37a825864e2ee782484ed073ce9/llvm/lib/IR/Instructions.cpp#L3299-L3302 This can actually be reproduced anywhere a vector is bit_casted to or from a vector of long double. [Example](https://godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(filename:'1',fontScale:14,fontUsePx:'0',j:1,lang:c%2B%2B,selection:(endColumn:1,endLineNumber:3,positionColumn:1,positionLineNumber:3,selectionStartColumn:1,selectionStartLineNumber:3,startColumn:1,startLineNumber:3),source:'using+fp80_vec+%3D+long+double+__attribute__((vector_size(32)))%3B%0Ausing+int16_vec+%3D+short+__attribute__((vector_size(32)))%3B%0A%0Afp80_vec+bit_cast_vec(int16_vec+vec)+%7B%0Areturn+(fp80_vec)vec%3B%0A%7D%0A'),l:'5',n:'0',o:'C%2B%2B+source+%231',t:'0')),k:37.545691906005224,l:'4',n:'0',o:'',s:0,t:'0'),(g:!((g:!((h:compiler,i:(compiler:clang170assert,deviceViewOpen:'1',filters:(b:'0',binary:'1',binaryObject:'1',commentOnly:'0',debugCalls:'1',demangle:'0',directives:'0',execute:'1',intel:'0',libraryCode:'0',trim:'1'),flagsViewOpen:'1',fontScale:14,fontUsePx:'0',j:1,lang:c%2B%2B,libs:!(),options:'-emit-llvm+-march%3Dskylake',overrides:!(),selection:(endColumn:1,endLineNumber:1,positionColumn:1,positionLineNumber:1,selectionStartColumn:1,selectionStartLineNumber:1,startColumn:1,startLineNumber:1),source:1),l:'5',n:'0',o:'+x86-64+clang+17.0.1+(assertions)+(Editor+%231)',t:'0')),k:50,l:'4',m:31.542857142857144,n:'0',o:'',s:0,t:'0'),(g:!((h:output,i:(compilerName:'x86-64+clang+17.0.1+(assertions)',editorid:1,fontScale:14,fontUsePx:'0',j:1,wrap:'1'),l:'5',n:'0',o:'Output+of+x86-64+clang+17.0.1+(assertions)+(Compiler+%231)',t:'0')),header:(),l:'4',m:68.45714285714286,n:'0',o:'',s:0,t:'0')),k:62.45430809399477,l:'3',n:'0',o:'',t:'0')),l:'2',n:'0',o:'',t:'0')),version:4) This obviously needs to be fixed as well; should I do that here or make a separate PR for that? https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -7304,6 +7382,21 @@ class BufferToAPValueConverter { return ArrayValue; } + std::optional visit(const VectorType *Ty, CharUnits Offset) { +SmallVector Bytes; +if (!Buffer.readObject(Offset, Info.Ctx.getTypeSizeInChars(Ty), Bytes)) + return std::nullopt; zygoloid wrote: The object representation indeed does not seem to initialize the padding bits: https://godbolt.org/z/szWenbE8c - In Clang, the padding bytes contain non-zero values for both vectors and structs. - In Clang msan, only the branch on uninitialized padding in the struct is caught. (I think this is an msan bug; it presumably isn't taking into account that a vector type might contain padding.) - In GCC, the padding bytes in the vector are zeroed but the padding bytes in the struct are not. (Though that could be an accident of implementation rather than intent.) Casts between vector types don't seem to initialize padding bits either: https://godbolt.org/z/Gex93x3xx -- so the test in const-init.c seems to be wrong. > Should I rewrite all the bit cast conversion code in > `APValueToBufferConverter`/`BufferToAPValueConverter` again while taking > uninitialized padding bytes into account, and redirect the existing > `CK_BitCast` code to point to that? :( Yeah, I guess so. Sorry. https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -7304,6 +7382,21 @@ class BufferToAPValueConverter { return ArrayValue; } + std::optional visit(const VectorType *Ty, CharUnits Offset) { +SmallVector Bytes; +if (!Buffer.readObject(Offset, Info.Ctx.getTypeSizeInChars(Ty), Bytes)) + return std::nullopt; DaMatrix wrote: Hrm, this is indeed awkward: I obviously can't load the entire f80 vector at once, but loading individual elements at a time would not only force me to duplicate much of the code again, but would also make bool vectors break again without once again adding special handling (since we'd have to load individual bytes at a time again). Can we simply assume the uninitialized padding bits are always zero? This test in `CodeGen/const-init.c` (the case `b`): https://github.com/llvm/llvm-project/blob/8768741800aae37a825864e2ee782484ed073ce9/clang/test/CodeGen/const-init.c#L138-L148 which uses `CK_BitCast` seems to make that assumption, while a variety of the existing tests in `SemaCXX/constexpr-builtin-bit-cast.cpp`: https://github.com/llvm/llvm-project/blob/8768741800aae37a825864e2ee782484ed073ce9/clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp#L332-L351 assume that bit-casting padding space should return uninitialized values (or fail when the target type isn't allowed to be uninitialized in a constexpr context). Is the `CK_BitCast` assumption simply wrong, or do these two different ways of triggering a bit cast really have such different semantics? I can see a few places in the actual LLVM constant folding code where vector bit casts containing uninitialized elements are, in fact, initialized to zero, but I feel like that makes sense there since it doesn't have to adhere to the rules of `constexpr`. Should I rewrite all the bit cast conversion code in `APValueToBufferConverter`/`BufferToAPValueConverter` again while taking uninitialized padding bytes into account, and redirect the existing `CK_BitCast` code to point to that? https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -7095,6 +7157,22 @@ class APValueToBufferConverter { return true; } + bool visitVector(const APValue , QualType Ty, CharUnits Offset) { +const VectorType *VTy = Ty->castAs(); + +APInt Bits; +if (!BitcastVectorToAPInt(Info, VTy, Val, Bits)) + return false; + +assert(Bits.getBitWidth() == Info.Ctx.getTypeSize(Ty)); + +unsigned Width = Bits.getBitWidth(); +SmallVector Bytes(Width / 8); +llvm::StoreIntToMemory(Bits, &*Bytes.begin(), Width / 8); +Buffer.writeObject(Offset, Bytes); DaMatrix wrote: This example on [Compiler Explorer](https://godbolt.org/#z:OYLghAFBqd5QCxAYwPYBMCmBRdBLAF1QCcAaPECAMzwBtMA7AQwFtMQByARg9KtQYEAysib0QXACx8BBAKoBnTAAUAHpwAMvAFYTStJg1DIApACYAQuYukl9ZATwDKjdAGFUtAK4sGe1wAyeAyYAHI%2BAEaYxCBmpAAOqAqETgwe3r56icmOAkEh4SxRMXF2mA6pQgRMxATpPn5ctpj2uQxVNQT5YZHRsbbVtfWZTQqDXcE9RX1mAJS2qF7EyOwcaAxjANS0AsCb6IsR9JtU8QAcGgD6CqIGxJsmAMwAIpsQO0b7h/Szm1ybAHo3h89gcvEdML9Hk8rBoAIImeFeZKfU4XS4AN3KDxe212X3Bx0ulyYBAIxDwES8BEwxKgWIcJGueAAXpgII85rNZjDEXC0VcGZtgJgCJjyhBfiYAOywuGbBWbYiipYME7nQXlGUWdXom5iGqkXVXfV3GXPXnw818vljYheBzG67kh0EB6yvGfMEQzZMI0RGHui2POUC532x0isV212S91yxVKlXENXap2mw3p241IOWhHSi3wjjzWicACsvD8HC0pFQnDc1msmwUi2WmAeZkePFIBE0xfmAGsQI9HgA6EcTydTgBs%2Bk4kkrfdrnF4ChAGh7ffmcFgSDQLHidGi5Eo%2B8P9BiyAMRkuLoYA9IWAxeBWADU8JgAO4AeXijE43Y0LQNLEGuEAREuETBDUACeAG8FBzDEDB34RNo5S9twvD7mwgjfgwtBwdWvBYFSwBuGItBrlhj6YCwhjAOIxGPngyoVFi1E1pgqjlNSqzdsENKlsxtCUsQsEeFgS7kngLDwfMVAGMACjvl%2Bv7/jR/CCCIYjsFIMiCIoKjqMxuhNNexiNpY%2BiUmukDzKg8RtNRvCoFixAUlgdmSs0rSpC4DDuJ4DT%2BIF3SFMUWRJCkAjDI0CTRW04W9DEowtBhlTjHFehlBUAgdLUyXTKlAydNlozjEVkVcPMLZLCsEgluWi7MXWHCbKoZzTgAtNOkibFeDFvHeA6/BAuCECQHZdrMvCYVo3KkEOI7jlOa0jrOwkLqQclcBoG5VjWbWruum7EduMCICgqAHkeZAUBAZ53SAynMPECgIKgBC0c%2Bb4fj%2Bf5VoBdAgWBEHMYhsHwaQkPIah6EONDOGMAQ%2BGEUupFeORlHUd2WD0UYTE1vgbGOBxS7cbxNLQ4JLRLqJETichkmrDWMlyVhClKSp/3qUDvBacItx6dIgtGWoS66HEFkoFZNgM95DlOakLm1u5nmYIrvkZc4ECuOVpCBJMEV9E02QxWkwUjAlOSpFVpva3l7RZVb8W5W0BUTAUKU5S7GRu5Vxs%2BzVCz1XpTUcBWpCHa5nAdV1vX9cAyDIMN9r3mNE1EPc5gzXNW6DsOY7retc4cNtMfLhwJ0bvN/Zl2YLVHSuZ0LfM7nJM4khAA%3D%3D%3D) seems to show that the padding bits are uninitialized for both vectors and scalars: in either case, both clang and gcc don't initialize the 6 bytes of padding after each fp80 element. https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
https://github.com/zygoloid edited https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -7304,6 +7382,21 @@ class BufferToAPValueConverter { return ArrayValue; } + std::optional visit(const VectorType *Ty, CharUnits Offset) { +SmallVector Bytes; +if (!Buffer.readObject(Offset, Info.Ctx.getTypeSizeInChars(Ty), Bytes)) + return std::nullopt; zygoloid wrote: At least, assuming that there is padding in the same places in both. Maybe the vector doesn't actually have padding, but the struct does, so the round-trip *should* fail? https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
https://github.com/zygoloid edited https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -2732,6 +2732,92 @@ static bool truncateBitfieldValue(EvalInfo , const Expr *E, return true; } +static bool BitcastAPIntToVector(EvalInfo , const VectorType *VTy, + const llvm::APInt , + SmallVectorImpl ) { + QualType EltTy = VTy->getElementType(); + unsigned NElts = VTy->getNumElements(); + unsigned EltSize = + VTy->isExtVectorBoolType() ? 1 : Info.Ctx.getTypeSize(EltTy); + + if ((NElts * EltSize) % Info.Ctx.getCharWidth() != 0) { +// The vector's size in bits is not a multiple of the target's byte size, +// so its layout is unspecified. For now, we'll simply treat these cases as +// unsupported (this should only be possible with OpenCL bool vectors whose +// element count isn't a multiple of the byte size). +return false; + } + + Elts.reserve(NElts); + bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian(); + if (EltTy->isRealFloatingType()) { +const llvm::fltSemantics = Info.Ctx.getFloatTypeSemantics(EltTy); +unsigned FloatEltSize = EltSize; +if ( == ::x87DoubleExtended()) + FloatEltSize = 80; +for (unsigned i = 0; i < NElts; i++) { + llvm::APInt Elt; + if (BigEndian) +Elt = SValInt.rotl(i * EltSize + FloatEltSize).trunc(FloatEltSize); + else +Elt = SValInt.rotr(i * EltSize).trunc(FloatEltSize); zygoloid wrote: ```suggestion llvm::APInt Elt = SValInt.extractBits(FloatEltSize, BigEndian ? (NElts - i) * EltSize - FloatEltSize : i * EltSize); ``` Extracting the bits in one go will avoid a heap allocation if the vector is larger than 64 bits but its elements are not. https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -2732,6 +2732,92 @@ static bool truncateBitfieldValue(EvalInfo , const Expr *E, return true; } +static bool BitcastAPIntToVector(EvalInfo , const VectorType *VTy, + const llvm::APInt , + SmallVectorImpl ) { + QualType EltTy = VTy->getElementType(); + unsigned NElts = VTy->getNumElements(); + unsigned EltSize = + VTy->isExtVectorBoolType() ? 1 : Info.Ctx.getTypeSize(EltTy); + + if ((NElts * EltSize) % Info.Ctx.getCharWidth() != 0) { +// The vector's size in bits is not a multiple of the target's byte size, +// so its layout is unspecified. For now, we'll simply treat these cases as +// unsupported (this should only be possible with OpenCL bool vectors whose +// element count isn't a multiple of the byte size). +return false; + } + + Elts.reserve(NElts); + bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian(); + if (EltTy->isRealFloatingType()) { +const llvm::fltSemantics = Info.Ctx.getFloatTypeSemantics(EltTy); +unsigned FloatEltSize = EltSize; +if ( == ::x87DoubleExtended()) + FloatEltSize = 80; +for (unsigned i = 0; i < NElts; i++) { + llvm::APInt Elt; + if (BigEndian) +Elt = SValInt.rotl(i * EltSize + FloatEltSize).trunc(FloatEltSize); + else +Elt = SValInt.rotr(i * EltSize).trunc(FloatEltSize); + Elts.push_back(APValue(APFloat(Sem, Elt))); +} + } else if (EltTy->isIntegerType()) { +for (unsigned i = 0; i < NElts; i++) { + llvm::APInt Elt; + if (BigEndian) +Elt = SValInt.rotl(i * EltSize + EltSize).zextOrTrunc(EltSize); + else +Elt = SValInt.rotr(i * EltSize).zextOrTrunc(EltSize); + Elts.push_back(APValue(APSInt(Elt, !EltTy->isSignedIntegerType(; +} + } else { +return false; + } + return true; +} + +static bool BitcastVectorToAPInt(EvalInfo , const VectorType *VTy, + const APValue , llvm::APInt ) { + QualType EltTy = VTy->getElementType(); + unsigned NElts = VTy->getNumElements(); + unsigned EltSize = + VTy->isExtVectorBoolType() ? 1 : Info.Ctx.getTypeSize(EltTy); + unsigned VecSize = Info.Ctx.getTypeSize(VTy); + + if ((NElts * EltSize) % Info.Ctx.getCharWidth() != 0) { +// The vector's size in bits is not a multiple of the target's byte size, +// so its layout is unspecified. For now, we'll simply treat these cases as +// unsupported (this should only be possible with OpenCL bool vectors whose +// element count isn't a multiple of the byte size). +return false; + } + + bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian(); + Res = llvm::APInt::getZero(VecSize); + for (unsigned i = 0; i < SVal.getVectorLength(); i++) { +const APValue = SVal.getVectorElt(i); +llvm::APInt EltAsInt; zygoloid wrote: Move this out of the loop so that we only allocate storage for it once. (It typically won't fit in 64 bits, so this will perform a heap allocation.) https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -7095,6 +7157,22 @@ class APValueToBufferConverter { return true; } + bool visitVector(const APValue , QualType Ty, CharUnits Offset) { +const VectorType *VTy = Ty->castAs(); + +APInt Bits; +if (!BitcastVectorToAPInt(Info, VTy, Val, Bits)) + return false; + +assert(Bits.getBitWidth() == Info.Ctx.getTypeSize(Ty)); + +unsigned Width = Bits.getBitWidth(); +SmallVector Bytes(Width / 8); +llvm::StoreIntToMemory(Bits, &*Bytes.begin(), Width / 8); +Buffer.writeObject(Offset, Bytes); zygoloid wrote: Are the padding bits of an x86 fp80 vector defined? If not, we'll need to avoid marking them as initialized here... https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -2732,6 +2732,92 @@ static bool truncateBitfieldValue(EvalInfo , const Expr *E, return true; } +static bool BitcastAPIntToVector(EvalInfo , const VectorType *VTy, + const llvm::APInt , + SmallVectorImpl ) { + QualType EltTy = VTy->getElementType(); + unsigned NElts = VTy->getNumElements(); + unsigned EltSize = + VTy->isExtVectorBoolType() ? 1 : Info.Ctx.getTypeSize(EltTy); + + if ((NElts * EltSize) % Info.Ctx.getCharWidth() != 0) { +// The vector's size in bits is not a multiple of the target's byte size, +// so its layout is unspecified. For now, we'll simply treat these cases as +// unsupported (this should only be possible with OpenCL bool vectors whose +// element count isn't a multiple of the byte size). +return false; + } + + Elts.reserve(NElts); + bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian(); + if (EltTy->isRealFloatingType()) { +const llvm::fltSemantics = Info.Ctx.getFloatTypeSemantics(EltTy); +unsigned FloatEltSize = EltSize; +if ( == ::x87DoubleExtended()) + FloatEltSize = 80; +for (unsigned i = 0; i < NElts; i++) { + llvm::APInt Elt; + if (BigEndian) +Elt = SValInt.rotl(i * EltSize + FloatEltSize).trunc(FloatEltSize); + else +Elt = SValInt.rotr(i * EltSize).trunc(FloatEltSize); + Elts.push_back(APValue(APFloat(Sem, Elt))); +} + } else if (EltTy->isIntegerType()) { +for (unsigned i = 0; i < NElts; i++) { + llvm::APInt Elt; + if (BigEndian) +Elt = SValInt.rotl(i * EltSize + EltSize).zextOrTrunc(EltSize); + else +Elt = SValInt.rotr(i * EltSize).zextOrTrunc(EltSize); + Elts.push_back(APValue(APSInt(Elt, !EltTy->isSignedIntegerType(; +} + } else { +return false; + } + return true; +} + +static bool BitcastVectorToAPInt(EvalInfo , const VectorType *VTy, + const APValue , llvm::APInt ) { + QualType EltTy = VTy->getElementType(); + unsigned NElts = VTy->getNumElements(); + unsigned EltSize = + VTy->isExtVectorBoolType() ? 1 : Info.Ctx.getTypeSize(EltTy); + unsigned VecSize = Info.Ctx.getTypeSize(VTy); + + if ((NElts * EltSize) % Info.Ctx.getCharWidth() != 0) { +// The vector's size in bits is not a multiple of the target's byte size, +// so its layout is unspecified. For now, we'll simply treat these cases as +// unsupported (this should only be possible with OpenCL bool vectors whose +// element count isn't a multiple of the byte size). +return false; + } + + bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian(); + Res = llvm::APInt::getZero(VecSize); + for (unsigned i = 0; i < SVal.getVectorLength(); i++) { +const APValue = SVal.getVectorElt(i); +llvm::APInt EltAsInt; +if (Elt.isInt()) { + EltAsInt = Elt.getInt(); +} else if (Elt.isFloat()) { + EltAsInt = Elt.getFloat().bitcastToAPInt(); +} else { + // Don't try to handle vectors of anything other than int or float + // (not sure if it's possible to hit this case). + return false; +} +unsigned BaseEltSize = EltAsInt.getBitWidth(); +if (BigEndian) + Res |= EltAsInt.zextOrTrunc(VecSize).rotr(i * EltSize + BaseEltSize); +else + Res |= EltAsInt.zextOrTrunc(VecSize).rotl(i * EltSize); zygoloid wrote: ```suggestion Res.insertBits(EltAsInt, BigEndian ? (NElts - i) * EltSize - BaseEltSize : i * EltSize); ``` Avoid another heap allocation. https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -7304,6 +7382,21 @@ class BufferToAPValueConverter { return ArrayValue; } + std::optional visit(const VectorType *Ty, CharUnits Offset) { +SmallVector Bytes; +if (!Buffer.readObject(Offset, Info.Ctx.getTypeSizeInChars(Ty), Bytes)) + return std::nullopt; zygoloid wrote: ... and here we'll need to not reject if the padding bits are uninitialized. As a testcase, we should ensure that (for example) this: ```c++ struct A { long double a, b, c, d; }; ``` can round-trip through a vector of 4 `long double`s. https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -2732,6 +2732,92 @@ static bool truncateBitfieldValue(EvalInfo , const Expr *E, return true; } +static bool BitcastAPIntToVector(EvalInfo , const VectorType *VTy, + const llvm::APInt , + SmallVectorImpl ) { + QualType EltTy = VTy->getElementType(); + unsigned NElts = VTy->getNumElements(); + unsigned EltSize = + VTy->isExtVectorBoolType() ? 1 : Info.Ctx.getTypeSize(EltTy); + + if ((NElts * EltSize) % Info.Ctx.getCharWidth() != 0) { +// The vector's size in bits is not a multiple of the target's byte size, +// so its layout is unspecified. For now, we'll simply treat these cases as +// unsupported (this should only be possible with OpenCL bool vectors whose +// element count isn't a multiple of the byte size). +return false; + } + + Elts.reserve(NElts); + bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian(); + if (EltTy->isRealFloatingType()) { +const llvm::fltSemantics = Info.Ctx.getFloatTypeSemantics(EltTy); +unsigned FloatEltSize = EltSize; +if ( == ::x87DoubleExtended()) + FloatEltSize = 80; +for (unsigned i = 0; i < NElts; i++) { + llvm::APInt Elt; + if (BigEndian) +Elt = SValInt.rotl(i * EltSize + FloatEltSize).trunc(FloatEltSize); + else +Elt = SValInt.rotr(i * EltSize).trunc(FloatEltSize); + Elts.push_back(APValue(APFloat(Sem, Elt))); +} + } else if (EltTy->isIntegerType()) { +for (unsigned i = 0; i < NElts; i++) { + llvm::APInt Elt; + if (BigEndian) +Elt = SValInt.rotl(i * EltSize + EltSize).zextOrTrunc(EltSize); + else +Elt = SValInt.rotr(i * EltSize).zextOrTrunc(EltSize); + Elts.push_back(APValue(APSInt(Elt, !EltTy->isSignedIntegerType(; zygoloid wrote: ```suggestion llvm::APInt Elt = SValInt.extractBits(FloatEltSize, (BigEndian ? NElts - i - 1 : i) * EltSize)); Elts.push_back(APValue(APSInt(std::move(Elt), !EltTy->isSignedIntegerType(; ``` As above, but also `std::move` the `APInt` into the `APSInt` to avoid another heap allocation if the element size is > 64 bits. https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
https://github.com/zygoloid commented: Thanks, I like the code reuse! There are some minor optimization and simplification opportunities in the code you're reusing that might be worth addressing now. I'm worried that vectors with padding (which I think is only vectors of x86 `long double`) aren't being treated properly by `bit_cast` here. It's probably a bit awkward to fix, given the new approach, but maybe we can handle the padding separately from the conversion of the vector to/from `APInt`. https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
https://github.com/zygoloid edited https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -7095,6 +7096,40 @@ class APValueToBufferConverter { return true; } + bool visitVector(const APValue , QualType Ty, CharUnits Offset) { +const auto *VT = Ty->castAs(); +unsigned VectorLength = Val.getVectorLength(); + +if (VT->isExtVectorBoolType()) { + // Special handling for OpenCL bool vectors: we need to pack the vector + // of 1-bit unsigned integers into a single integer with the corresponding + // bits set, then write out the resulting integer. + + CharUnits VecWidthBits = Info.Ctx.getTypeSizeInChars(VT) * 8; + + APSInt Bits(VecWidthBits.getQuantity()); + for (unsigned I = 0; I != VectorLength; ++I) { +const APValue = Val.getVectorElt(I); +assert(SubObj.isInt() && "Bool vector element isn't an int?"); +Bits.setBitVal(I, !SubObj.getInt().isZero()); DaMatrix wrote: Okay, the latest revision will now fail to evaluate vectors which aren't a multiple of the byte size. https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -463,3 +463,38 @@ static_assert(bit_cast(ld539) == fivehundredandthirtynine, ""); static_assert(round_trip<__int128_t>(34.0L)); #endif } + +namespace test_vector { + +typedef unsigned uint2 __attribute__((vector_size(2 * sizeof(unsigned; +typedef char byte8 __attribute__((vector_size(sizeof(unsigned long long; + +constexpr uint2 test_vector = { 0x0C05FEFE, 0xCAFEBABE }; + +static_assert(bit_cast(test_vector) == (LITTLE_END +? 0xCAFEBABE0C05FEFE +: 0x0C05FEFECAFEBABE), ""); + +static_assert(round_trip(0xCAFEBABE0C05FEFEULL), ""); +static_assert(round_trip(0xCAFEBABE0C05FEFEULL), ""); + +typedef bool bool8 __attribute__((ext_vector_type(8))); +typedef bool bool9 __attribute__((ext_vector_type(9))); +typedef bool bool17 __attribute__((ext_vector_type(17))); +typedef bool bool32 __attribute__((ext_vector_type(32))); + +static_assert(bit_cast(bool8{1,0,1,0,1,0,1,0}) == 0x55, ""); +static_assert(round_trip(static_cast(0)), ""); +static_assert(round_trip(static_cast(1)), ""); +static_assert(round_trip(static_cast(0x55)), ""); + +static_assert(bit_cast(bool9{1,1,0,1,0,1,0,1,0}) == 0xAB, ""); DaMatrix wrote: Alright, the latest revision should handle byte order correctly. https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
DaMatrix wrote: While attempting to make the result properly endianness-dependent, I noticed that `VectorExprEvaluator::VisitCastExpr` with `CK_BitCast` already had code for this which takes the byte ordering into account (although it also didn't handle bool vectors correctly either). I've now moved the existing Vector<->APInt bit casting code into a pair of separate methods, and made both `CK_BitCast` and the new bit casting code use those. https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
https://github.com/DaMatrix updated https://github.com/llvm/llvm-project/pull/66894 >From 8768741800aae37a825864e2ee782484ed073ce9 Mon Sep 17 00:00:00 2001 From: DaPorkchop_ Date: Sun, 13 Aug 2023 22:39:12 +0200 Subject: [PATCH] [clang] Implement constexpr bit_cast for vectors --- clang/lib/AST/ExprConstant.cpp| 181 -- .../SemaCXX/constexpr-builtin-bit-cast.cpp| 38 2 files changed, 162 insertions(+), 57 deletions(-) diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index fea06b97259fe31..8cd6a0e390ee0f8 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -2732,6 +2732,92 @@ static bool truncateBitfieldValue(EvalInfo , const Expr *E, return true; } +static bool BitcastAPIntToVector(EvalInfo , const VectorType *VTy, + const llvm::APInt , + SmallVectorImpl ) { + QualType EltTy = VTy->getElementType(); + unsigned NElts = VTy->getNumElements(); + unsigned EltSize = + VTy->isExtVectorBoolType() ? 1 : Info.Ctx.getTypeSize(EltTy); + + if ((NElts * EltSize) % Info.Ctx.getCharWidth() != 0) { +// The vector's size in bits is not a multiple of the target's byte size, +// so its layout is unspecified. For now, we'll simply treat these cases as +// unsupported (this should only be possible with OpenCL bool vectors whose +// element count isn't a multiple of the byte size). +return false; + } + + Elts.reserve(NElts); + bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian(); + if (EltTy->isRealFloatingType()) { +const llvm::fltSemantics = Info.Ctx.getFloatTypeSemantics(EltTy); +unsigned FloatEltSize = EltSize; +if ( == ::x87DoubleExtended()) + FloatEltSize = 80; +for (unsigned i = 0; i < NElts; i++) { + llvm::APInt Elt; + if (BigEndian) +Elt = SValInt.rotl(i * EltSize + FloatEltSize).trunc(FloatEltSize); + else +Elt = SValInt.rotr(i * EltSize).trunc(FloatEltSize); + Elts.push_back(APValue(APFloat(Sem, Elt))); +} + } else if (EltTy->isIntegerType()) { +for (unsigned i = 0; i < NElts; i++) { + llvm::APInt Elt; + if (BigEndian) +Elt = SValInt.rotl(i * EltSize + EltSize).zextOrTrunc(EltSize); + else +Elt = SValInt.rotr(i * EltSize).zextOrTrunc(EltSize); + Elts.push_back(APValue(APSInt(Elt, !EltTy->isSignedIntegerType(; +} + } else { +return false; + } + return true; +} + +static bool BitcastVectorToAPInt(EvalInfo , const VectorType *VTy, + const APValue , llvm::APInt ) { + QualType EltTy = VTy->getElementType(); + unsigned NElts = VTy->getNumElements(); + unsigned EltSize = + VTy->isExtVectorBoolType() ? 1 : Info.Ctx.getTypeSize(EltTy); + unsigned VecSize = Info.Ctx.getTypeSize(VTy); + + if ((NElts * EltSize) % Info.Ctx.getCharWidth() != 0) { +// The vector's size in bits is not a multiple of the target's byte size, +// so its layout is unspecified. For now, we'll simply treat these cases as +// unsupported (this should only be possible with OpenCL bool vectors whose +// element count isn't a multiple of the byte size). +return false; + } + + bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian(); + Res = llvm::APInt::getZero(VecSize); + for (unsigned i = 0; i < SVal.getVectorLength(); i++) { +const APValue = SVal.getVectorElt(i); +llvm::APInt EltAsInt; +if (Elt.isInt()) { + EltAsInt = Elt.getInt(); +} else if (Elt.isFloat()) { + EltAsInt = Elt.getFloat().bitcastToAPInt(); +} else { + // Don't try to handle vectors of anything other than int or float + // (not sure if it's possible to hit this case). + return false; +} +unsigned BaseEltSize = EltAsInt.getBitWidth(); +if (BigEndian) + Res |= EltAsInt.zextOrTrunc(VecSize).rotr(i * EltSize + BaseEltSize); +else + Res |= EltAsInt.zextOrTrunc(VecSize).rotl(i * EltSize); + } + + return true; +} + static bool EvalAndBitcastToAPInt(EvalInfo , const Expr *E, llvm::APInt ) { APValue SVal; @@ -2745,34 +2831,9 @@ static bool EvalAndBitcastToAPInt(EvalInfo , const Expr *E, Res = SVal.getFloat().bitcastToAPInt(); return true; } - if (SVal.isVector()) { -QualType VecTy = E->getType(); -unsigned VecSize = Info.Ctx.getTypeSize(VecTy); -QualType EltTy = VecTy->castAs()->getElementType(); -unsigned EltSize = Info.Ctx.getTypeSize(EltTy); -bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian(); -Res = llvm::APInt::getZero(VecSize); -for (unsigned i = 0; i < SVal.getVectorLength(); i++) { - APValue = SVal.getVectorElt(i); - llvm::APInt EltAsInt; - if (Elt.isInt()) { -EltAsInt = Elt.getInt(); - } else if (Elt.isFloat()) { -EltAsInt = Elt.getFloat().bitcastToAPInt(); - } else { -// Don't try to handle
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -7095,6 +7096,40 @@ class APValueToBufferConverter { return true; } + bool visitVector(const APValue , QualType Ty, CharUnits Offset) { +const auto *VT = Ty->castAs(); +unsigned VectorLength = Val.getVectorLength(); + +if (VT->isExtVectorBoolType()) { + // Special handling for OpenCL bool vectors: we need to pack the vector + // of 1-bit unsigned integers into a single integer with the corresponding + // bits set, then write out the resulting integer. + + CharUnits VecWidthBits = Info.Ctx.getTypeSizeInChars(VT) * 8; + + APSInt Bits(VecWidthBits.getQuantity()); + for (unsigned I = 0; I != VectorLength; ++I) { +const APValue = Val.getVectorElt(I); +assert(SubObj.isInt() && "Bool vector element isn't an int?"); +Bits.setBitVal(I, !SubObj.getInt().isZero()); zygoloid wrote: I think that'd be fine. It doesn't seem like those vectors are well-supported elsewhere in Clang and LLVM (for example, I hit a miscompile bug #67060 while trying to figure out how they are stored in memory), so I think it's fine if they're also not well-supported by constant evaluation, at least for now. https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -7095,6 +7096,40 @@ class APValueToBufferConverter { return true; } + bool visitVector(const APValue , QualType Ty, CharUnits Offset) { +const auto *VT = Ty->castAs(); +unsigned VectorLength = Val.getVectorLength(); + +if (VT->isExtVectorBoolType()) { + // Special handling for OpenCL bool vectors: we need to pack the vector + // of 1-bit unsigned integers into a single integer with the corresponding + // bits set, then write out the resulting integer. + + CharUnits VecWidthBits = Info.Ctx.getTypeSizeInChars(VT) * 8; + + APSInt Bits(VecWidthBits.getQuantity()); + for (unsigned I = 0; I != VectorLength; ++I) { +const APValue = Val.getVectorElt(I); +assert(SubObj.isInt() && "Bool vector element isn't an int?"); +Bits.setBitVal(I, !SubObj.getInt().isZero()); DaMatrix wrote: I've come to the same conclusion as you that I don't think this is possible with non-byte-sized vectors. Since this is only an issue for OpenCL bool vectors, should I just have it fail with an unsupported exception when the number of bool elements isn't a multiple of the char size? https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
https://github.com/DaMatrix edited https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -463,3 +463,38 @@ static_assert(bit_cast(ld539) == fivehundredandthirtynine, ""); static_assert(round_trip<__int128_t>(34.0L)); #endif } + +namespace test_vector { + +typedef unsigned uint2 __attribute__((vector_size(2 * sizeof(unsigned; +typedef char byte8 __attribute__((vector_size(sizeof(unsigned long long; + +constexpr uint2 test_vector = { 0x0C05FEFE, 0xCAFEBABE }; + +static_assert(bit_cast(test_vector) == (LITTLE_END +? 0xCAFEBABE0C05FEFE +: 0x0C05FEFECAFEBABE), ""); + +static_assert(round_trip(0xCAFEBABE0C05FEFEULL), ""); +static_assert(round_trip(0xCAFEBABE0C05FEFEULL), ""); + +typedef bool bool8 __attribute__((ext_vector_type(8))); +typedef bool bool9 __attribute__((ext_vector_type(9))); +typedef bool bool17 __attribute__((ext_vector_type(17))); +typedef bool bool32 __attribute__((ext_vector_type(32))); + +static_assert(bit_cast(bool8{1,0,1,0,1,0,1,0}) == 0x55, ""); +static_assert(round_trip(static_cast(0)), ""); +static_assert(round_trip(static_cast(1)), ""); +static_assert(round_trip(static_cast(0x55)), ""); + +static_assert(bit_cast(bool9{1,1,0,1,0,1,0,1,0}) == 0xAB, ""); DaMatrix wrote: Sorry, disregard this - further experimentation and [your comment above](https://github.com/llvm/llvm-project/pull/66894#discussion_r1333587577) has convinced me that this isn't the case. https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -463,3 +463,38 @@ static_assert(bit_cast(ld539) == fivehundredandthirtynine, ""); static_assert(round_trip<__int128_t>(34.0L)); #endif } + +namespace test_vector { + +typedef unsigned uint2 __attribute__((vector_size(2 * sizeof(unsigned; +typedef char byte8 __attribute__((vector_size(sizeof(unsigned long long; + +constexpr uint2 test_vector = { 0x0C05FEFE, 0xCAFEBABE }; + +static_assert(bit_cast(test_vector) == (LITTLE_END +? 0xCAFEBABE0C05FEFE +: 0x0C05FEFECAFEBABE), ""); + +static_assert(round_trip(0xCAFEBABE0C05FEFEULL), ""); +static_assert(round_trip(0xCAFEBABE0C05FEFEULL), ""); + +typedef bool bool8 __attribute__((ext_vector_type(8))); +typedef bool bool9 __attribute__((ext_vector_type(9))); +typedef bool bool17 __attribute__((ext_vector_type(17))); +typedef bool bool32 __attribute__((ext_vector_type(32))); + +static_assert(bit_cast(bool8{1,0,1,0,1,0,1,0}) == 0x55, ""); +static_assert(round_trip(static_cast(0)), ""); +static_assert(round_trip(static_cast(1)), ""); +static_assert(round_trip(static_cast(0x55)), ""); + +static_assert(bit_cast(bool9{1,1,0,1,0,1,0,1,0}) == 0xAB, ""); DaMatrix wrote: I don't think it should be: from what I can tell, existing code such as `CodeGenFunction::EmitLoadOfScalar` stores an N-element bool vector directly as a single N-bit integer (with some extra padding bits if the vector length doesn't correspond directly to a native integer type), where the least significant bit corresponds to vector element `0`, etc. To the best of my understanding, this would mean that `bit_cast`-ing a bool vector to an integer type should work the same as `bit_cast`-ing an integer type to another integer type of the same size, and endianness should be irrelevant when casting between integers because both integers are in the native byte order. It would probably be good to get someone who knows how this stuff is supposed to work to confirm one way or the other, but I'm not sure who that would be. https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -463,3 +463,38 @@ static_assert(bit_cast(ld539) == fivehundredandthirtynine, ""); static_assert(round_trip<__int128_t>(34.0L)); #endif } + +namespace test_vector { + +typedef unsigned uint2 __attribute__((vector_size(2 * sizeof(unsigned; +typedef char byte8 __attribute__((vector_size(sizeof(unsigned long long; + +constexpr uint2 test_vector = { 0x0C05FEFE, 0xCAFEBABE }; + +static_assert(bit_cast(test_vector) == (LITTLE_END +? 0xCAFEBABE0C05FEFE +: 0x0C05FEFECAFEBABE), ""); + +static_assert(round_trip(0xCAFEBABE0C05FEFEULL), ""); +static_assert(round_trip(0xCAFEBABE0C05FEFEULL), ""); + +typedef bool bool8 __attribute__((ext_vector_type(8))); +typedef bool bool9 __attribute__((ext_vector_type(9))); +typedef bool bool17 __attribute__((ext_vector_type(17))); +typedef bool bool32 __attribute__((ext_vector_type(32))); + +static_assert(bit_cast(bool8{1,0,1,0,1,0,1,0}) == 0x55, ""); +static_assert(round_trip(static_cast(0)), ""); +static_assert(round_trip(static_cast(1)), ""); +static_assert(round_trip(static_cast(0x55)), ""); + +static_assert(bit_cast(bool9{1,1,0,1,0,1,0,1,0}) == 0xAB, ""); zygoloid wrote: I believe this result should be endianness-dependent; for ppc64 I think we should give `0x1AA` instead. https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
https://github.com/zygoloid edited https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -7095,6 +7096,40 @@ class APValueToBufferConverter { return true; } + bool visitVector(const APValue , QualType Ty, CharUnits Offset) { +const auto *VT = Ty->castAs(); +unsigned VectorLength = Val.getVectorLength(); + +if (VT->isExtVectorBoolType()) { + // Special handling for OpenCL bool vectors: we need to pack the vector + // of 1-bit unsigned integers into a single integer with the corresponding + // bits set, then write out the resulting integer. + + CharUnits VecWidthBits = Info.Ctx.getTypeSizeInChars(VT) * 8; + + APSInt Bits(VecWidthBits.getQuantity()); + for (unsigned I = 0; I != VectorLength; ++I) { +const APValue = Val.getVectorElt(I); +assert(SubObj.isInt() && "Bool vector element isn't an int?"); +Bits.setBitVal(I, !SubObj.getInt().isZero()); zygoloid wrote: Hm, it concerns me that the documentation says: "When isn’t evenly divisible by the byte size the exact memory layout is unspecified (just like it is for an integral type of the same size). This is because different targets could put the padding at different positions when the type size is smaller than the type’s store size." Can we reliably constant-evaluate a `bit_cast` from a vector of a number of bits that's not a multiple of the byte size? https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -7095,6 +7096,40 @@ class APValueToBufferConverter { return true; } + bool visitVector(const APValue , QualType Ty, CharUnits Offset) { +const auto *VT = Ty->castAs(); +unsigned VectorLength = Val.getVectorLength(); + +if (VT->isExtVectorBoolType()) { + // Special handling for OpenCL bool vectors: we need to pack the vector + // of 1-bit unsigned integers into a single integer with the corresponding + // bits set, then write out the resulting integer. + + CharUnits VecWidthBits = Info.Ctx.getTypeSizeInChars(VT) * 8; + + APSInt Bits(VecWidthBits.getQuantity()); + for (unsigned I = 0; I != VectorLength; ++I) { +const APValue = Val.getVectorElt(I); +assert(SubObj.isInt() && "Bool vector element isn't an int?"); +Bits.setBitVal(I, !SubObj.getInt().isZero()); zygoloid wrote: >From what I've found through some experimentation, it looks like: - Vector element 0 is always stored at a lower address than vector element 8. - The actual vector loads and stores operate like integer loads and stores, and in particular, if the vector is narrower than the storage, you get padding beyond the high-order bits. Which I think means that for big-endian systems we want to put vector element `I` in integer bit `VectorLength - I - 1`, so that when we reverse and right-align the bits, we end up with the first vector element in the earlier memory address. That seems to match what's described in https://llvm.org/docs/LangRef.html#vector-type https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -7095,6 +7096,45 @@ class APValueToBufferConverter { return true; } + bool visitVector(const APValue , QualType Ty, CharUnits Offset) { +const auto *VT = Ty->castAs(); +unsigned VectorLength = Val.getVectorLength(); + +if (VT->isExtVectorBoolType()) { + // Special handling for OpenCL bool vectors: we need to pack the vector + // of 1-bit unsigned integers into a single integer with the corresponding + // bits set, then write out the resulting integer. + + CharUnits VecWidthBytes = Info.Ctx.getTypeSizeInChars(VT); + assert(VecWidthBytes.getQuantity() * Info.Ctx.getCharWidth() >= + VectorLength && + "Vector type is smaller than the number of bool elements?"); + + APSInt Bits(VecWidthBytes.getQuantity() * Info.Ctx.getCharWidth()); DaMatrix wrote: I've now changed this, as well as the other identical one further down the file. https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
https://github.com/DaMatrix updated https://github.com/llvm/llvm-project/pull/66894 >From 61f1f5f7325e7cfea8c04ad5c0dea0fdd8c96ab5 Mon Sep 17 00:00:00 2001 From: DaPorkchop_ Date: Sun, 13 Aug 2023 22:39:12 +0200 Subject: [PATCH] [clang] Implement constexpr bit_cast for vectors --- clang/lib/AST/ExprConstant.cpp| 84 ++- .../SemaCXX/constexpr-builtin-bit-cast.cpp| 35 2 files changed, 118 insertions(+), 1 deletion(-) diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index fea06b97259fe31..184d1d15bdc660d 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -7005,10 +7005,11 @@ class APValueToBufferConverter { return visitArray(Val, Ty, Offset); case APValue::Struct: return visitRecord(Val, Ty, Offset); +case APValue::Vector: + return visitVector(Val, Ty, Offset); case APValue::ComplexInt: case APValue::ComplexFloat: -case APValue::Vector: case APValue::FixedPoint: // FIXME: We should support these. @@ -7095,6 +7096,44 @@ class APValueToBufferConverter { return true; } + bool visitVector(const APValue , QualType Ty, CharUnits Offset) { +const auto *VT = Ty->castAs(); +unsigned VectorLength = Val.getVectorLength(); + +if (VT->isExtVectorBoolType()) { + // Special handling for OpenCL bool vectors: we need to pack the vector + // of 1-bit unsigned integers into a single integer with the corresponding + // bits set, then write out the resulting integer. + + unsigned VecWidthBits = Info.Ctx.getTypeSize(VT); + unsigned CharWidth = Info.Ctx.getCharWidth(); + assert(VecWidthBits >= VectorLength && + "Vector type is smaller than the number of bool elements?"); + + APSInt Bits(VecWidthBits); + for (unsigned I = 0; I != VectorLength; ++I) { +const APValue = Val.getVectorElt(I); +assert(SubObj.isInt() && "Bool vector element isn't an int?"); +Bits.setBitVal(I, !SubObj.getInt().isZero()); + } + + SmallVector Bytes(VecWidthBits / CharWidth); + llvm::StoreIntToMemory(Bits, &*Bytes.begin(), VecWidthBits / CharWidth); + Buffer.writeObject(Offset, Bytes); + return true; +} + +CharUnits ElemWidth = Info.Ctx.getTypeSizeInChars(VT->getElementType()); +// Visit each of the vector elements +for (unsigned I = 0; I != VectorLength; ++I) { + const APValue = Val.getVectorElt(I); + if (!visit(SubObj, VT->getElementType(), Offset + I * ElemWidth)) +return false; +} + +return true; + } + bool visitInt(const APSInt , QualType Ty, CharUnits Offset) { APSInt AdjustedVal = Val; unsigned Width = AdjustedVal.getBitWidth(); @@ -7304,6 +7343,49 @@ class BufferToAPValueConverter { return ArrayValue; } + std::optional visit(const VectorType *Ty, CharUnits Offset) { +unsigned NumElements = Ty->getNumElements(); + +SmallVector Elts; +Elts.reserve(NumElements); + +if (Ty->isExtVectorBoolType()) { + // Special handling for OpenCL bool vectors: we need to read + // the individual bits and then unpack them into a vector of 1-bit + // unsigned integers. + + unsigned VecWidthBits = Info.Ctx.getTypeSize(Ty); + assert(VecWidthBits >= NumElements && + "Vector type is smaller than the number of bool elements?"); + + SmallVector Bytes; + if (!Buffer.readObject(Offset, Info.Ctx.getTypeSizeInChars(Ty), Bytes)) +return std::nullopt; + + APSInt Bits(VecWidthBits, true); + llvm::LoadIntFromMemory(Bits, &*Bytes.begin(), Bytes.size()); + + for (unsigned I = 0; I != NumElements; ++I) { +APSInt Bit(1); +Bit = Bits.intersects(APInt::getOneBitSet(Bits.getBitWidth(), I)); +Elts.emplace_back(std::move(Bit)); + } +} else { + CharUnits ElementWidth = + Info.Ctx.getTypeSizeInChars(Ty->getElementType()); + + for (unsigned I = 0; I != NumElements; ++I) { +std::optional ElementValue = +visitType(Ty->getElementType(), Offset + I * ElementWidth); +if (!ElementValue) + return std::nullopt; +Elts.push_back(std::move(*ElementValue)); + } +} + +return APValue(Elts.data(), Elts.size()); + } + std::optional visit(const Type *Ty, CharUnits Offset) { return unsupportedType(QualType(Ty, 0)); } diff --git a/clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp b/clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp index a6ebe0572d063bb..fe7aa51c167fa67 100644 --- a/clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp +++ b/clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp @@ -463,3 +463,38 @@ static_assert(bit_cast(ld539) == fivehundredandthirtynine, ""); static_assert(round_trip<__int128_t>(34.0L)); #endif } + +namespace test_vector { + +typedef unsigned uint2 __attribute__((vector_size(2 * sizeof(unsigned; +typedef char byte8
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
https://github.com/zygoloid resolved https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -7095,6 +7096,45 @@ class APValueToBufferConverter { return true; } + bool visitVector(const APValue , QualType Ty, CharUnits Offset) { +const auto *VT = Ty->castAs(); +unsigned VectorLength = Val.getVectorLength(); + +if (VT->isExtVectorBoolType()) { + // Special handling for OpenCL bool vectors: we need to pack the vector + // of 1-bit unsigned integers into a single integer with the corresponding + // bits set, then write out the resulting integer. + + CharUnits VecWidthBytes = Info.Ctx.getTypeSizeInChars(VT); + assert(VecWidthBytes.getQuantity() * Info.Ctx.getCharWidth() >= + VectorLength && + "Vector type is smaller than the number of bool elements?"); + + APSInt Bits(VecWidthBytes.getQuantity() * Info.Ctx.getCharWidth()); zygoloid wrote: ```suggestion unsigned VecWidthBits = Info.Ctx.getTypeSize(VT); assert(VecWidthBits >= VectorLength && "Vector type is smaller than the number of bool elements?"); APSInt Bits(VecWidthBits); ``` https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -7095,6 +7096,40 @@ class APValueToBufferConverter { return true; } + bool visitVector(const APValue , QualType Ty, CharUnits Offset) { +const auto *VT = Ty->castAs(); +unsigned VectorLength = Val.getVectorLength(); + +if (VT->isExtVectorBoolType()) { + // Special handling for OpenCL bool vectors: we need to pack the vector + // of 1-bit unsigned integers into a single integer with the corresponding + // bits set, then write out the resulting integer. + + CharUnits VecWidthBits = Info.Ctx.getTypeSizeInChars(VT) * 8; + + APSInt Bits(VecWidthBits.getQuantity()); + for (unsigned I = 0; I != VectorLength; ++I) { +const APValue = Val.getVectorElt(I); +assert(SubObj.isInt() && "Bool vector element isn't an int?"); +Bits.setBitVal(I, !SubObj.getInt().isZero()); DaMatrix wrote: It shouldn't be, once the value's been loaded the byte order should be irrelevant. The byte order conversion (if any) appears to be handled automagically by `llvm::StoreIntToMemory` (and its `load` counterpart). https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -7095,6 +7096,40 @@ class APValueToBufferConverter { return true; } + bool visitVector(const APValue , QualType Ty, CharUnits Offset) { +const auto *VT = Ty->castAs(); +unsigned VectorLength = Val.getVectorLength(); + +if (VT->isExtVectorBoolType()) { + // Special handling for OpenCL bool vectors: we need to pack the vector + // of 1-bit unsigned integers into a single integer with the corresponding + // bits set, then write out the resulting integer. + + CharUnits VecWidthBits = Info.Ctx.getTypeSizeInChars(VT) * 8; + + APSInt Bits(VecWidthBits.getQuantity()); DaMatrix wrote: Sorry, I pushed another commit right afterwards in which this is changed to not store bits. Should be correct now https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -7095,6 +7096,40 @@ class APValueToBufferConverter { return true; } + bool visitVector(const APValue , QualType Ty, CharUnits Offset) { +const auto *VT = Ty->castAs(); +unsigned VectorLength = Val.getVectorLength(); + +if (VT->isExtVectorBoolType()) { + // Special handling for OpenCL bool vectors: we need to pack the vector + // of 1-bit unsigned integers into a single integer with the corresponding + // bits set, then write out the resulting integer. + + CharUnits VecWidthBits = Info.Ctx.getTypeSizeInChars(VT) * 8; + + APSInt Bits(VecWidthBits.getQuantity()); zygoloid wrote: ```suggestion APSInt Bits(Info.Ctx.getTypeSize(VT)); ``` You can just ask for the size in bits directly. (Also, please only use `CharUnits` for representing a number of `char` units, not bits.) https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -7095,6 +7096,40 @@ class APValueToBufferConverter { return true; } + bool visitVector(const APValue , QualType Ty, CharUnits Offset) { +const auto *VT = Ty->castAs(); +unsigned VectorLength = Val.getVectorLength(); + +if (VT->isExtVectorBoolType()) { + // Special handling for OpenCL bool vectors: we need to pack the vector + // of 1-bit unsigned integers into a single integer with the corresponding + // bits set, then write out the resulting integer. + + CharUnits VecWidthBits = Info.Ctx.getTypeSizeInChars(VT) * 8; + + APSInt Bits(VecWidthBits.getQuantity()); + for (unsigned I = 0; I != VectorLength; ++I) { +const APValue = Val.getVectorElt(I); +assert(SubObj.isInt() && "Bool vector element isn't an int?"); +Bits.setBitVal(I, !SubObj.getInt().isZero()); zygoloid wrote: Is this endianness-dependent? (I have no idea, but it seems worth checking.) https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -7095,6 +7096,21 @@ class APValueToBufferConverter { return true; } + bool visitVector(const APValue , QualType Ty, CharUnits Offset) { +const auto *VT = Ty->castAs(); + +CharUnits ElemWidth = Info.Ctx.getTypeSizeInChars(VT->getElementType()); +unsigned VectorLength = Val.getVectorLength(); +// Visit each of the vector elements +for (unsigned I = 0; I != VectorLength; ++I) { + const APValue = Val.getVectorElt(I); + if (!visit(SubObj, VT->getElementType(), Offset + I * ElemWidth)) DaMatrix wrote: Ah right, I forgot about those :) The most recent revision should implement that. https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
https://github.com/DaMatrix updated https://github.com/llvm/llvm-project/pull/66894 >From cb7e616dacc1afcdf3357a4a95278479a234be6d Mon Sep 17 00:00:00 2001 From: DaPorkchop_ Date: Sun, 13 Aug 2023 22:39:12 +0200 Subject: [PATCH] [clang] Implement constexpr bit_cast for vectors --- clang/lib/AST/ExprConstant.cpp| 86 ++- .../SemaCXX/constexpr-builtin-bit-cast.cpp| 35 2 files changed, 120 insertions(+), 1 deletion(-) diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index fea06b97259fe31..9612ca5d15c686e 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -7005,10 +7005,11 @@ class APValueToBufferConverter { return visitArray(Val, Ty, Offset); case APValue::Struct: return visitRecord(Val, Ty, Offset); +case APValue::Vector: + return visitVector(Val, Ty, Offset); case APValue::ComplexInt: case APValue::ComplexFloat: -case APValue::Vector: case APValue::FixedPoint: // FIXME: We should support these. @@ -7095,6 +7096,45 @@ class APValueToBufferConverter { return true; } + bool visitVector(const APValue , QualType Ty, CharUnits Offset) { +const auto *VT = Ty->castAs(); +unsigned VectorLength = Val.getVectorLength(); + +if (VT->isExtVectorBoolType()) { + // Special handling for OpenCL bool vectors: we need to pack the vector + // of 1-bit unsigned integers into a single integer with the corresponding + // bits set, then write out the resulting integer. + + CharUnits VecWidthBytes = Info.Ctx.getTypeSizeInChars(VT); + assert(VecWidthBytes.getQuantity() * Info.Ctx.getCharWidth() >= + VectorLength && + "Vector type is smaller than the number of bool elements?"); + + APSInt Bits(VecWidthBytes.getQuantity() * Info.Ctx.getCharWidth()); + for (unsigned I = 0; I != VectorLength; ++I) { +const APValue = Val.getVectorElt(I); +assert(SubObj.isInt() && "Bool vector element isn't an int?"); +Bits.setBitVal(I, !SubObj.getInt().isZero()); + } + + SmallVector Bytes(VecWidthBytes.getQuantity()); + llvm::StoreIntToMemory(Bits, &*Bytes.begin(), + VecWidthBytes.getQuantity()); + Buffer.writeObject(Offset, Bytes); + return true; +} + +CharUnits ElemWidth = Info.Ctx.getTypeSizeInChars(VT->getElementType()); +// Visit each of the vector elements +for (unsigned I = 0; I != VectorLength; ++I) { + const APValue = Val.getVectorElt(I); + if (!visit(SubObj, VT->getElementType(), Offset + I * ElemWidth)) +return false; +} + +return true; + } + bool visitInt(const APSInt , QualType Ty, CharUnits Offset) { APSInt AdjustedVal = Val; unsigned Width = AdjustedVal.getBitWidth(); @@ -7304,6 +7344,50 @@ class BufferToAPValueConverter { return ArrayValue; } + std::optional visit(const VectorType *Ty, CharUnits Offset) { +unsigned NumElements = Ty->getNumElements(); + +SmallVector Elts; +Elts.reserve(NumElements); + +if (Ty->isExtVectorBoolType()) { + // Special handling for OpenCL bool vectors: we need to read + // the individual bits and then unpack them into a vector of 1-bit + // unsigned integers. + + CharUnits VecWidthBytes = Info.Ctx.getTypeSizeInChars(Ty); + assert(VecWidthBytes.getQuantity() * Info.Ctx.getCharWidth() >= + NumElements && + "Vector type is smaller than the number of bool elements?"); + + SmallVector Bytes; + if (!Buffer.readObject(Offset, VecWidthBytes, Bytes)) +return std::nullopt; + + APSInt Bits(VecWidthBytes.getQuantity() * Info.Ctx.getCharWidth(), true); + llvm::LoadIntFromMemory(Bits, &*Bytes.begin(), Bytes.size()); + + for (unsigned I = 0; I != NumElements; ++I) { +APSInt Bit(1); +Bit = Bits.intersects(APInt::getOneBitSet(Bits.getBitWidth(), I)); +Elts.emplace_back(std::move(Bit)); + } +} else { + CharUnits ElementWidth = + Info.Ctx.getTypeSizeInChars(Ty->getElementType()); + + for (unsigned I = 0; I != NumElements; ++I) { +std::optional ElementValue = +visitType(Ty->getElementType(), Offset + I * ElementWidth); +if (!ElementValue) + return std::nullopt; +Elts.push_back(std::move(*ElementValue)); + } +} + +return APValue(Elts.data(), Elts.size()); + } + std::optional visit(const Type *Ty, CharUnits Offset) { return unsupportedType(QualType(Ty, 0)); } diff --git a/clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp b/clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp index a6ebe0572d063bb..fe7aa51c167fa67 100644 --- a/clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp +++ b/clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp @@ -463,3 +463,38 @@ static_assert(bit_cast(ld539) == fivehundredandthirtynine, "");
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
https://github.com/zygoloid resolved https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
https://github.com/DaMatrix updated https://github.com/llvm/llvm-project/pull/66894 >From 99d894e132468a7008e89aaab4847e16b4743bc7 Mon Sep 17 00:00:00 2001 From: DaPorkchop_ Date: Sun, 13 Aug 2023 22:39:12 +0200 Subject: [PATCH] [clang] Implement constexpr bit_cast for vectors --- clang/lib/AST/ExprConstant.cpp| 77 ++- .../SemaCXX/constexpr-builtin-bit-cast.cpp| 35 + 2 files changed, 111 insertions(+), 1 deletion(-) diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index fea06b97259fe31..e84d6214b99d818 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -7005,10 +7005,11 @@ class APValueToBufferConverter { return visitArray(Val, Ty, Offset); case APValue::Struct: return visitRecord(Val, Ty, Offset); +case APValue::Vector: + return visitVector(Val, Ty, Offset); case APValue::ComplexInt: case APValue::ComplexFloat: -case APValue::Vector: case APValue::FixedPoint: // FIXME: We should support these. @@ -7095,6 +7096,40 @@ class APValueToBufferConverter { return true; } + bool visitVector(const APValue , QualType Ty, CharUnits Offset) { +const auto *VT = Ty->castAs(); +unsigned VectorLength = Val.getVectorLength(); + +if (VT->isExtVectorBoolType()) { + // Special handling for OpenCL bool vectors: we need to pack the vector + // of 1-bit unsigned integers into a single integer with the corresponding + // bits set, then write out the resulting integer. + + CharUnits VecWidthBits = Info.Ctx.getTypeSizeInChars(VT) * 8; + + APSInt Bits(VecWidthBits.getQuantity()); + for (unsigned I = 0; I != VectorLength; ++I) { +const APValue = Val.getVectorElt(I); +assert(SubObj.isInt() && "Bool vector element isn't an int?"); +Bits.setBitVal(I, !SubObj.getInt().isZero()); + } + return visit( + APValue(Bits), + Info.Ctx.getIntTypeForBitwidth(Bits.getBitWidth(), Bits.isSigned()), + Offset); +} + +CharUnits ElemWidth = Info.Ctx.getTypeSizeInChars(VT->getElementType()); +// Visit each of the vector elements +for (unsigned I = 0; I != VectorLength; ++I) { + const APValue = Val.getVectorElt(I); + if (!visit(SubObj, VT->getElementType(), Offset + I * ElemWidth)) +return false; +} + +return true; + } + bool visitInt(const APSInt , QualType Ty, CharUnits Offset) { APSInt AdjustedVal = Val; unsigned Width = AdjustedVal.getBitWidth(); @@ -7304,6 +7339,46 @@ class BufferToAPValueConverter { return ArrayValue; } + std::optional visit(const VectorType *Ty, CharUnits Offset) { +unsigned NumElements = Ty->getNumElements(); + +SmallVector Elts; +Elts.reserve(NumElements); + +if (Ty->isExtVectorBoolType()) { + // Special handling for OpenCL bool vectors: we need to read + // the individual bits and then unpack them into a vector of 1-bit + // unsigned integers. + + CharUnits VecWidthBits = Info.Ctx.getTypeSizeInChars(Ty) * 8; + std::optional BitsValue = visitType( + Info.Ctx.getIntTypeForBitwidth(VecWidthBits.getQuantity(), false), + Offset); + if (!BitsValue) +return std::nullopt; + + const APSInt = BitsValue->getInt(); + for (unsigned I = 0; I != NumElements; ++I) { +APSInt Bit(1); +Bit = Bits.intersects(APInt::getOneBitSet(Bits.getBitWidth(), I)); +Elts.emplace_back(std::move(Bit)); + } +} else { + CharUnits ElementWidth = + Info.Ctx.getTypeSizeInChars(Ty->getElementType()); + + for (unsigned I = 0; I != NumElements; ++I) { +std::optional ElementValue = +visitType(Ty->getElementType(), Offset + I * ElementWidth); +if (!ElementValue) + return std::nullopt; +Elts.push_back(std::move(*ElementValue)); + } +} + +return APValue(Elts.data(), Elts.size()); + } + std::optional visit(const Type *Ty, CharUnits Offset) { return unsupportedType(QualType(Ty, 0)); } diff --git a/clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp b/clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp index a6ebe0572d063bb..fe7aa51c167fa67 100644 --- a/clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp +++ b/clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp @@ -463,3 +463,38 @@ static_assert(bit_cast(ld539) == fivehundredandthirtynine, ""); static_assert(round_trip<__int128_t>(34.0L)); #endif } + +namespace test_vector { + +typedef unsigned uint2 __attribute__((vector_size(2 * sizeof(unsigned; +typedef char byte8 __attribute__((vector_size(sizeof(unsigned long long; + +constexpr uint2 test_vector = { 0x0C05FEFE, 0xCAFEBABE }; + +static_assert(bit_cast(test_vector) == (LITTLE_END +? 0xCAFEBABE0C05FEFE +
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
https://github.com/zygoloid commented: Generally this looks good to me, but doesn't seem to properly handle `__attribute__((ext_vector_type(N))) bool`. https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
https://github.com/zygoloid edited https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
@@ -7095,6 +7096,21 @@ class APValueToBufferConverter { return true; } + bool visitVector(const APValue , QualType Ty, CharUnits Offset) { +const auto *VT = Ty->castAs(); + +CharUnits ElemWidth = Info.Ctx.getTypeSizeInChars(VT->getElementType()); +unsigned VectorLength = Val.getVectorLength(); +// Visit each of the vector elements +for (unsigned I = 0; I != VectorLength; ++I) { + const APValue = Val.getVectorElt(I); + if (!visit(SubObj, VT->getElementType(), Offset + I * ElemWidth)) zygoloid wrote: This isn't correct for a vector with element type `bool`, which Clang bit-packs. https://github.com/llvm/llvm-project/pull/66894 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
https://github.com/DaMatrix created https://github.com/llvm/llvm-project/pull/66894 This makes __builtin_bit_cast support converting to and from vector types in a constexpr context. >From d4c7b67eff9997479712f1a25ebb162756d431c6 Mon Sep 17 00:00:00 2001 From: DaPorkchop_ Date: Sun, 13 Aug 2023 22:39:12 +0200 Subject: [PATCH] [clang] Implement constexpr bit_cast for vectors --- clang/lib/AST/ExprConstant.cpp| 34 ++- .../SemaCXX/constexpr-builtin-bit-cast.cpp| 16 + 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index fea06b97259fe31..d58ff10604ee593 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -7005,10 +7005,11 @@ class APValueToBufferConverter { return visitArray(Val, Ty, Offset); case APValue::Struct: return visitRecord(Val, Ty, Offset); +case APValue::Vector: + return visitVector(Val, Ty, Offset); case APValue::ComplexInt: case APValue::ComplexFloat: -case APValue::Vector: case APValue::FixedPoint: // FIXME: We should support these. @@ -7095,6 +7096,21 @@ class APValueToBufferConverter { return true; } + bool visitVector(const APValue , QualType Ty, CharUnits Offset) { +const auto *VT = Ty->castAs(); + +CharUnits ElemWidth = Info.Ctx.getTypeSizeInChars(VT->getElementType()); +unsigned VectorLength = Val.getVectorLength(); +// Visit each of the vector elements +for (unsigned I = 0; I != VectorLength; ++I) { + const APValue = Val.getVectorElt(I); + if (!visit(SubObj, VT->getElementType(), Offset + I * ElemWidth)) +return false; +} + +return true; + } + bool visitInt(const APSInt , QualType Ty, CharUnits Offset) { APSInt AdjustedVal = Val; unsigned Width = AdjustedVal.getBitWidth(); @@ -7304,6 +7320,22 @@ class BufferToAPValueConverter { return ArrayValue; } + std::optional visit(const VectorType *Ty, CharUnits Offset) { +size_t NumElements = Ty->getNumElements(); +CharUnits ElementWidth = Info.Ctx.getTypeSizeInChars(Ty->getElementType()); + +SmallVector Elts; +for (size_t I = 0; I != NumElements; ++I) { + std::optional ElementValue = + visitType(Ty->getElementType(), Offset + I * ElementWidth); + if (!ElementValue) +return std::nullopt; + Elts.push_back(std::move(*ElementValue)); +} + +return APValue(Elts.data(), Elts.size()); + } + std::optional visit(const Type *Ty, CharUnits Offset) { return unsupportedType(QualType(Ty, 0)); } diff --git a/clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp b/clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp index a6ebe0572d063bb..7a45b8624d8011f 100644 --- a/clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp +++ b/clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp @@ -463,3 +463,19 @@ static_assert(bit_cast(ld539) == fivehundredandthirtynine, ""); static_assert(round_trip<__int128_t>(34.0L)); #endif } + +namespace test_vector { + +typedef unsigned uint2 __attribute__((vector_size(2 * sizeof(unsigned; +typedef char byte8 __attribute__((vector_size(sizeof(unsigned long long; + +constexpr uint2 test_vector = { 0x0C05FEFE, 0xCAFEBABE }; + +static_assert(bit_cast(test_vector) == (LITTLE_END +? 0xCAFEBABE0C05FEFE +: 0x0C05FEFECAFEBABE), ""); + +static_assert(round_trip(0xCAFEBABE0C05FEFEULL), ""); +static_assert(round_trip(0xCAFEBABE0C05FEFEULL), ""); + +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits