[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