1 | //===--- CIRGenExprCXX.cpp - Emit CIR Code for C++ expressions ------------===// |
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 code generation of C++ expressions |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "CIRGenCXXABI.h" |
14 | #include "CIRGenFunction.h" |
15 | |
16 | #include "clang/AST/DeclCXX.h" |
17 | #include "clang/AST/ExprCXX.h" |
18 | #include "clang/CIR/MissingFeatures.h" |
19 | |
20 | using namespace clang; |
21 | using namespace clang::CIRGen; |
22 | |
23 | namespace { |
24 | struct MemberCallInfo { |
25 | RequiredArgs reqArgs; |
26 | // Number of prefix arguments for the call. Ignores the `this` pointer. |
27 | unsigned prefixSize; |
28 | }; |
29 | } // namespace |
30 | |
31 | static MemberCallInfo commonBuildCXXMemberOrOperatorCall( |
32 | CIRGenFunction &cgf, const CXXMethodDecl *md, mlir::Value thisPtr, |
33 | mlir::Value implicitParam, QualType implicitParamTy, const CallExpr *ce, |
34 | CallArgList &args, CallArgList *rtlArgs) { |
35 | assert(ce == nullptr || isa<CXXMemberCallExpr>(ce) || |
36 | isa<CXXOperatorCallExpr>(ce)); |
37 | assert(md->isInstance() && |
38 | "Trying to emit a member or operator call expr on a static method!" ); |
39 | |
40 | // Push the this ptr. |
41 | const CXXRecordDecl *rd = |
42 | cgf.cgm.getCXXABI().getThisArgumentTypeForMethod(md); |
43 | args.add(RValue::rvalue: get(thisPtr), type: cgf.getTypes().deriveThisType(rd, md)); |
44 | |
45 | // If there is an implicit parameter (e.g. VTT), emit it. |
46 | if (implicitParam) { |
47 | args.add(RValue::rvalue: get(implicitParam), type: implicitParamTy); |
48 | } |
49 | |
50 | const auto *fpt = md->getType()->castAs<FunctionProtoType>(); |
51 | RequiredArgs required = |
52 | RequiredArgs::getFromProtoWithExtraSlots(fpt, args.size()); |
53 | unsigned prefixSize = args.size() - 1; |
54 | |
55 | // Add the rest of the call args |
56 | if (rtlArgs) { |
57 | // Special case: if the caller emitted the arguments right-to-left already |
58 | // (prior to emitting the *this argument), we're done. This happens for |
59 | // assignment operators. |
60 | args.addFrom(other: *rtlArgs); |
61 | } else if (ce) { |
62 | // Special case: skip first argument of CXXOperatorCall (it is "this"). |
63 | unsigned argsToSkip = isa<CXXOperatorCallExpr>(Val: ce) ? 1 : 0; |
64 | cgf.emitCallArgs(args, prototype: fpt, argRange: drop_begin(ce->arguments(), argsToSkip), |
65 | callee: ce->getDirectCallee()); |
66 | } else { |
67 | assert( |
68 | fpt->getNumParams() == 0 && |
69 | "No CallExpr specified for function with non-zero number of arguments" ); |
70 | } |
71 | |
72 | // return {required, prefixSize}; |
73 | return {.reqArgs: required, .prefixSize: prefixSize}; |
74 | } |
75 | |
76 | RValue CIRGenFunction::emitCXXMemberOrOperatorMemberCallExpr( |
77 | const CallExpr *ce, const CXXMethodDecl *md, ReturnValueSlot returnValue, |
78 | bool hasQualifier, NestedNameSpecifier *qualifier, bool isArrow, |
79 | const Expr *base) { |
80 | assert(isa<CXXMemberCallExpr>(ce) || isa<CXXOperatorCallExpr>(ce)); |
81 | |
82 | if (md->isVirtual()) { |
83 | cgm.errorNYI(ce->getSourceRange(), |
84 | "emitCXXMemberOrOperatorMemberCallExpr: virtual call" ); |
85 | return RValue::get(nullptr); |
86 | } |
87 | |
88 | bool trivialForCodegen = |
89 | md->isTrivial() || (md->isDefaulted() && md->getParent()->isUnion()); |
90 | bool trivialAssignment = |
91 | trivialForCodegen && |
92 | (md->isCopyAssignmentOperator() || md->isMoveAssignmentOperator()) && |
93 | !md->getParent()->mayInsertExtraPadding(); |
94 | (void)trivialAssignment; |
95 | |
96 | // C++17 demands that we evaluate the RHS of a (possibly-compound) assignment |
97 | // operator before the LHS. |
98 | CallArgList rtlArgStorage; |
99 | CallArgList *rtlArgs = nullptr; |
100 | if (auto *oce = dyn_cast<CXXOperatorCallExpr>(Val: ce)) { |
101 | if (oce->isAssignmentOp()) { |
102 | cgm.errorNYI( |
103 | oce->getSourceRange(), |
104 | "emitCXXMemberOrOperatorMemberCallExpr: assignment operator" ); |
105 | } |
106 | } |
107 | |
108 | LValue thisPtr; |
109 | if (isArrow) { |
110 | LValueBaseInfo baseInfo; |
111 | assert(!cir::MissingFeatures::opTBAA()); |
112 | Address thisValue = emitPointerWithAlignment(expr: base, baseInfo: &baseInfo); |
113 | thisPtr = makeAddrLValue(addr: thisValue, ty: base->getType(), baseInfo); |
114 | } else { |
115 | thisPtr = emitLValue(e: base); |
116 | } |
117 | |
118 | if (isa<CXXConstructorDecl>(Val: md)) { |
119 | cgm.errorNYI(ce->getSourceRange(), |
120 | "emitCXXMemberOrOperatorMemberCallExpr: constructor call" ); |
121 | return RValue::get(nullptr); |
122 | } |
123 | |
124 | if (trivialForCodegen) { |
125 | if (isa<CXXDestructorDecl>(Val: md)) |
126 | return RValue::get(nullptr); |
127 | |
128 | if (trivialAssignment) { |
129 | cgm.errorNYI(ce->getSourceRange(), |
130 | "emitCXXMemberOrOperatorMemberCallExpr: trivial assignment" ); |
131 | return RValue::get(nullptr); |
132 | } |
133 | |
134 | assert(md->getParent()->mayInsertExtraPadding() && |
135 | "unknown trivial member function" ); |
136 | } |
137 | |
138 | // Compute the function type we're calling |
139 | const CXXMethodDecl *calleeDecl = md; |
140 | const CIRGenFunctionInfo *fInfo = nullptr; |
141 | if (isa<CXXDestructorDecl>(Val: calleeDecl)) { |
142 | cgm.errorNYI(ce->getSourceRange(), |
143 | "emitCXXMemberOrOperatorMemberCallExpr: destructor call" ); |
144 | return RValue::get(nullptr); |
145 | } |
146 | |
147 | fInfo = &cgm.getTypes().arrangeCXXMethodDeclaration(md: calleeDecl); |
148 | |
149 | mlir::Type ty = cgm.getTypes().getFunctionType(*fInfo); |
150 | |
151 | assert(!cir::MissingFeatures::sanitizers()); |
152 | assert(!cir::MissingFeatures::emitTypeCheck()); |
153 | |
154 | if (isa<CXXDestructorDecl>(Val: calleeDecl)) { |
155 | cgm.errorNYI(ce->getSourceRange(), |
156 | "emitCXXMemberOrOperatorMemberCallExpr: destructor call" ); |
157 | return RValue::get(nullptr); |
158 | } |
159 | |
160 | assert(!cir::MissingFeatures::sanitizers()); |
161 | if (getLangOpts().AppleKext) { |
162 | cgm.errorNYI(ce->getSourceRange(), |
163 | "emitCXXMemberOrOperatorMemberCallExpr: AppleKext" ); |
164 | return RValue::get(nullptr); |
165 | } |
166 | CIRGenCallee callee = |
167 | CIRGenCallee::forDirect(cgm.getAddrOfFunction(md, ty), GlobalDecl(md)); |
168 | |
169 | return emitCXXMemberOrOperatorCall( |
170 | calleeDecl, callee, returnValue, thisPtr.getPointer(), |
171 | /*ImplicitParam=*/nullptr, QualType(), ce, rtlArgs); |
172 | } |
173 | |
174 | RValue |
175 | CIRGenFunction::emitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *e, |
176 | const CXXMethodDecl *md, |
177 | ReturnValueSlot returnValue) { |
178 | assert(md->isInstance() && |
179 | "Trying to emit a member call expr on a static method!" ); |
180 | return emitCXXMemberOrOperatorMemberCallExpr( |
181 | ce: e, md, returnValue, /*HasQualifier=*/hasQualifier: false, /*Qualifier=*/qualifier: nullptr, |
182 | /*IsArrow=*/isArrow: false, base: e->getArg(0)); |
183 | } |
184 | |
185 | RValue CIRGenFunction::emitCXXMemberOrOperatorCall( |
186 | const CXXMethodDecl *md, const CIRGenCallee &callee, |
187 | ReturnValueSlot returnValue, mlir::Value thisPtr, mlir::Value implicitParam, |
188 | QualType implicitParamTy, const CallExpr *ce, CallArgList *rtlArgs) { |
189 | const auto *fpt = md->getType()->castAs<FunctionProtoType>(); |
190 | CallArgList args; |
191 | MemberCallInfo callInfo = commonBuildCXXMemberOrOperatorCall( |
192 | *this, md, thisPtr, implicitParam, implicitParamTy, ce, args, rtlArgs); |
193 | auto &fnInfo = cgm.getTypes().arrangeCXXMethodCall( |
194 | args, type: fpt, required: callInfo.reqArgs, numPrefixArgs: callInfo.prefixSize); |
195 | assert((ce || currSrcLoc) && "expected source location" ); |
196 | mlir::Location loc = ce ? getLoc(ce->getExprLoc()) : *currSrcLoc; |
197 | assert(!cir::MissingFeatures::opCallMustTail()); |
198 | return emitCall(calleeTy: fnInfo, callee, e: returnValue, returnValue: args, nullptr, loc); |
199 | } |
200 | |