[clang] [CIR] Handle scalar DerivedToBase cast expressions (PR #167370)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Nov 10 10:57:18 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clangir
Author: Andy Kaylor (andykaylor)
<details>
<summary>Changes</summary>
This adds handling in CIR's ScalarExprEmitter for CK_DerivedToBase cast expressions.
---
Full diff: https://github.com/llvm/llvm-project/pull/167370.diff
6 Files Affected:
- (modified) clang/include/clang/CIR/MissingFeatures.h (+1)
- (modified) clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp (+8)
- (modified) clang/lib/CIR/CodeGen/CIRGenFunction.h (+6)
- (added) clang/lib/CIR/CodeGen/CIRGenPointerAuth.cpp (+23)
- (modified) clang/lib/CIR/CodeGen/CMakeLists.txt (+1)
- (added) clang/test/CIR/CodeGen/derived-to-base.cpp (+129)
``````````diff
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]]
``````````
</details>
https://github.com/llvm/llvm-project/pull/167370
More information about the cfe-commits
mailing list