https://github.com/andykaylor created 
https://github.com/llvm/llvm-project/pull/167370

This adds handling in CIR's ScalarExprEmitter for CK_DerivedToBase cast 
expressions.

>From 719dfa81f765367f7de62933f4e983ba636d5328 Mon Sep 17 00:00:00 2001
From: Andy Kaylor <[email protected]>
Date: Fri, 7 Nov 2025 15:36:49 -0800
Subject: [PATCH] [CIR] Handle scalar DerivedToBase cast expressions

This adds handling in CIR's ScalarExprEmitter for CK_DerivedToBase cast
expressions.
---
 clang/include/clang/CIR/MissingFeatures.h   |   1 +
 clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp  |   8 ++
 clang/lib/CIR/CodeGen/CIRGenFunction.h      |   6 +
 clang/lib/CIR/CodeGen/CIRGenPointerAuth.cpp |  23 ++++
 clang/lib/CIR/CodeGen/CMakeLists.txt        |   1 +
 clang/test/CIR/CodeGen/derived-to-base.cpp  | 129 ++++++++++++++++++++
 6 files changed, 168 insertions(+)
 create mode 100644 clang/lib/CIR/CodeGen/CIRGenPointerAuth.cpp
 create mode 100644 clang/test/CIR/CodeGen/derived-to-base.cpp

diff --git a/clang/include/clang/CIR/MissingFeatures.h 
b/clang/include/clang/CIR/MissingFeatures.h
index af1ffffcf54c0..3f6fab0447445 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -294,6 +294,7 @@ struct MissingFeatures {
   static bool opTBAA() { return false; }
   static bool peepholeProtection() { return false; }
   static bool pgoUse() { return false; }
+  static bool pointerAuthentication() { return false; }
   static bool pointerOverflowSanitizer() { return false; }
   static bool preservedAccessIndexRegion() { return false; }
   static bool requiresCleanups() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 5eba5ba6c3df1..3f40cf0c0027a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -1929,6 +1929,14 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr 
*ce) {
     return builder.createIntToPtr(middleVal, destCIRTy);
   }
 
+  case CK_UncheckedDerivedToBase:
+  case CK_DerivedToBase: {
+    // The EmitPointerWithAlignment path does this fine; just discard
+    // the alignment.
+    return cgf.getAsNaturalPointerTo(cgf.emitPointerWithAlignment(ce),
+                                     ce->getType()->getPointeeType());
+  }
+
   case CK_Dynamic: {
     Address v = cgf.emitPointerWithAlignment(subExpr);
     const auto *dce = cast<CXXDynamicCastExpr>(ce);
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index f879e580989f7..cab4a3d4d3b25 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -497,6 +497,12 @@ class CIRGenFunction : public CIRGenTypeCache {
   VlaSizePair getVLASize(const VariableArrayType *type);
   VlaSizePair getVLASize(QualType type);
 
+  Address getAsNaturalAddressOf(Address addr, QualType pointeeTy);
+
+  mlir::Value getAsNaturalPointerTo(Address addr, QualType pointeeType) {
+    return getAsNaturalAddressOf(addr, pointeeType).getBasePointer();
+  }
+
   void finishFunction(SourceLocation endLoc);
 
   /// Determine whether the given initializer is trivial in the sense
diff --git a/clang/lib/CIR/CodeGen/CIRGenPointerAuth.cpp 
b/clang/lib/CIR/CodeGen/CIRGenPointerAuth.cpp
new file mode 100644
index 0000000000000..20b0646fdab44
--- /dev/null
+++ b/clang/lib/CIR/CodeGen/CIRGenPointerAuth.cpp
@@ -0,0 +1,23 @@
+//===--- CIRGenPointerAuth.cpp - CIR generation for ptr auth 
--------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains common routines relating to the emission of
+// pointer authentication operations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CIRGenFunction.h"
+
+using namespace clang;
+using namespace clang::CIRGen;
+
+Address CIRGenFunction::getAsNaturalAddressOf(Address addr,
+                                              QualType pointeeTy) {
+  assert(!cir::MissingFeatures::pointerAuthentication());
+  return addr;
+}
diff --git a/clang/lib/CIR/CodeGen/CMakeLists.txt 
b/clang/lib/CIR/CodeGen/CMakeLists.txt
index 7c31beacc5fb3..d3e2290ceea0b 100644
--- a/clang/lib/CIR/CodeGen/CMakeLists.txt
+++ b/clang/lib/CIR/CodeGen/CMakeLists.txt
@@ -35,6 +35,7 @@ add_clang_library(clangCIR
   CIRGenOpenACC.cpp
   CIRGenOpenACCClause.cpp
   CIRGenOpenACCRecipe.cpp
+  CIRGenPointerAuth.cpp
   CIRGenRecordLayoutBuilder.cpp
   CIRGenStmt.cpp
   CIRGenStmtOpenACC.cpp
diff --git a/clang/test/CIR/CodeGen/derived-to-base.cpp 
b/clang/test/CIR/CodeGen/derived-to-base.cpp
new file mode 100644
index 0000000000000..13acb47022c65
--- /dev/null
+++ b/clang/test/CIR/CodeGen/derived-to-base.cpp
@@ -0,0 +1,129 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o 
%t.cir
+// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o 
%t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG
+
+// TODO(cir): The constructors in this test case are only here because we don't
+//            have support for zero-initialization of base classes yet. We 
should
+//            fix that soon.
+
+struct Base {
+  Base();
+  void f();
+  int a;
+};
+
+struct Derived : Base {
+  Derived();
+  double b;
+};
+
+void f() {
+  Derived d;
+  d.f();
+}
+
+// CIR: cir.func {{.*}} @_Z1fv()
+// CIR:   %[[D:.*]] = cir.alloca !rec_Derived, !cir.ptr<!rec_Derived>, ["d", 
init]
+// CIR:   cir.call @_ZN7DerivedC1Ev(%[[D]]) : (!cir.ptr<!rec_Derived>) -> ()
+// CIR:   %[[D_BASE:.*]] = cir.base_class_addr %[[D]] : !cir.ptr<!rec_Derived> 
nonnull [0] -> !cir.ptr<!rec_Base>
+// CIR:   cir.call @_ZN4Base1fEv(%[[D_BASE]]) : (!cir.ptr<!rec_Base>) -> ()
+
+// LLVM: define {{.*}}void @_Z1fv()
+// LLVM:   %[[D:.*]] = alloca %struct.Derived
+// LLVM:   call void @_ZN7DerivedC1Ev(ptr %[[D]])
+// LLVM:   call void @_ZN4Base1fEv(ptr %[[D]])
+
+// OGCG: define {{.*}}void @_Z1fv()
+// OGCG:   %[[D:.*]] = alloca %struct.Derived
+// OGCG:   call void @_ZN7DerivedC1Ev(ptr {{.*}} %[[D]])
+// OGCG:   call void @_ZN4Base1fEv(ptr {{.*}} %[[D]])
+
+void useBase(Base *base);
+void callBaseUsingDerived(Derived *derived) {
+  useBase(derived);
+}
+
+
+// CIR: cir.func {{.*}} 
@_Z20callBaseUsingDerivedP7Derived(%[[DERIVED_ARG:.*]]: !cir.ptr<!rec_Derived> 
{{.*}})
+// CIR:   %[[DERIVED_ADDR:.*]] = cir.alloca !cir.ptr<!rec_Derived>, 
!cir.ptr<!cir.ptr<!rec_Derived>>, ["derived", init]
+// CIR:   cir.store %[[DERIVED_ARG]], %[[DERIVED_ADDR]]
+// CIR:   %[[DERIVED:.*]] = cir.load{{.*}} %[[DERIVED_ADDR]]
+// CIR:   %[[DERIVED_BASE:.*]] = cir.base_class_addr %[[DERIVED]] : 
!cir.ptr<!rec_Derived> nonnull [0] -> !cir.ptr<!rec_Base>
+// CIR:   cir.call @_Z7useBaseP4Base(%[[DERIVED_BASE]]) : 
(!cir.ptr<!rec_Base>) -> ()
+
+// LLVM: define {{.*}} void @_Z20callBaseUsingDerivedP7Derived(ptr 
%[[DERIVED_ARG:.*]])
+// LLVM:   %[[DERIVED_ADDR:.*]] = alloca ptr
+// LLVM:   store ptr %[[DERIVED_ARG]], ptr %[[DERIVED_ADDR]]
+// LLVM:   %[[DERIVED:.*]] = load ptr, ptr %[[DERIVED_ADDR]]
+// LLVM:   call void @_Z7useBaseP4Base(ptr %[[DERIVED]])
+
+// OGCG: define {{.*}} void @_Z20callBaseUsingDerivedP7Derived(ptr {{.*}} 
%[[DERIVED_ARG:.*]])
+// OGCG:   %[[DERIVED_ADDR:.*]] = alloca ptr
+// OGCG:   store ptr %[[DERIVED_ARG]], ptr %[[DERIVED_ADDR]]
+// OGCG:   %[[DERIVED:.*]] = load ptr, ptr %[[DERIVED_ADDR]]
+// OGCG:   call void @_Z7useBaseP4Base(ptr {{.*}} %[[DERIVED]])
+
+Base *returnBaseFromDerived(Derived* derived) {
+  return derived;
+}
+
+// CIR: cir.func {{.*}} 
@_Z21returnBaseFromDerivedP7Derived(%[[DERIVED_ARG:.*]]: !cir.ptr<!rec_Derived> 
{{.*}}) -> !cir.ptr<!rec_Base>
+// CIR:   %[[DERIVED_ADDR:.*]] = cir.alloca !cir.ptr<!rec_Derived>, 
!cir.ptr<!cir.ptr<!rec_Derived>>, ["derived", init]
+// CIR:   %[[BASE_ADDR:.*]] = cir.alloca !cir.ptr<!rec_Base>, 
!cir.ptr<!cir.ptr<!rec_Base>>, ["__retval"]
+// CIR:   cir.store %[[DERIVED_ARG]], %[[DERIVED_ADDR]]
+// CIR:   %[[DERIVED:.*]] = cir.load{{.*}} %[[DERIVED_ADDR]]
+// CIR:   %[[DERIVED_BASE:.*]] = cir.base_class_addr %[[DERIVED]] : 
!cir.ptr<!rec_Derived> nonnull [0] -> !cir.ptr<!rec_Base>
+// CIR:   cir.store %[[DERIVED_BASE]], %[[BASE_ADDR]]
+// CIR:   %[[BASE:.*]] = cir.load{{.*}} %[[BASE_ADDR]]
+// CIR:   cir.return %[[BASE]] : !cir.ptr<!rec_Base>
+
+// LLVM: define {{.*}} ptr @_Z21returnBaseFromDerivedP7Derived(ptr 
%[[DERIVED_ARG:.*]])
+// LLVM:   %[[DERIVED_ADDR:.*]] = alloca ptr
+// LLVM:   store ptr %[[DERIVED_ARG]], ptr %[[DERIVED_ADDR]]
+// LLVM:   %[[DERIVED:.*]] = load ptr, ptr %[[DERIVED_ADDR]]
+
+// OGCG: define {{.*}} ptr @_Z21returnBaseFromDerivedP7Derived(ptr {{.*}} 
%[[DERIVED_ARG:.*]])
+// OGCG:   %[[DERIVED_ADDR:.*]] = alloca ptr
+// OGCG:   store ptr %[[DERIVED_ARG]], ptr %[[DERIVED_ADDR]]
+// OGCG:   %[[DERIVED:.*]] = load ptr, ptr %[[DERIVED_ADDR]]
+
+volatile Derived derivedObj;
+
+void test_volatile_store() {
+  derivedObj.a = 0;
+}
+
+// CIR: cir.func {{.*}} @_Z19test_volatile_storev()
+// CIR:   %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i
+// CIR:   %[[DERIVED_OBJ:.*]] = cir.get_global @derivedObj : 
!cir.ptr<!rec_Derived>
+// CIR:   %[[DERIVED_OBJ_BASE:.*]] = cir.base_class_addr %[[DERIVED_OBJ]] : 
!cir.ptr<!rec_Derived> nonnull [0] -> !cir.ptr<!rec_Base>
+// CIR:   %[[DERIVED_OBJ_A:.*]] = cir.get_member %[[DERIVED_OBJ_BASE]][0] 
{name = "a"} : !cir.ptr<!rec_Base> -> !cir.ptr<!s32i>
+// CIR:   cir.store volatile {{.*}} %[[ZERO]], %[[DERIVED_OBJ_A]] : !s32i, 
!cir.ptr<!s32i>
+
+// LLVM: define {{.*}} void @_Z19test_volatile_storev()
+// LLVM:   store volatile i32 0, ptr @derivedObj
+
+// OGCG: define {{.*}} void @_Z19test_volatile_storev()
+// OGCG:   store volatile i32 0, ptr @derivedObj
+
+void test_volatile_load() {
+  [[maybe_unused]] int val = derivedObj.a;
+}
+
+// CIR: cir.func {{.*}} @_Z18test_volatile_loadv()
+// CIR:   %[[DERIVED_OBJ:.*]] = cir.get_global @derivedObj : 
!cir.ptr<!rec_Derived>
+// CIR:   %[[DERIVED_OBJ_BASE:.*]] = cir.base_class_addr %[[DERIVED_OBJ]] : 
!cir.ptr<!rec_Derived> nonnull [0] -> !cir.ptr<!rec_Base>
+// CIR:   %[[DERIVED_OBJ_A:.*]] = cir.get_member %[[DERIVED_OBJ_BASE]][0] 
{name = "a"} : !cir.ptr<!rec_Base> -> !cir.ptr<!s32i>
+// CIR:   %[[VAL:.*]] = cir.load volatile {{.*}} %[[DERIVED_OBJ_A]] : 
!cir.ptr<!s32i>, !s32i
+
+// LLVM: define {{.*}} void @_Z18test_volatile_loadv()
+// LLVM:   %[[VAL_ADDR:.*]] = alloca i32
+// LLVM:   %[[DERIVED_OBJ:.*]] = load volatile i32, ptr @derivedObj
+
+// OGCG: define {{.*}} void @_Z18test_volatile_loadv()
+// OGCG:   %[[VAL_ADDR:.*]] = alloca i32
+// OGCG:   %[[DERIVED_OBJ:.*]] = load volatile i32, ptr @derivedObj
+// OGCG:   store i32 %[[DERIVED_OBJ]], ptr %[[VAL_ADDR]]

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to