[clang] [clang][bytecode] Implement base casts on integral pointers (PR #108340)

via cfe-commits cfe-commits at lists.llvm.org
Thu Sep 12 00:41:53 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Timm Baeder (tbaederr)

<details>
<summary>Changes</summary>

Get the right offset to apply from the RecordLayout.

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


5 Files Affected:

- (modified) clang/lib/AST/ByteCode/Interp.h (+12) 
- (modified) clang/lib/AST/ByteCode/Pointer.cpp (+23) 
- (modified) clang/lib/AST/ByteCode/Pointer.h (+1) 
- (added) clang/test/AST/ByteCode/const-base-cast.cpp (+19) 
- (modified) clang/test/CodeGenCXX/const-base-cast.cpp (+1-1) 


``````````diff
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 7b7c7822e4a925..3d507e2e2ba764 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -1611,6 +1611,12 @@ inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off) {
 
 inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
   const Pointer &Ptr = S.Stk.peek<Pointer>();
+
+  if (!Ptr.isBlockPointer()) {
+    S.Stk.push<Pointer>(Ptr.asIntPointer().baseCast(S.getASTContext(), Off));
+    return true;
+  }
+
   if (!CheckNull(S, OpPC, Ptr, CSK_Base))
     return false;
   if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
@@ -1624,6 +1630,12 @@ inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
 
 inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off) {
   const Pointer &Ptr = S.Stk.pop<Pointer>();
+
+  if (!Ptr.isBlockPointer()) {
+    S.Stk.push<Pointer>(Ptr.asIntPointer().baseCast(S.getASTContext(), Off));
+    return true;
+  }
+
   if (!CheckNull(S, OpPC, Ptr, CSK_Base))
     return false;
   if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp
index 9eaf0db45c7451..282953eb991a6b 100644
--- a/clang/lib/AST/ByteCode/Pointer.cpp
+++ b/clang/lib/AST/ByteCode/Pointer.cpp
@@ -667,3 +667,26 @@ IntPointer IntPointer::atOffset(const ASTContext &ASTCtx,
           .getQuantity();
   return IntPointer{this->Desc, this->Value + FieldOffset};
 }
+
+IntPointer IntPointer::baseCast(const ASTContext &ASTCtx,
+                                unsigned BaseOffset) const {
+  const Record *R = Desc->ElemRecord;
+  const Descriptor *BaseDesc = nullptr;
+
+  // This iterates over bases and checks for the proper offset. That's
+  // potentially slow but this case really shouldn't happen a lot.
+  for (const Record::Base &B : R->bases()) {
+    if (B.Offset == BaseOffset) {
+      BaseDesc = B.Desc;
+      break;
+    }
+  }
+  assert(BaseDesc);
+
+  // Adjust the offset value based on the information from the record layout.
+  const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(R->getDecl());
+  CharUnits BaseLayoutOffset =
+      Layout.getBaseClassOffset(cast<CXXRecordDecl>(BaseDesc->asDecl()));
+
+  return {BaseDesc, Value + BaseLayoutOffset.getQuantity()};
+}
diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h
index acbef437752388..ac9b9ed4091b66 100644
--- a/clang/lib/AST/ByteCode/Pointer.h
+++ b/clang/lib/AST/ByteCode/Pointer.h
@@ -46,6 +46,7 @@ struct IntPointer {
   uint64_t Value;
 
   IntPointer atOffset(const ASTContext &ASTCtx, unsigned Offset) const;
+  IntPointer baseCast(const ASTContext &ASTCtx, unsigned BaseOffset) const;
 };
 
 enum class Storage { Block, Int, Fn };
diff --git a/clang/test/AST/ByteCode/const-base-cast.cpp b/clang/test/AST/ByteCode/const-base-cast.cpp
new file mode 100644
index 00000000000000..80226b973bf977
--- /dev/null
+++ b/clang/test/AST/ByteCode/const-base-cast.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm %s -o - -fexperimental-new-constant-interpreter | FileCheck %s
+
+
+/// Slightly adapted to the version from test/CodeGenCXX/.
+
+struct X { int x[12];};
+struct A : X { char x, y, z; };
+struct B { char y; };
+struct C : A,B {};
+unsigned char x = ((char*)(X*)(C*)0x1000) - (char*)0x1000;
+// CHECK: @x = {{(dso_local )?}}global i8 0
+
+unsigned char y = ((char*)(B*)(C*)0x1000) - (char*)0x1000;
+// CHECK: @y = {{(dso_local )?}}global i8 51
+
+unsigned char z = ((char*)(A*)(C*)0x1000) - (char*)0x1000;
+// CHECK: @z = {{(dso_local )?}}global i8 0
+
diff --git a/clang/test/CodeGenCXX/const-base-cast.cpp b/clang/test/CodeGenCXX/const-base-cast.cpp
index bb08b9d21fcfce..7f2c66e6ca0886 100644
--- a/clang/test/CodeGenCXX/const-base-cast.cpp
+++ b/clang/test/CodeGenCXX/const-base-cast.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm %s -o - -fexperimental-new-constant-interpreter | FileCheck %s
 
 // Check that the following construct, which is similar to one which occurs
 // in Firefox, is folded correctly.

``````````

</details>


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


More information about the cfe-commits mailing list