[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)

2023-10-30 Thread Richard Smith via cfe-commits

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)

2023-10-30 Thread via cfe-commits

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)

2023-10-24 Thread Richard Smith via cfe-commits

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)

2023-10-24 Thread via cfe-commits

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)

2023-10-24 Thread via cfe-commits

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)

2023-10-21 Thread Richard Smith via cfe-commits


@@ -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)

2023-10-21 Thread via cfe-commits


@@ -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)

2023-10-21 Thread via cfe-commits


@@ -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)

2023-10-20 Thread Richard Smith via cfe-commits


@@ -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)

2023-10-20 Thread Richard Smith via cfe-commits

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)

2023-10-20 Thread Richard Smith via cfe-commits

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)

2023-10-19 Thread via cfe-commits

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)

2023-10-11 Thread Richard Smith via cfe-commits


@@ -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)

2023-10-11 Thread via cfe-commits


@@ -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)

2023-10-11 Thread Richard Smith via cfe-commits

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)

2023-10-11 Thread Richard Smith via cfe-commits


@@ -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)

2023-10-11 Thread Richard Smith via cfe-commits

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)

2023-10-11 Thread Richard Smith via cfe-commits


@@ -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)

2023-10-11 Thread Richard Smith via cfe-commits


@@ -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)

2023-10-11 Thread Richard Smith via cfe-commits


@@ -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)

2023-10-11 Thread Richard Smith via cfe-commits

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)

2023-10-10 Thread via cfe-commits

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)

2023-10-09 Thread via cfe-commits

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)

2023-10-05 Thread via cfe-commits


@@ -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)

2023-10-05 Thread via cfe-commits


@@ -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)

2023-10-04 Thread Richard Smith via cfe-commits


@@ -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)

2023-10-04 Thread Richard Smith via cfe-commits

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)

2023-10-04 Thread Richard Smith via cfe-commits


@@ -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)

2023-10-04 Thread Richard Smith via cfe-commits

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)

2023-10-04 Thread Richard Smith via cfe-commits


@@ -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)

2023-10-03 Thread via cfe-commits

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)

2023-10-03 Thread via cfe-commits

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)

2023-10-03 Thread via cfe-commits


@@ -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)

2023-10-01 Thread Richard Smith via cfe-commits


@@ -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)

2023-09-29 Thread via cfe-commits


@@ -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)

2023-09-29 Thread via cfe-commits


@@ -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)

2023-09-27 Thread Richard Smith via cfe-commits

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)

2023-09-27 Thread Richard Smith via cfe-commits


@@ -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)

2023-09-27 Thread Richard Smith via cfe-commits

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)

2023-09-27 Thread Richard Smith via cfe-commits


@@ -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)

2023-09-27 Thread Richard Smith via cfe-commits


@@ -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)

2023-09-27 Thread Richard Smith via cfe-commits


@@ -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)

2023-09-27 Thread Richard Smith via cfe-commits


@@ -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)

2023-09-27 Thread Richard Smith via cfe-commits


@@ -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)

2023-09-27 Thread Richard Smith via cfe-commits


@@ -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)

2023-09-27 Thread Richard Smith via cfe-commits

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)

2023-09-27 Thread Richard Smith via cfe-commits

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)

2023-09-24 Thread via cfe-commits


@@ -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)

2023-09-24 Thread via cfe-commits


@@ -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)

2023-09-24 Thread via cfe-commits

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)

2023-09-24 Thread via cfe-commits

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)

2023-09-22 Thread Richard Smith via cfe-commits


@@ -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)

2023-09-22 Thread via cfe-commits


@@ -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)

2023-09-22 Thread via cfe-commits

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)

2023-09-22 Thread via cfe-commits


@@ -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)

2023-09-22 Thread via cfe-commits


@@ -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)

2023-09-21 Thread Richard Smith via cfe-commits


@@ -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)

2023-09-21 Thread Richard Smith via cfe-commits

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)

2023-09-21 Thread Richard Smith via cfe-commits


@@ -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)

2023-09-21 Thread Richard Smith via cfe-commits


@@ -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)

2023-09-21 Thread via cfe-commits


@@ -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)

2023-09-21 Thread via cfe-commits

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)

2023-09-21 Thread Richard Smith via cfe-commits

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)

2023-09-21 Thread Richard Smith via cfe-commits


@@ -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)

2023-09-21 Thread via cfe-commits


@@ -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)

2023-09-21 Thread via cfe-commits


@@ -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)

2023-09-21 Thread Richard Smith via cfe-commits


@@ -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)

2023-09-21 Thread Richard Smith via cfe-commits


@@ -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)

2023-09-21 Thread via cfe-commits


@@ -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)

2023-09-21 Thread via cfe-commits

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)

2023-09-21 Thread Richard Smith via cfe-commits

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)

2023-09-21 Thread via cfe-commits

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)

2023-09-20 Thread Richard Smith via cfe-commits

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)

2023-09-20 Thread Richard Smith via cfe-commits

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)

2023-09-20 Thread Richard Smith via cfe-commits


@@ -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)

2023-09-20 Thread via cfe-commits

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