| 1 | //===----------------------------------------------------------------------===// |
| 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 contains code dealing with C++ code generation of classes |
| 10 | // |
| 11 | //===----------------------------------------------------------------------===// |
| 12 | |
| 13 | #include "CIRGenCXXABI.h" |
| 14 | #include "CIRGenFunction.h" |
| 15 | |
| 16 | #include "clang/AST/ExprCXX.h" |
| 17 | #include "clang/AST/RecordLayout.h" |
| 18 | #include "clang/AST/Type.h" |
| 19 | #include "clang/CIR/MissingFeatures.h" |
| 20 | |
| 21 | using namespace clang; |
| 22 | using namespace clang::CIRGen; |
| 23 | |
| 24 | Address CIRGenFunction::getAddressOfBaseClass( |
| 25 | Address value, const CXXRecordDecl *derived, |
| 26 | llvm::iterator_range<CastExpr::path_const_iterator> path, |
| 27 | bool nullCheckValue, SourceLocation loc) { |
| 28 | assert(!path.empty() && "Base path should not be empty!" ); |
| 29 | |
| 30 | if ((*path.begin())->isVirtual()) { |
| 31 | // The implementation here is actually complete, but let's flag this |
| 32 | // as an error until the rest of the virtual base class support is in place. |
| 33 | cgm.errorNYI(loc, "getAddrOfBaseClass: virtual base" ); |
| 34 | return Address::invalid(); |
| 35 | } |
| 36 | |
| 37 | // Compute the static offset of the ultimate destination within its |
| 38 | // allocating subobject (the virtual base, if there is one, or else |
| 39 | // the "complete" object that we see). |
| 40 | CharUnits nonVirtualOffset = |
| 41 | cgm.computeNonVirtualBaseClassOffset(derivedClass: derived, path); |
| 42 | |
| 43 | // Get the base pointer type. |
| 44 | mlir::Type baseValueTy = convertType((path.end()[-1])->getType()); |
| 45 | assert(!cir::MissingFeatures::addressSpace()); |
| 46 | |
| 47 | // The if statement here is redundant now, but it will be needed when we add |
| 48 | // support for virtual base classes. |
| 49 | // If there is no virtual base, use cir.base_class_addr. It takes care of |
| 50 | // the adjustment and the null pointer check. |
| 51 | if (nonVirtualOffset.isZero()) { |
| 52 | assert(!cir::MissingFeatures::sanitizers()); |
| 53 | return builder.createBaseClassAddr(getLoc(loc), value, baseValueTy, 0, |
| 54 | /*assumeNotNull=*/true); |
| 55 | } |
| 56 | |
| 57 | assert(!cir::MissingFeatures::sanitizers()); |
| 58 | |
| 59 | // Apply the offset |
| 60 | value = builder.createBaseClassAddr(getLoc(loc), value, baseValueTy, |
| 61 | nonVirtualOffset.getQuantity(), |
| 62 | /*assumeNotNull=*/true); |
| 63 | |
| 64 | // Cast to the destination type. |
| 65 | value = value.withElementType(builder, baseValueTy); |
| 66 | |
| 67 | return value; |
| 68 | } |
| 69 | |
| 70 | void CIRGenFunction::emitCXXConstructorCall(const clang::CXXConstructorDecl *d, |
| 71 | clang::CXXCtorType type, |
| 72 | bool forVirtualBase, |
| 73 | bool delegating, |
| 74 | AggValueSlot thisAVS, |
| 75 | const clang::CXXConstructExpr *e) { |
| 76 | CallArgList args; |
| 77 | Address thisAddr = thisAVS.getAddress(); |
| 78 | QualType thisType = d->getThisType(); |
| 79 | mlir::Value thisPtr = thisAddr.getPointer(); |
| 80 | |
| 81 | assert(!cir::MissingFeatures::addressSpace()); |
| 82 | |
| 83 | args.add(RValue::rvalue: get(thisPtr), type: thisType); |
| 84 | |
| 85 | // In LLVM Codegen: If this is a trivial constructor, just emit what's needed. |
| 86 | // If this is a union copy constructor, we must emit a memcpy, because the AST |
| 87 | // does not model that copy. |
| 88 | assert(!cir::MissingFeatures::isMemcpyEquivalentSpecialMember()); |
| 89 | |
| 90 | const FunctionProtoType *fpt = d->getType()->castAs<FunctionProtoType>(); |
| 91 | |
| 92 | assert(!cir::MissingFeatures::opCallArgEvaluationOrder()); |
| 93 | |
| 94 | emitCallArgs(args, prototype: fpt, argRange: e->arguments(), callee: e->getConstructor(), |
| 95 | /*ParamsToSkip=*/paramsToSkip: 0); |
| 96 | |
| 97 | assert(!cir::MissingFeatures::sanitizers()); |
| 98 | emitCXXConstructorCall(d, type, forVirtualBase, delegating, thisAddr, args, |
| 99 | e->getExprLoc()); |
| 100 | } |
| 101 | |
| 102 | void CIRGenFunction::emitCXXConstructorCall( |
| 103 | const CXXConstructorDecl *d, CXXCtorType type, bool forVirtualBase, |
| 104 | bool delegating, Address thisAddr, CallArgList &args, SourceLocation loc) { |
| 105 | |
| 106 | const CXXRecordDecl *crd = d->getParent(); |
| 107 | |
| 108 | // If this is a call to a trivial default constructor: |
| 109 | // In LLVM: do nothing. |
| 110 | // In CIR: emit as a regular call, other later passes should lower the |
| 111 | // ctor call into trivial initialization. |
| 112 | assert(!cir::MissingFeatures::isTrivialCtorOrDtor()); |
| 113 | |
| 114 | assert(!cir::MissingFeatures::isMemcpyEquivalentSpecialMember()); |
| 115 | |
| 116 | bool passPrototypeArgs = true; |
| 117 | |
| 118 | // Check whether we can actually emit the constructor before trying to do so. |
| 119 | if (d->getInheritedConstructor()) { |
| 120 | cgm.errorNYI(d->getSourceRange(), |
| 121 | "emitCXXConstructorCall: inherited constructor" ); |
| 122 | return; |
| 123 | } |
| 124 | |
| 125 | // Insert any ABI-specific implicit constructor arguments. |
| 126 | assert(!cir::MissingFeatures::implicitConstructorArgs()); |
| 127 | |
| 128 | // Emit the call. |
| 129 | auto calleePtr = cgm.getAddrOfCXXStructor(GlobalDecl(d, type)); |
| 130 | const CIRGenFunctionInfo &info = cgm.getTypes().arrangeCXXConstructorCall( |
| 131 | args, d, ctorKind: type, passProtoArgs: passPrototypeArgs); |
| 132 | CIRGenCallee callee = CIRGenCallee::forDirect(calleePtr, GlobalDecl(d, type)); |
| 133 | cir::CIRCallOpInterface c; |
| 134 | emitCall(info, callee, ReturnValueSlot(), args, &c, getLoc(loc)); |
| 135 | |
| 136 | if (cgm.getCodeGenOpts().OptimizationLevel != 0 && !crd->isDynamicClass() && |
| 137 | type != Ctor_Base && cgm.getCodeGenOpts().StrictVTablePointers) |
| 138 | cgm.errorNYI(d->getSourceRange(), "vtable assumption loads" ); |
| 139 | } |
| 140 | |