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

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


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

Get the right offset to apply from the RecordLayout.

>From af62225a90e3dd2ebd234c391a4e05dd1d1d7df9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Thu, 12 Sep 2024 09:36:17 +0200
Subject: [PATCH] [clang][bytecode] Implement base casts on integral pointers

Get the right offset to apply from the RecordLayout.
---
 clang/lib/AST/ByteCode/Interp.h             | 12 +++++++++++
 clang/lib/AST/ByteCode/Pointer.cpp          | 23 +++++++++++++++++++++
 clang/lib/AST/ByteCode/Pointer.h            |  1 +
 clang/test/AST/ByteCode/const-base-cast.cpp | 19 +++++++++++++++++
 clang/test/CodeGenCXX/const-base-cast.cpp   |  2 +-
 5 files changed, 56 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/AST/ByteCode/const-base-cast.cpp

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.



More information about the cfe-commits mailing list