Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions clang/include/clang/CIR/MissingFeatures.h
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
23 changes: 23 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenPointerAuth.cpp
Original file line number Diff line number Diff line change
@@ -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;
}
1 change: 1 addition & 0 deletions clang/lib/CIR/CodeGen/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ add_clang_library(clangCIR
CIRGenOpenACC.cpp
CIRGenOpenACCClause.cpp
CIRGenOpenACCRecipe.cpp
CIRGenPointerAuth.cpp
CIRGenRecordLayoutBuilder.cpp
CIRGenStmt.cpp
CIRGenStmtOpenACC.cpp
Expand Down
129 changes: 129 additions & 0 deletions clang/test/CIR/CodeGen/derived-to-base.cpp
Original file line number Diff line number Diff line change
@@ -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]]