[clang] 8a49af8 - [clang][bytecode] Pass bitfield width directly to opcodes (#188423)

via cfe-commits cfe-commits at lists.llvm.org
Thu Mar 26 22:56:07 PDT 2026


Author: Timm Baeder
Date: 2026-03-27T06:56:03+01:00
New Revision: 8a49af8752021bbabc6f76e657beaf56a4645624

URL: https://github.com/llvm/llvm-project/commit/8a49af8752021bbabc6f76e657beaf56a4645624
DIFF: https://github.com/llvm/llvm-project/commit/8a49af8752021bbabc6f76e657beaf56a4645624.diff

LOG: [clang][bytecode] Pass bitfield width directly to opcodes (#188423)

Pass a `FieldOffset` + `FieldBitWidth` pair instead of a `Record::Field`
pointer.

Added: 
    

Modified: 
    clang/lib/AST/ByteCode/Compiler.cpp
    clang/lib/AST/ByteCode/Interp.h
    clang/lib/AST/ByteCode/Opcodes.td
    clang/lib/AST/ByteCode/Record.h

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index c38eb0fa93877..217ba3663edb0 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -2130,9 +2130,11 @@ bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
 
       bool BitField = FieldToInit->isBitField();
       if (BitField && Activate)
-        return this->emitInitBitFieldActivate(T, FieldToInit, E);
+        return this->emitInitBitFieldActivate(T, FieldToInit->Offset,
+                                              FieldToInit->bitWidth(), E);
       if (BitField)
-        return this->emitInitBitField(T, FieldToInit, E);
+        return this->emitInitBitField(T, FieldToInit->Offset,
+                                      FieldToInit->bitWidth(), E);
       if (Activate)
         return this->emitInitFieldActivate(T, FieldToInit->Offset, E);
       return this->emitInitField(T, FieldToInit->Offset, E);
@@ -5361,7 +5363,8 @@ bool Compiler<Emitter>::visitAPValueInitializer(const APValue &Val,
       if (!this->visitAPValue(F, *PT, E))
         return false;
       if (RF->isBitField())
-        return this->emitInitBitFieldActivate(*PT, RF, E);
+        return this->emitInitBitFieldActivate(*PT, RF->Offset, RF->bitWidth(),
+                                              E);
       return this->emitInitFieldActivate(*PT, RF->Offset, E);
     }
 
@@ -6669,9 +6672,9 @@ bool Compiler<Emitter>::compileConstructor(const CXXConstructorDecl *Ctor) {
       if (!this->visit(InitExpr))
         return false;
 
-      bool BitField = F->isBitField();
-      if (BitField)
-        return this->emitInitThisBitField(*T, F, FieldOffset, InitExpr);
+      if (F->isBitField())
+        return this->emitInitThisBitField(*T, FieldOffset, F->bitWidth(),
+                                          InitExpr);
       return this->emitInitThisField(*T, FieldOffset, InitExpr);
     }
     // Non-primitive case. Get a pointer to the field-to-initialize

diff  --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 5b6d1bb18fff4..90dc88c1dbde7 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -1659,9 +1659,9 @@ bool InitThisFieldActivate(InterpState &S, CodePtr OpPC, uint32_t I) {
 // FIXME: The Field pointer here is too much IMO and we could instead just
 // pass an Offset + BitWidth pair.
 template <PrimType Name, class T = typename PrimConv<Name>::T>
-bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F,
-                      uint32_t FieldOffset) {
-  assert(F->isBitField());
+bool InitThisBitField(InterpState &S, CodePtr OpPC,
+                      uint32_t FieldOffset, // const Record::Field *F,
+                      uint32_t FieldBitWidth) {
   if (S.checkingPotentialConstantExpression() && S.Current->getDepth() == 0)
     return false;
   if (!CheckThis(S, OpPC))
@@ -1670,15 +1670,14 @@ bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F,
   const Pointer &Field = This.atField(FieldOffset);
   assert(Field.canBeInitialized());
   const auto &Value = S.Stk.pop<T>();
-  Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue());
+  Field.deref<T>() = Value.truncate(FieldBitWidth);
   Field.initialize();
   return true;
 }
 
 template <PrimType Name, class T = typename PrimConv<Name>::T>
 bool InitThisBitFieldActivate(InterpState &S, CodePtr OpPC,
-                              const Record::Field *F, uint32_t FieldOffset) {
-  assert(F->isBitField());
+                              uint32_t FieldOffset, uint32_t FieldBitWidth) {
   if (S.checkingPotentialConstantExpression() && S.Current->getDepth() == 0)
     return false;
   if (!CheckThis(S, OpPC))
@@ -1687,7 +1686,7 @@ bool InitThisBitFieldActivate(InterpState &S, CodePtr OpPC,
   const Pointer &Field = This.atField(FieldOffset);
   assert(Field.canBeInitialized());
   const auto &Value = S.Stk.pop<T>();
-  Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue());
+  Field.deref<T>() = Value.truncate(FieldBitWidth);
   Field.initialize();
   Field.activate();
   return true;
@@ -1728,8 +1727,8 @@ bool InitFieldActivate(InterpState &S, CodePtr OpPC, uint32_t I) {
 }
 
 template <PrimType Name, class T = typename PrimConv<Name>::T>
-bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
-  assert(F->isBitField());
+bool InitBitField(InterpState &S, CodePtr OpPC, uint32_t FieldOffset,
+                  uint32_t FieldBitWidth) {
   const T &Value = S.Stk.pop<T>();
   const Pointer &Ptr = S.Stk.peek<Pointer>();
   if (!CheckRange(S, OpPC, Ptr, CSK_Field))
@@ -1737,9 +1736,9 @@ bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
   if (!CheckArray(S, OpPC, Ptr))
     return false;
 
-  const Pointer &Field = Ptr.atField(F->Offset);
+  const Pointer &Field = Ptr.atField(FieldOffset);
 
-  unsigned BitWidth = std::min(F->Decl->getBitWidthValue(), Value.bitWidth());
+  unsigned BitWidth = std::min(FieldBitWidth, Value.bitWidth());
   if constexpr (needsAlloc<T>()) {
     T Result = S.allocAP<T>(Value.bitWidth());
     if constexpr (T::isSigned())
@@ -1751,16 +1750,15 @@ bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
 
     Field.deref<T>() = Result;
   } else {
-    Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue());
+    Field.deref<T>() = Value.truncate(FieldBitWidth);
   }
   Field.initialize();
   return true;
 }
 
 template <PrimType Name, class T = typename PrimConv<Name>::T>
-bool InitBitFieldActivate(InterpState &S, CodePtr OpPC,
-                          const Record::Field *F) {
-  assert(F->isBitField());
+bool InitBitFieldActivate(InterpState &S, CodePtr OpPC, uint32_t FieldOffset,
+                          uint32_t FieldBitWidth) {
   const T &Value = S.Stk.pop<T>();
   const Pointer &Ptr = S.Stk.peek<Pointer>();
   if (!CheckRange(S, OpPC, Ptr, CSK_Field))
@@ -1768,9 +1766,9 @@ bool InitBitFieldActivate(InterpState &S, CodePtr OpPC,
   if (!CheckArray(S, OpPC, Ptr))
     return false;
 
-  const Pointer &Field = Ptr.atField(F->Offset);
+  const Pointer &Field = Ptr.atField(FieldOffset);
 
-  unsigned BitWidth = std::min(F->Decl->getBitWidthValue(), Value.bitWidth());
+  unsigned BitWidth = std::min(FieldBitWidth, Value.bitWidth());
   if constexpr (needsAlloc<T>()) {
     T Result = S.allocAP<T>(Value.bitWidth());
     if constexpr (T::isSigned())
@@ -1782,7 +1780,7 @@ bool InitBitFieldActivate(InterpState &S, CodePtr OpPC,
 
     Field.deref<T>() = Result;
   } else {
-    Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue());
+    Field.deref<T>() = Value.truncate(FieldBitWidth);
   }
   Field.activate();
   Field.initialize();

diff  --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td
index 5fbd35950c0eb..5e4d0ab2a84af 100644
--- a/clang/lib/AST/ByteCode/Opcodes.td
+++ b/clang/lib/AST/ByteCode/Opcodes.td
@@ -417,7 +417,8 @@ class AccessOpcode : Opcode {
 
 class BitFieldOpcode : Opcode {
   let Types = [IntegralTypeClass];
-  let Args = [ArgRecordField];
+  //          FieldOffset, FieldBitWidth
+  let Args = [ArgUint32, ArgUint32];
   let HasGroup = 1;
 }
 
@@ -485,16 +486,7 @@ def SetThisField : AccessOpcode;
 def InitThisField : AccessOpcode;
 def InitThisFieldActivate : AccessOpcode;
 // [Value] -> []
-def InitThisBitField : Opcode {
-  let Types = [AluTypeClass];
-  let Args = [ArgRecordField, ArgUint32];
-  let HasGroup = 1;
-}
-def InitThisBitFieldActivate : Opcode {
-  let Types = [AluTypeClass];
-  let Args = [ArgRecordField, ArgUint32];
-  let HasGroup = 1;
-}
+def InitThisBitField : BitFieldOpcode;
 // [Pointer, Value] -> []
 def InitField : AccessOpcode;
 def InitFieldActivate : AccessOpcode;

diff  --git a/clang/lib/AST/ByteCode/Record.h b/clang/lib/AST/ByteCode/Record.h
index e43f683364e26..c0c10f72ae3ee 100644
--- a/clang/lib/AST/ByteCode/Record.h
+++ b/clang/lib/AST/ByteCode/Record.h
@@ -32,6 +32,10 @@ class Record final {
 
     bool isBitField() const { return Decl->isBitField(); }
     bool isUnnamedBitField() const { return Decl->isUnnamedBitField(); }
+    unsigned bitWidth() const {
+      assert(isBitField());
+      return Decl->getBitWidthValue();
+    }
 
     Field(const FieldDecl *D, const Descriptor *Desc, unsigned Offset)
         : Decl(D), Desc(Desc), Offset(Offset) {}


        


More information about the cfe-commits mailing list