clang 22.0.0git
LoweringPrepareItaniumCXXABI.cpp
Go to the documentation of this file.
1//===--------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with
4// LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===--------------------------------------------------------------------===//
9//
10// This file provides Itanium C++ ABI specific code
11// that is used during LLVMIR lowering prepare.
12//
13//===--------------------------------------------------------------------===//
14
16#include "mlir/IR/BuiltinAttributes.h"
17#include "mlir/IR/Value.h"
18#include "mlir/IR/ValueRange.h"
25
27public:
28 mlir::Value lowerDynamicCast(cir::CIRBaseBuilderTy &builder,
29 clang::ASTContext &astCtx,
30 cir::DynamicCastOp op) override;
31};
32
36
37static void buildBadCastCall(cir::CIRBaseBuilderTy &builder, mlir::Location loc,
38 mlir::FlatSymbolRefAttr badCastFuncRef) {
39 builder.createCallOp(loc, badCastFuncRef, cir::VoidType(),
40 mlir::ValueRange{});
41 // TODO(cir): Set the 'noreturn' attribute on the function.
43 cir::UnreachableOp::create(builder, loc);
44 builder.clearInsertionPoint();
45}
46
47static mlir::Value
49 cir::DynamicCastOp op) {
50 mlir::Location loc = op->getLoc();
51 mlir::Value srcValue = op.getSrc();
52 cir::DynamicCastInfoAttr castInfo = op.getInfo().value();
53
54 // TODO(cir): consider address space
56
57 mlir::Value srcPtr = builder.createBitcast(srcValue, builder.getVoidPtrTy());
58 cir::ConstantOp srcRtti = builder.getConstant(loc, castInfo.getSrcRtti());
59 cir::ConstantOp destRtti = builder.getConstant(loc, castInfo.getDestRtti());
60 cir::ConstantOp offsetHint =
61 builder.getConstant(loc, castInfo.getOffsetHint());
62
63 mlir::FlatSymbolRefAttr dynCastFuncRef = castInfo.getRuntimeFunc();
64 mlir::Value dynCastFuncArgs[4] = {srcPtr, srcRtti, destRtti, offsetHint};
65
66 mlir::Value castedPtr =
67 builder
68 .createCallOp(loc, dynCastFuncRef, builder.getVoidPtrTy(),
69 dynCastFuncArgs)
70 .getResult();
71
72 assert(mlir::isa<cir::PointerType>(castedPtr.getType()) &&
73 "the return value of __dynamic_cast should be a ptr");
74
75 /// C++ [expr.dynamic.cast]p9:
76 /// A failed cast to reference type throws std::bad_cast
77 if (op.isRefCast()) {
78 // Emit a cir.if that checks the casted value.
79 mlir::Value castedValueIsNull = builder.createPtrIsNull(castedPtr);
80 cir::IfOp::create(builder, loc, castedValueIsNull, false,
81 [&](mlir::OpBuilder &, mlir::Location) {
82 buildBadCastCall(builder, loc,
83 castInfo.getBadCastFunc());
84 });
85 }
86
87 // Note that castedPtr is a void*. Cast it to a pointer to the destination
88 // type before return.
89 return builder.createBitcast(castedPtr, op.getType());
90}
91
92static mlir::Value
94 clang::ASTContext &astCtx,
95 cir::DynamicCastOp op) {
96 mlir::Location loc = op.getLoc();
97 bool vtableUsesRelativeLayout = op.getRelativeLayout();
98
99 // TODO(cir): consider address space in this function.
101
102 mlir::Type vtableElemTy;
103 uint64_t vtableElemAlign;
104 if (vtableUsesRelativeLayout) {
105 vtableElemTy = builder.getSIntNTy(32);
106 vtableElemAlign = 4;
107 } else {
108 const auto &targetInfo = astCtx.getTargetInfo();
109 auto ptrdiffTy = targetInfo.getPtrDiffType(clang::LangAS::Default);
110 bool ptrdiffTyIsSigned = clang::TargetInfo::isTypeSigned(ptrdiffTy);
111 uint64_t ptrdiffTyWidth = targetInfo.getTypeWidth(ptrdiffTy);
112
113 vtableElemTy = cir::IntType::get(builder.getContext(), ptrdiffTyWidth,
114 ptrdiffTyIsSigned);
115 vtableElemAlign =
116 llvm::divideCeil(targetInfo.getPointerAlign(clang::LangAS::Default), 8);
117 }
118
119 // Access vtable to get the offset from the given object to its containing
120 // complete object.
121 // TODO: Add a specialized operation to get the object offset?
122 auto vptrTy = cir::VPtrType::get(builder.getContext());
123 cir::PointerType vptrPtrTy = builder.getPointerTo(vptrTy);
124 auto vptrPtr =
125 cir::VTableGetVPtrOp::create(builder, loc, vptrPtrTy, op.getSrc());
126 mlir::Value vptr = builder.createLoad(loc, vptrPtr);
127 mlir::Value elementPtr =
128 builder.createBitcast(vptr, builder.getPointerTo(vtableElemTy));
129 mlir::Value minusTwo = builder.getSignedInt(loc, -2, 64);
130 auto offsetToTopSlotPtr = cir::PtrStrideOp::create(
131 builder, loc, builder.getPointerTo(vtableElemTy), elementPtr, minusTwo);
132 mlir::Value offsetToTop =
133 builder.createAlignedLoad(loc, offsetToTopSlotPtr, vtableElemAlign);
134
135 // Add the offset to the given pointer to get the cast result.
136 // Cast the input pointer to a uint8_t* to allow pointer arithmetic.
137 cir::PointerType u8PtrTy = builder.getPointerTo(builder.getUIntNTy(8));
138 mlir::Value srcBytePtr = builder.createBitcast(op.getSrc(), u8PtrTy);
139 auto dstBytePtr =
140 cir::PtrStrideOp::create(builder, loc, u8PtrTy, srcBytePtr, offsetToTop);
141 // Cast the result to a void*.
142 return builder.createBitcast(dstBytePtr, builder.getVoidPtrTy());
143}
144
145mlir::Value
147 clang::ASTContext &astCtx,
148 cir::DynamicCastOp op) {
149 mlir::Location loc = op->getLoc();
150 mlir::Value srcValue = op.getSrc();
151
153
154 if (op.isRefCast())
155 return buildDynamicCastAfterNullCheck(builder, op);
156
157 mlir::Value srcValueIsNotNull = builder.createPtrToBoolCast(srcValue);
158 return cir::TernaryOp::create(
159 builder, loc, srcValueIsNotNull,
160 [&](mlir::OpBuilder &, mlir::Location) {
161 mlir::Value castedValue =
162 op.isCastToVoid()
163 ? buildDynamicCastToVoidAfterNullCheck(builder, astCtx,
164 op)
165 : buildDynamicCastAfterNullCheck(builder, op);
166 builder.createYield(loc, castedValue);
167 },
168 [&](mlir::OpBuilder &, mlir::Location) {
169 builder.createYield(
170 loc, builder.getNullPtr(op.getType(), loc).getResult());
171 })
172 .getResult();
173}
static void buildBadCastCall(cir::CIRBaseBuilderTy &builder, mlir::Location loc, mlir::FlatSymbolRefAttr badCastFuncRef)
static mlir::Value buildDynamicCastToVoidAfterNullCheck(cir::CIRBaseBuilderTy &builder, clang::ASTContext &astCtx, cir::DynamicCastOp op)
static mlir::Value buildDynamicCastAfterNullCheck(cir::CIRBaseBuilderTy &builder, cir::DynamicCastOp op)
mlir::Value lowerDynamicCast(cir::CIRBaseBuilderTy &builder, clang::ASTContext &astCtx, cir::DynamicCastOp op) override
cir::ConstantOp getConstant(mlir::Location loc, mlir::TypedAttr attr)
mlir::Value createPtrIsNull(mlir::Value ptr)
cir::PointerType getPointerTo(mlir::Type ty)
cir::ConstantOp getNullPtr(mlir::Type ty, mlir::Location loc)
cir::IntType getUIntNTy(int n)
cir::CallOp createCallOp(mlir::Location loc, mlir::SymbolRefAttr callee, mlir::Type returnType, mlir::ValueRange operands, llvm::ArrayRef< mlir::NamedAttribute > attrs={})
mlir::Value getSignedInt(mlir::Location loc, int64_t val, unsigned numBits)
mlir::Value createBitcast(mlir::Value src, mlir::Type newTy)
cir::LoadOp createLoad(mlir::Location loc, mlir::Value ptr, bool isVolatile=false, uint64_t alignment=0)
mlir::Value createPtrToBoolCast(mlir::Value v)
cir::PointerType getVoidPtrTy(clang::LangAS langAS=clang::LangAS::Default)
cir::IntType getSIntNTy(int n)
mlir::Value createAlignedLoad(mlir::Location loc, mlir::Value ptr, uint64_t alignment)
cir::YieldOp createYield(mlir::Location loc, mlir::ValueRange value={})
Create a yield operation.
static LoweringPrepareCXXABI * createItaniumABI()
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:220
const TargetInfo & getTargetInfo() const
Definition ASTContext.h:891
static bool isTypeSigned(IntType T)
Returns true if the type is signed; false otherwise.
IntType getPtrDiffType(LangAS AddrSpace) const
Definition TargetInfo.h:404
Defines the clang::TargetInfo interface.
static bool addressSpace()
static bool opFuncNoReturn()
static bool emitTypeCheck()