Timm =?utf-8?q?Bäder?= <tbae...@redhat.com>,
Timm =?utf-8?q?Bäder?= <tbae...@redhat.com>,
Timm =?utf-8?q?Bäder?= <tbae...@redhat.com>,
Timm =?utf-8?q?Bäder?= <tbae...@redhat.com>,
Timm =?utf-8?q?Bäder?= <tbae...@redhat.com>,
Timm =?utf-8?q?Bäder?= <tbae...@redhat.com>,
Timm =?utf-8?q?Bäder?= <tbae...@redhat.com>,
Timm =?utf-8?q?Bäder?= <tbae...@redhat.com>,
Timm =?utf-8?q?Bäder?= <tbae...@redhat.com>,
Timm =?utf-8?q?Bäder?= <tbae...@redhat.com>,
Timm =?utf-8?q?Bäder?= <tbae...@redhat.com>,
Timm =?utf-8?q?Bäder?= <tbae...@redhat.com>,
Timm =?utf-8?q?Bäder?= <tbae...@redhat.com>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/68...@github.com>


================
@@ -0,0 +1,452 @@
+//===--- InterpBitcast.cpp - Interpreter for the constexpr VM ---*- C++ 
-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#include "Boolean.h"
+#include "Interp.h"
+#include "PrimType.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/Basic/Builtins.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/BitVector.h"
+
+namespace clang {
+namespace interp {
+
+/// Used to iterate over pointer fields.
+using DataFunc =
+    llvm::function_ref<bool(const Pointer &P, PrimType Ty, size_t BitOffset)>;
+
+#define BITCAST_TYPE_SWITCH(Expr, B)                                           
\
+  do {                                                                         
\
+    switch (Expr) {                                                            
\
+      TYPE_SWITCH_CASE(PT_Sint8, B)                                            
\
+      TYPE_SWITCH_CASE(PT_Uint8, B)                                            
\
+      TYPE_SWITCH_CASE(PT_Sint16, B)                                           
\
+      TYPE_SWITCH_CASE(PT_Uint16, B)                                           
\
+      TYPE_SWITCH_CASE(PT_Sint32, B)                                           
\
+      TYPE_SWITCH_CASE(PT_Uint32, B)                                           
\
+      TYPE_SWITCH_CASE(PT_Sint64, B)                                           
\
+      TYPE_SWITCH_CASE(PT_Uint64, B)                                           
\
+      TYPE_SWITCH_CASE(PT_IntAP, B)                                            
\
+      TYPE_SWITCH_CASE(PT_IntAPS, B)                                           
\
+      TYPE_SWITCH_CASE(PT_Bool, B)                                             
\
+    default:                                                                   
\
+      llvm_unreachable("Unhandled bitcast type");                              
\
+    }                                                                          
\
+  } while (0)
+
+/// Float is a special case that sometimes needs the floating point semantics
+/// to be available.
+#define BITCAST_TYPE_SWITCH_WITH_FLOAT(Expr, B)                                
\
+  do {                                                                         
\
+    switch (Expr) {                                                            
\
+      TYPE_SWITCH_CASE(PT_Sint8, B)                                            
\
+      TYPE_SWITCH_CASE(PT_Uint8, B)                                            
\
+      TYPE_SWITCH_CASE(PT_Sint16, B)                                           
\
+      TYPE_SWITCH_CASE(PT_Uint16, B)                                           
\
+      TYPE_SWITCH_CASE(PT_Sint32, B)                                           
\
+      TYPE_SWITCH_CASE(PT_Uint32, B)                                           
\
+      TYPE_SWITCH_CASE(PT_Sint64, B)                                           
\
+      TYPE_SWITCH_CASE(PT_Uint64, B)                                           
\
+      TYPE_SWITCH_CASE(PT_IntAP, B)                                            
\
+      TYPE_SWITCH_CASE(PT_IntAPS, B)                                           
\
+      TYPE_SWITCH_CASE(PT_Bool, B)                                             
\
+      TYPE_SWITCH_CASE(PT_Float, B)                                            
\
+    default:                                                                   
\
+      llvm_unreachable("Unhandled bitcast type");                              
\
+    }                                                                          
\
+  } while (0)
+
+/// Rotate things around for big endian targets.
+static void swapBytes(std::byte *M, size_t N) {
+  for (size_t I = 0; I != (N / 2); ++I)
+    std::swap(M[I], M[N - 1 - I]);
+}
+
+/// Track what bits have been initialized to known values and which ones
+/// have indeterminate value.
+/// All offsets are in bits.
+struct BitTracker {
+  llvm::BitVector Initialized;
+  llvm::BitVector Data;
----------------
sethp wrote:

I tried `llvm::BitVector` to work for me in #74775 , but it was a little 
awkward; the operations that I ended up wanting from the buffer's backing store 
for (cross-endian) bit fields were:

* [`getBits(src, [start, 
end])`](https://github.com/llvm/llvm-project/blob/2e0d3f81e4f5b623bb476bfac0278cfc6d1bd4bc/clang/lib/AST/ExprConstant.cpp#L7114)
 , which looks very much like what `getBytes` here would need (at a byte 
granularity)
* [`copyBitsFrom(dst, [dstStart, dstEnd], src, 
...)`](https://github.com/llvm/llvm-project/blob/2e0d3f81e4f5b623bb476bfac0278cfc6d1bd4bc/clang/lib/AST/ExprConstant.cpp#L7126-L7127),
 i.e. `pushData`'s bread and butter
* [`clearBits(dst, [start, 
end])`](https://github.com/llvm/llvm-project/blob/2e0d3f81e4f5b623bb476bfac0278cfc6d1bd4bc/clang/lib/AST/ExprConstant.cpp#L7139),
 this started off being `setBits`; it's basically the same underlying op for 
`markUninitializedUntil`

I ended up going with `APInt` as the alternate spelling for `BitVector` because 
it exposed those operations more or less directly (as `extractBits`, 
`insertBits`, and `~setBits` respectively), and it meant two fewer copies to 
get data into & out of the buffer—especially after extending `copyBitsFrom` to 
take a `[srcStart, srcEnd]` range.

Plus, it ended up being very helpful to use the bit-twiddling operators 
(`&`/`|`/`~`/ `<<`, etc.) at least in the prototype/debugging stages to get my 
head around what was going on, but more on that later.

The main difference that I saw (besides APInt supporting far more operations) 
was that `BitVector`s were grow-able, but I'm not sure that helps here: we 
should know the size of the object at BitTracker-initialization time, right?

Here, I think another difference is that the end "pointer" of the BitVector is 
keeping track of where to write to next; I like that, though it'll take some 
care to make sure it works with cross-endian bit-fields I think. Either way, 
`BitTracker` could also offer that simply by tracking its own bit-sized end 
pointer.

https://github.com/llvm/llvm-project/pull/68288
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to