Skip to content

Commit 1c8aa96

Browse files
Merge branch 'llvm:main' into stacktrace23
2 parents ee82541 + f27cfea commit 1c8aa96

File tree

77 files changed

+748
-233
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

77 files changed

+748
-233
lines changed

clang/include/clang/CIR/MissingFeatures.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@ struct MissingFeatures {
9090
static bool opCallArgEvaluationOrder() { return false; }
9191
static bool opCallCallConv() { return false; }
9292
static bool opCallSideEffect() { return false; }
93-
static bool opCallChainCall() { return false; }
9493
static bool opCallNoPrototypeFunc() { return false; }
9594
static bool opCallMustTail() { return false; }
9695
static bool opCallIndirect() { return false; }
@@ -107,6 +106,13 @@ struct MissingFeatures {
107106
static bool opCallLandingPad() { return false; }
108107
static bool opCallContinueBlock() { return false; }
109108

109+
// FnInfoOpts -- This is used to track whether calls are chain calls or
110+
// instance methods. Classic codegen uses chain call to track and extra free
111+
// register for x86 and uses instance method as a condition for a thunk
112+
// generation special case. It's not clear that we need either of these in
113+
// pre-lowering CIR codegen.
114+
static bool opCallFnInfoOpts() { return false; }
115+
110116
// ScopeOp handling
111117
static bool opScopeCleanupRegion() { return false; }
112118

@@ -189,6 +195,12 @@ struct MissingFeatures {
189195
static bool constEmitterArrayILE() { return false; }
190196
static bool constEmitterVectorILE() { return false; }
191197
static bool needsGlobalCtorDtor() { return false; }
198+
static bool emitTypeCheck() { return false; }
199+
static bool cxxabiThisDecl() { return false; }
200+
static bool cxxabiThisAlignment() { return false; }
201+
static bool writebacks() { return false; }
202+
static bool cleanupsToDeactivate() { return false; }
203+
static bool stackBase() { return false; }
192204

193205
// Missing types
194206
static bool dataMemberType() { return false; }
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
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 provides an abstract class for C++ code generation. Concrete subclasses
10+
// of this implement code generation for specific C++ ABIs.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#include "CIRGenCXXABI.h"
15+
#include "CIRGenFunction.h"
16+
17+
#include "clang/AST/Decl.h"
18+
#include "clang/AST/GlobalDecl.h"
19+
20+
using namespace clang;
21+
using namespace clang::CIRGen;
22+
23+
CIRGenCXXABI::~CIRGenCXXABI() {}
24+
25+
void CIRGenCXXABI::buildThisParam(CIRGenFunction &cgf,
26+
FunctionArgList &params) {
27+
const auto *md = cast<CXXMethodDecl>(cgf.curGD.getDecl());
28+
29+
// FIXME: I'm not entirely sure I like using a fake decl just for code
30+
// generation. Maybe we can come up with a better way?
31+
auto *thisDecl =
32+
ImplicitParamDecl::Create(cgm.getASTContext(), nullptr, md->getLocation(),
33+
&cgm.getASTContext().Idents.get("this"),
34+
md->getThisType(), ImplicitParamKind::CXXThis);
35+
params.push_back(thisDecl);
36+
37+
// Classic codegen save thisDecl in CodeGenFunction::CXXABIThisDecl, but it
38+
// doesn't seem to be needed in CIRGen.
39+
assert(!cir::MissingFeatures::cxxabiThisDecl());
40+
41+
// Classic codegen computes the alignment of thisDecl and saves it in
42+
// CodeGenFunction::CXXABIThisAlignment, but it doesn't seem to be needed in
43+
// CIRGen.
44+
assert(!cir::MissingFeatures::cxxabiThisAlignment());
45+
}

clang/lib/CIR/CodeGen/CIRGenCXXABI.h

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#ifndef LLVM_CLANG_LIB_CIR_CIRGENCXXABI_H
1515
#define LLVM_CLANG_LIB_CIR_CIRGENCXXABI_H
1616

17+
#include "CIRGenCall.h"
1718
#include "CIRGenModule.h"
1819

1920
#include "clang/AST/Mangle.h"
@@ -31,9 +32,33 @@ class CIRGenCXXABI {
3132
// implemented.
3233
CIRGenCXXABI(CIRGenModule &cgm)
3334
: cgm(cgm), mangleContext(cgm.getASTContext().createMangleContext()) {}
34-
~CIRGenCXXABI();
35+
virtual ~CIRGenCXXABI();
3536

3637
public:
38+
/// Get the type of the implicit "this" parameter used by a method. May return
39+
/// zero if no specific type is applicable, e.g. if the ABI expects the "this"
40+
/// parameter to point to some artificial offset in a complete object due to
41+
/// vbases being reordered.
42+
virtual const clang::CXXRecordDecl *
43+
getThisArgumentTypeForMethod(const clang::CXXMethodDecl *md) {
44+
return md->getParent();
45+
}
46+
47+
/// Build a parameter variable suitable for 'this'.
48+
void buildThisParam(CIRGenFunction &cgf, FunctionArgList &params);
49+
50+
/// Returns true if the given constructor or destructor is one of the kinds
51+
/// that the ABI says returns 'this' (only applies when called non-virtually
52+
/// for destructors).
53+
///
54+
/// There currently is no way to indicate if a destructor returns 'this' when
55+
/// called virtually, and CIR generation does not support this case.
56+
virtual bool hasThisReturn(clang::GlobalDecl gd) const { return false; }
57+
58+
virtual bool hasMostDerivedReturn(clang::GlobalDecl gd) const {
59+
return false;
60+
}
61+
3762
/// Gets the mangle context.
3863
clang::MangleContext &getMangleContext() { return *mangleContext; }
3964
};
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
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::get(thisPtr), 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::get(implicitParam), 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(*rtlArgs);
61+
} else if (ce) {
62+
// Special case: skip first argument of CXXOperatorCall (it is "this").
63+
unsigned argsToSkip = isa<CXXOperatorCallExpr>(ce) ? 1 : 0;
64+
cgf.emitCallArgs(args, fpt, drop_begin(ce->arguments(), argsToSkip),
65+
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 {required, 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>(ce)) {
101+
cgm.errorNYI(oce->getSourceRange(),
102+
"emitCXXMemberOrOperatorMemberCallExpr: operator call");
103+
return RValue::get(nullptr);
104+
}
105+
106+
LValue thisPtr;
107+
if (isArrow) {
108+
LValueBaseInfo baseInfo;
109+
assert(!cir::MissingFeatures::opTBAA());
110+
Address thisValue = emitPointerWithAlignment(base, &baseInfo);
111+
thisPtr = makeAddrLValue(thisValue, base->getType(), baseInfo);
112+
} else {
113+
thisPtr = emitLValue(base);
114+
}
115+
116+
if (const CXXConstructorDecl *ctor = dyn_cast<CXXConstructorDecl>(md)) {
117+
cgm.errorNYI(ce->getSourceRange(),
118+
"emitCXXMemberOrOperatorMemberCallExpr: constructor call");
119+
return RValue::get(nullptr);
120+
}
121+
122+
if (trivialForCodegen) {
123+
if (isa<CXXDestructorDecl>(md))
124+
return RValue::get(nullptr);
125+
126+
if (trivialAssignment) {
127+
cgm.errorNYI(ce->getSourceRange(),
128+
"emitCXXMemberOrOperatorMemberCallExpr: trivial assignment");
129+
return RValue::get(nullptr);
130+
} else {
131+
assert(md->getParent()->mayInsertExtraPadding() &&
132+
"unknown trivial member function");
133+
}
134+
}
135+
136+
// Compute the function type we're calling
137+
const CXXMethodDecl *calleeDecl = md;
138+
const CIRGenFunctionInfo *fInfo = nullptr;
139+
if (const auto *dtor = dyn_cast<CXXDestructorDecl>(calleeDecl)) {
140+
cgm.errorNYI(ce->getSourceRange(),
141+
"emitCXXMemberOrOperatorMemberCallExpr: destructor call");
142+
return RValue::get(nullptr);
143+
} else {
144+
fInfo = &cgm.getTypes().arrangeCXXMethodDeclaration(calleeDecl);
145+
}
146+
147+
mlir::Type ty = cgm.getTypes().getFunctionType(*fInfo);
148+
149+
assert(!cir::MissingFeatures::sanitizers());
150+
assert(!cir::MissingFeatures::emitTypeCheck());
151+
152+
if (const auto *dtor = dyn_cast<CXXDestructorDecl>(calleeDecl)) {
153+
cgm.errorNYI(ce->getSourceRange(),
154+
"emitCXXMemberOrOperatorMemberCallExpr: destructor call");
155+
return RValue::get(nullptr);
156+
}
157+
158+
assert(!cir::MissingFeatures::sanitizers());
159+
if (getLangOpts().AppleKext) {
160+
cgm.errorNYI(ce->getSourceRange(),
161+
"emitCXXMemberOrOperatorMemberCallExpr: AppleKext");
162+
return RValue::get(nullptr);
163+
}
164+
CIRGenCallee callee =
165+
CIRGenCallee::forDirect(cgm.getAddrOfFunction(md, ty), GlobalDecl(md));
166+
167+
return emitCXXMemberOrOperatorCall(
168+
calleeDecl, callee, returnValue, thisPtr.getPointer(),
169+
/*ImplicitParam=*/nullptr, QualType(), ce, rtlArgs);
170+
}
171+
172+
RValue CIRGenFunction::emitCXXMemberOrOperatorCall(
173+
const CXXMethodDecl *md, const CIRGenCallee &callee,
174+
ReturnValueSlot returnValue, mlir::Value thisPtr, mlir::Value implicitParam,
175+
QualType implicitParamTy, const CallExpr *ce, CallArgList *rtlArgs) {
176+
const auto *fpt = md->getType()->castAs<FunctionProtoType>();
177+
CallArgList args;
178+
MemberCallInfo callInfo = commonBuildCXXMemberOrOperatorCall(
179+
*this, md, thisPtr, implicitParam, implicitParamTy, ce, args, rtlArgs);
180+
auto &fnInfo = cgm.getTypes().arrangeCXXMethodCall(
181+
args, fpt, callInfo.reqArgs, callInfo.prefixSize);
182+
assert((ce || currSrcLoc) && "expected source location");
183+
mlir::Location loc = ce ? getLoc(ce->getExprLoc()) : *currSrcLoc;
184+
assert(!cir::MissingFeatures::opCallMustTail());
185+
return emitCall(fnInfo, callee, returnValue, args, nullptr, loc);
186+
}

0 commit comments

Comments
 (0)