Skip to content

Commit 260df80

Browse files
authored
[CIR] Handle scalar DerivedToBase cast expressions (#167370)
This adds handling in CIR's ScalarExprEmitter for CK_DerivedToBase cast expressions.
1 parent 1d2429b commit 260df80

File tree

6 files changed

+168
-0
lines changed

6 files changed

+168
-0
lines changed

clang/include/clang/CIR/MissingFeatures.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ struct MissingFeatures {
298298
static bool opTBAA() { return false; }
299299
static bool peepholeProtection() { return false; }
300300
static bool pgoUse() { return false; }
301+
static bool pointerAuthentication() { return false; }
301302
static bool pointerOverflowSanitizer() { return false; }
302303
static bool preservedAccessIndexRegion() { return false; }
303304
static bool requiresCleanups() { return false; }

clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1933,6 +1933,14 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) {
19331933
return builder.createIntToPtr(middleVal, destCIRTy);
19341934
}
19351935

1936+
case CK_UncheckedDerivedToBase:
1937+
case CK_DerivedToBase: {
1938+
// The EmitPointerWithAlignment path does this fine; just discard
1939+
// the alignment.
1940+
return cgf.getAsNaturalPointerTo(cgf.emitPointerWithAlignment(ce),
1941+
ce->getType()->getPointeeType());
1942+
}
1943+
19361944
case CK_Dynamic: {
19371945
Address v = cgf.emitPointerWithAlignment(subExpr);
19381946
const auto *dce = cast<CXXDynamicCastExpr>(ce);

clang/lib/CIR/CodeGen/CIRGenFunction.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,12 @@ class CIRGenFunction : public CIRGenTypeCache {
497497
VlaSizePair getVLASize(const VariableArrayType *type);
498498
VlaSizePair getVLASize(QualType type);
499499

500+
Address getAsNaturalAddressOf(Address addr, QualType pointeeTy);
501+
502+
mlir::Value getAsNaturalPointerTo(Address addr, QualType pointeeType) {
503+
return getAsNaturalAddressOf(addr, pointeeType).getBasePointer();
504+
}
505+
500506
void finishFunction(SourceLocation endLoc);
501507

502508
/// Determine whether the given initializer is trivial in the sense
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//===--- CIRGenPointerAuth.cpp - CIR generation for ptr auth --------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file contains common routines relating to the emission of
10+
// pointer authentication operations.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#include "CIRGenFunction.h"
15+
16+
using namespace clang;
17+
using namespace clang::CIRGen;
18+
19+
Address CIRGenFunction::getAsNaturalAddressOf(Address addr,
20+
QualType pointeeTy) {
21+
assert(!cir::MissingFeatures::pointerAuthentication());
22+
return addr;
23+
}

clang/lib/CIR/CodeGen/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ add_clang_library(clangCIR
3535
CIRGenOpenACC.cpp
3636
CIRGenOpenACCClause.cpp
3737
CIRGenOpenACCRecipe.cpp
38+
CIRGenPointerAuth.cpp
3839
CIRGenRecordLayoutBuilder.cpp
3940
CIRGenStmt.cpp
4041
CIRGenStmtOpenACC.cpp
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
2+
// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR
3+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
4+
// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM
5+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
6+
// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG
7+
8+
// TODO(cir): The constructors in this test case are only here because we don't
9+
// have support for zero-initialization of base classes yet. We should
10+
// fix that soon.
11+
12+
struct Base {
13+
Base();
14+
void f();
15+
int a;
16+
};
17+
18+
struct Derived : Base {
19+
Derived();
20+
double b;
21+
};
22+
23+
void f() {
24+
Derived d;
25+
d.f();
26+
}
27+
28+
// CIR: cir.func {{.*}} @_Z1fv()
29+
// CIR: %[[D:.*]] = cir.alloca !rec_Derived, !cir.ptr<!rec_Derived>, ["d", init]
30+
// CIR: cir.call @_ZN7DerivedC1Ev(%[[D]]) : (!cir.ptr<!rec_Derived>) -> ()
31+
// CIR: %[[D_BASE:.*]] = cir.base_class_addr %[[D]] : !cir.ptr<!rec_Derived> nonnull [0] -> !cir.ptr<!rec_Base>
32+
// CIR: cir.call @_ZN4Base1fEv(%[[D_BASE]]) : (!cir.ptr<!rec_Base>) -> ()
33+
34+
// LLVM: define {{.*}}void @_Z1fv()
35+
// LLVM: %[[D:.*]] = alloca %struct.Derived
36+
// LLVM: call void @_ZN7DerivedC1Ev(ptr %[[D]])
37+
// LLVM: call void @_ZN4Base1fEv(ptr %[[D]])
38+
39+
// OGCG: define {{.*}}void @_Z1fv()
40+
// OGCG: %[[D:.*]] = alloca %struct.Derived
41+
// OGCG: call void @_ZN7DerivedC1Ev(ptr {{.*}} %[[D]])
42+
// OGCG: call void @_ZN4Base1fEv(ptr {{.*}} %[[D]])
43+
44+
void useBase(Base *base);
45+
void callBaseUsingDerived(Derived *derived) {
46+
useBase(derived);
47+
}
48+
49+
50+
// CIR: cir.func {{.*}} @_Z20callBaseUsingDerivedP7Derived(%[[DERIVED_ARG:.*]]: !cir.ptr<!rec_Derived> {{.*}})
51+
// CIR: %[[DERIVED_ADDR:.*]] = cir.alloca !cir.ptr<!rec_Derived>, !cir.ptr<!cir.ptr<!rec_Derived>>, ["derived", init]
52+
// CIR: cir.store %[[DERIVED_ARG]], %[[DERIVED_ADDR]]
53+
// CIR: %[[DERIVED:.*]] = cir.load{{.*}} %[[DERIVED_ADDR]]
54+
// CIR: %[[DERIVED_BASE:.*]] = cir.base_class_addr %[[DERIVED]] : !cir.ptr<!rec_Derived> nonnull [0] -> !cir.ptr<!rec_Base>
55+
// CIR: cir.call @_Z7useBaseP4Base(%[[DERIVED_BASE]]) : (!cir.ptr<!rec_Base>) -> ()
56+
57+
// LLVM: define {{.*}} void @_Z20callBaseUsingDerivedP7Derived(ptr %[[DERIVED_ARG:.*]])
58+
// LLVM: %[[DERIVED_ADDR:.*]] = alloca ptr
59+
// LLVM: store ptr %[[DERIVED_ARG]], ptr %[[DERIVED_ADDR]]
60+
// LLVM: %[[DERIVED:.*]] = load ptr, ptr %[[DERIVED_ADDR]]
61+
// LLVM: call void @_Z7useBaseP4Base(ptr %[[DERIVED]])
62+
63+
// OGCG: define {{.*}} void @_Z20callBaseUsingDerivedP7Derived(ptr {{.*}} %[[DERIVED_ARG:.*]])
64+
// OGCG: %[[DERIVED_ADDR:.*]] = alloca ptr
65+
// OGCG: store ptr %[[DERIVED_ARG]], ptr %[[DERIVED_ADDR]]
66+
// OGCG: %[[DERIVED:.*]] = load ptr, ptr %[[DERIVED_ADDR]]
67+
// OGCG: call void @_Z7useBaseP4Base(ptr {{.*}} %[[DERIVED]])
68+
69+
Base *returnBaseFromDerived(Derived* derived) {
70+
return derived;
71+
}
72+
73+
// CIR: cir.func {{.*}} @_Z21returnBaseFromDerivedP7Derived(%[[DERIVED_ARG:.*]]: !cir.ptr<!rec_Derived> {{.*}}) -> !cir.ptr<!rec_Base>
74+
// CIR: %[[DERIVED_ADDR:.*]] = cir.alloca !cir.ptr<!rec_Derived>, !cir.ptr<!cir.ptr<!rec_Derived>>, ["derived", init]
75+
// CIR: %[[BASE_ADDR:.*]] = cir.alloca !cir.ptr<!rec_Base>, !cir.ptr<!cir.ptr<!rec_Base>>, ["__retval"]
76+
// CIR: cir.store %[[DERIVED_ARG]], %[[DERIVED_ADDR]]
77+
// CIR: %[[DERIVED:.*]] = cir.load{{.*}} %[[DERIVED_ADDR]]
78+
// CIR: %[[DERIVED_BASE:.*]] = cir.base_class_addr %[[DERIVED]] : !cir.ptr<!rec_Derived> nonnull [0] -> !cir.ptr<!rec_Base>
79+
// CIR: cir.store %[[DERIVED_BASE]], %[[BASE_ADDR]]
80+
// CIR: %[[BASE:.*]] = cir.load{{.*}} %[[BASE_ADDR]]
81+
// CIR: cir.return %[[BASE]] : !cir.ptr<!rec_Base>
82+
83+
// LLVM: define {{.*}} ptr @_Z21returnBaseFromDerivedP7Derived(ptr %[[DERIVED_ARG:.*]])
84+
// LLVM: %[[DERIVED_ADDR:.*]] = alloca ptr
85+
// LLVM: store ptr %[[DERIVED_ARG]], ptr %[[DERIVED_ADDR]]
86+
// LLVM: %[[DERIVED:.*]] = load ptr, ptr %[[DERIVED_ADDR]]
87+
88+
// OGCG: define {{.*}} ptr @_Z21returnBaseFromDerivedP7Derived(ptr {{.*}} %[[DERIVED_ARG:.*]])
89+
// OGCG: %[[DERIVED_ADDR:.*]] = alloca ptr
90+
// OGCG: store ptr %[[DERIVED_ARG]], ptr %[[DERIVED_ADDR]]
91+
// OGCG: %[[DERIVED:.*]] = load ptr, ptr %[[DERIVED_ADDR]]
92+
93+
volatile Derived derivedObj;
94+
95+
void test_volatile_store() {
96+
derivedObj.a = 0;
97+
}
98+
99+
// CIR: cir.func {{.*}} @_Z19test_volatile_storev()
100+
// CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i
101+
// CIR: %[[DERIVED_OBJ:.*]] = cir.get_global @derivedObj : !cir.ptr<!rec_Derived>
102+
// CIR: %[[DERIVED_OBJ_BASE:.*]] = cir.base_class_addr %[[DERIVED_OBJ]] : !cir.ptr<!rec_Derived> nonnull [0] -> !cir.ptr<!rec_Base>
103+
// CIR: %[[DERIVED_OBJ_A:.*]] = cir.get_member %[[DERIVED_OBJ_BASE]][0] {name = "a"} : !cir.ptr<!rec_Base> -> !cir.ptr<!s32i>
104+
// CIR: cir.store volatile {{.*}} %[[ZERO]], %[[DERIVED_OBJ_A]] : !s32i, !cir.ptr<!s32i>
105+
106+
// LLVM: define {{.*}} void @_Z19test_volatile_storev()
107+
// LLVM: store volatile i32 0, ptr @derivedObj
108+
109+
// OGCG: define {{.*}} void @_Z19test_volatile_storev()
110+
// OGCG: store volatile i32 0, ptr @derivedObj
111+
112+
void test_volatile_load() {
113+
[[maybe_unused]] int val = derivedObj.a;
114+
}
115+
116+
// CIR: cir.func {{.*}} @_Z18test_volatile_loadv()
117+
// CIR: %[[DERIVED_OBJ:.*]] = cir.get_global @derivedObj : !cir.ptr<!rec_Derived>
118+
// CIR: %[[DERIVED_OBJ_BASE:.*]] = cir.base_class_addr %[[DERIVED_OBJ]] : !cir.ptr<!rec_Derived> nonnull [0] -> !cir.ptr<!rec_Base>
119+
// CIR: %[[DERIVED_OBJ_A:.*]] = cir.get_member %[[DERIVED_OBJ_BASE]][0] {name = "a"} : !cir.ptr<!rec_Base> -> !cir.ptr<!s32i>
120+
// CIR: %[[VAL:.*]] = cir.load volatile {{.*}} %[[DERIVED_OBJ_A]] : !cir.ptr<!s32i>, !s32i
121+
122+
// LLVM: define {{.*}} void @_Z18test_volatile_loadv()
123+
// LLVM: %[[VAL_ADDR:.*]] = alloca i32
124+
// LLVM: %[[DERIVED_OBJ:.*]] = load volatile i32, ptr @derivedObj
125+
126+
// OGCG: define {{.*}} void @_Z18test_volatile_loadv()
127+
// OGCG: %[[VAL_ADDR:.*]] = alloca i32
128+
// OGCG: %[[DERIVED_OBJ:.*]] = load volatile i32, ptr @derivedObj
129+
// OGCG: store i32 %[[DERIVED_OBJ]], ptr %[[VAL_ADDR]]

0 commit comments

Comments
 (0)