[clang] [clang][bytecode] Support bitcasting into float fields (PR #114825)

via cfe-commits cfe-commits at lists.llvm.org
Mon Nov 4 08:26:50 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Timm Baeder (tbaederr)

<details>
<summary>Changes</summary>



---
Full diff: https://github.com/llvm/llvm-project/pull/114825.diff


4 Files Affected:

- (modified) clang/lib/AST/ByteCode/Compiler.cpp (+1-1) 
- (modified) clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp (+19-3) 
- (modified) clang/test/AST/ByteCode/builtin-bit-cast-long-double.cpp (+10-3) 
- (modified) clang/test/AST/ByteCode/builtin-bit-cast.cpp (+19) 


``````````diff
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 35116952901684..396213c7b2ae0e 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -2735,7 +2735,7 @@ bool Compiler<Emitter>::VisitMaterializeTemporaryExpr(
       InitLinkScope<Emitter> ILS(this, InitLink::Temp(*LocalIndex));
       if (!this->emitGetPtrLocal(*LocalIndex, E))
         return false;
-      return this->visitInitializer(SubExpr);
+      return this->visitInitializer(SubExpr) && this->emitFinishInit(E);
     }
   }
   return false;
diff --git a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp
index dd02eb25c3fa1f..e1de151af3e021 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp
@@ -397,19 +397,35 @@ bool clang::interp::DoBitCastPtr(InterpState &S, CodePtr OpPC,
                       /*ReturnOnUninit=*/false);
 
   // Now read the values out of the buffer again and into ToPtr.
+  const ASTContext &ASTCtx = S.getASTContext();
   size_t BitOffset = 0;
   bool Success = enumeratePointerFields(
       ToPtr, S.getContext(),
       [&](const Pointer &P, PrimType T, size_t _) -> bool {
-        BITCAST_TYPE_SWITCH_FIXED_SIZE(T, {
-          T &Val = P.deref<T>();
+        if (T == PT_Float) {
+          CharUnits ObjectReprChars = ASTCtx.getTypeSizeInChars(P.getType());
+          const auto &Semantics = ASTCtx.getFloatTypeSemantics(P.getType());
+          unsigned NumBits = llvm::APFloatBase::getSizeInBits(Semantics);
+          assert(NumBits % 8 == 0);
+          assert(NumBits <= ASTCtx.toBits(ObjectReprChars));
+          std::byte *M = Buffer.getBytes(BitOffset);
+
+          if (llvm::sys::IsBigEndianHost)
+            swapBytes(M, NumBits / 8);
 
+          P.deref<Floating>() = Floating::bitcastFromMemory(M, Semantics);
+          P.initialize();
+          BitOffset += ASTCtx.toBits(ObjectReprChars);
+          return true;
+        }
+
+        BITCAST_TYPE_SWITCH_FIXED_SIZE(T, {
           std::byte *M = Buffer.getBytes(BitOffset);
 
           if (llvm::sys::IsBigEndianHost)
             swapBytes(M, T::bitWidth() / 8);
 
-          Val = T::bitcastFromMemory(M, T::bitWidth());
+          P.deref<T>() = T::bitcastFromMemory(M, T::bitWidth());
           P.initialize();
           BitOffset += T::bitWidth();
         });
diff --git a/clang/test/AST/ByteCode/builtin-bit-cast-long-double.cpp b/clang/test/AST/ByteCode/builtin-bit-cast-long-double.cpp
index 230680ff3ced7d..0929f7cb70b744 100644
--- a/clang/test/AST/ByteCode/builtin-bit-cast-long-double.cpp
+++ b/clang/test/AST/ByteCode/builtin-bit-cast-long-double.cpp
@@ -45,7 +45,7 @@ struct bytes {
   unsigned char d[16];
 };
 
-// static_assert(round_trip<bytes>(ld), "");
+static_assert(round_trip<bytes>(ld), "");
 
 static_assert(round_trip<long double>(10.0L));
 
@@ -77,10 +77,17 @@ constexpr bytes ld539 = {
   0x8, 0x40, 0x0,  0x0,
   0x0, 0x0,  0x0,  0x0,
 };
-
 constexpr long double fivehundredandthirtynine = 539.0;
-
 static_assert(bit_cast<long double>(ld539) == fivehundredandthirtynine, "");
+
+struct LD {
+  long double v;
+};
+
+constexpr LD ld2 = __builtin_bit_cast(LD, ld539.d);
+constexpr long double five39 = __builtin_bit_cast(long double, ld539.d);
+static_assert(ld2.v == five39);
+
 #else
 static_assert(round_trip<__int128_t>(34.0L));
 #endif
diff --git a/clang/test/AST/ByteCode/builtin-bit-cast.cpp b/clang/test/AST/ByteCode/builtin-bit-cast.cpp
index 50382399eefc9c..0c55155ec64a24 100644
--- a/clang/test/AST/ByteCode/builtin-bit-cast.cpp
+++ b/clang/test/AST/ByteCode/builtin-bit-cast.cpp
@@ -467,3 +467,22 @@ struct ref_mem {
 // both-error at +2 {{constexpr variable 'run_ref_mem' must be initialized by a constant expression}}
 // both-note at +1 {{bit_cast from a type with a reference member is not allowed in a constant expression}}
 constexpr intptr_t run_ref_mem = __builtin_bit_cast(intptr_t, ref_mem{global_int});
+
+
+
+
+namespace test_complex {
+  constexpr _Complex unsigned test_int_complex = { 0x0C05FEFE, 0xCAFEBABE };
+  static_assert(round_trip<_Complex unsigned>(0xCAFEBABE0C05FEFEULL), "");
+  static_assert(bit_cast<unsigned long long>(test_int_complex) == (LITTLE_END
+                                                                   ? 0xCAFEBABE0C05FEFE
+                                                                   : 0x0C05FEFECAFEBABE), "");
+  static_assert(sizeof(double) == 2 * sizeof(float));
+  struct TwoFloats { float A; float B; };
+  constexpr _Complex float test_float_complex = {1.0f, 2.0f};
+  constexpr TwoFloats TF = __builtin_bit_cast(TwoFloats, test_float_complex);
+  static_assert(TF.A == 1.0f && TF.B == 2.0f);
+
+  constexpr double D = __builtin_bit_cast(double, test_float_complex);
+  constexpr int M = __builtin_bit_cast(int, test_int_complex); // both-error {{__builtin_bit_cast source size does not equal destination size}}
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/114825


More information about the cfe-commits mailing list