[clang] 4acbf9b - [CIR][CodeGen][NFCI] Move shared AST-only helpers into CodeGenUtils (#223418)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Sep 22 01:24:32 PDT 2026
Author: Henrich Lauko
Date: 2026-09-22T10:24:26+02:00
New Revision: 4acbf9b61c3f0579def4ebd1c1abca1048c4c378
URL: https://github.com/llvm/llvm-project/commit/4acbf9b61c3f0579def4ebd1c1abca1048c4c378
DIFF: https://github.com/llvm/llvm-project/commit/4acbf9b61c3f0579def4ebd1c1abca1048c4c378.diff
LOG: [CIR][CodeGen][NFCI] Move shared AST-only helpers into CodeGenUtils (#223418)
Follow-up to PR #221001. Ten more helpers that both CodeGens had
equivalent copies of, several of them already marked "should be shared"
in
CIR.
Instead of growing CodeGenUtils.h, each helper goes in a header named
for
the classic CodeGen file it came from, with the CGExpr*.cpp family
sharing
ExprUtils.h. CIR's files mirror the classic ones, so the grouping reads
the
same from both sides.
CIR's getNoFPClassTestMask returned unsigned where classic returns
llvm::FPClassTest; the shared version keeps the classic return type.
Assisted-by: Claude Code (Claude Fable 5.1).
Added:
clang/include/clang/CodeGenUtils/CallUtils.h
clang/include/clang/CodeGenUtils/ClassUtils.h
clang/include/clang/CodeGenUtils/ExprUtils.h
clang/include/clang/CodeGenUtils/FunctionUtils.h
clang/include/clang/CodeGenUtils/ItaniumCXXABIUtils.h
clang/lib/CodeGenUtils/CallUtils.cpp
clang/lib/CodeGenUtils/ClassUtils.cpp
clang/lib/CodeGenUtils/ExprUtils.cpp
clang/lib/CodeGenUtils/FunctionUtils.cpp
clang/lib/CodeGenUtils/ItaniumCXXABIUtils.cpp
Modified:
clang/lib/CIR/CodeGen/CIRGenCall.cpp
clang/lib/CIR/CodeGen/CIRGenClass.cpp
clang/lib/CIR/CodeGen/CIRGenExpr.cpp
clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
clang/lib/CIR/CodeGen/CIRGenFunction.cpp
clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
clang/lib/CodeGen/CGCall.cpp
clang/lib/CodeGen/CGClass.cpp
clang/lib/CodeGen/CGExpr.cpp
clang/lib/CodeGen/CGExprAgg.cpp
clang/lib/CodeGen/CGExprScalar.cpp
clang/lib/CodeGen/CodeGenFunction.cpp
clang/lib/CodeGen/ItaniumCXXABI.cpp
clang/lib/CodeGenUtils/CMakeLists.txt
Removed:
################################################################################
diff --git a/clang/include/clang/CodeGenUtils/CallUtils.h b/clang/include/clang/CodeGenUtils/CallUtils.h
new file mode 100644
index 0000000000000..450a62a448e49
--- /dev/null
+++ b/clang/include/clang/CodeGenUtils/CallUtils.h
@@ -0,0 +1,32 @@
+//===--- CallUtils.h - Shared call emission queries -------------*- C++ -*-===//
+//
+// 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 holds the AST and language option queries that both classic
+// CodeGen and CIR CodeGen need while building a call and its argument and
+// return value attributes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CODEGENUTILS_CALLUTILS_H
+#define LLVM_CLANG_CODEGENUTILS_CALLUTILS_H
+
+#include "clang/AST/ASTContext.h"
+#include "llvm/ADT/FloatingPointMode.h"
+
+namespace clang::CodeGenUtils {
+
+/// Returns the canonical formal type of the given C++ method.
+CanQual<FunctionProtoType> getFormalType(const CXXMethodDecl *MD);
+
+/// Returns the set of floating-point value kinds that the language options
+/// promise never reach a function's arguments or return value.
+llvm::FPClassTest getNoFPClassTestMask(const LangOptions &LangOpts);
+
+} // namespace clang::CodeGenUtils
+
+#endif // LLVM_CLANG_CODEGENUTILS_CALLUTILS_H
diff --git a/clang/include/clang/CodeGenUtils/ClassUtils.h b/clang/include/clang/CodeGenUtils/ClassUtils.h
new file mode 100644
index 0000000000000..63664ed737933
--- /dev/null
+++ b/clang/include/clang/CodeGenUtils/ClassUtils.h
@@ -0,0 +1,29 @@
+//===--- ClassUtils.h - Shared C++ class emission queries -------*- C++ -*-===//
+//
+// 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 holds the AST queries about C++ class construction and destruction
+// that both classic CodeGen and CIR CodeGen need, chiefly to decide when a
+// vtable pointer has to be established before running member initializers or
+// a destructor body.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CODEGENUTILS_CLASSUTILS_H
+#define LLVM_CLANG_CODEGENUTILS_CLASSUTILS_H
+
+#include "clang/AST/ASTContext.h"
+
+namespace clang::CodeGenUtils {
+
+/// Check whether \p Init uses 'this' in a way which requires the vtable to be
+/// properly set.
+bool baseInitializerUsesThis(ASTContext &Ctx, const Expr *Init);
+
+} // namespace clang::CodeGenUtils
+
+#endif // LLVM_CLANG_CODEGENUTILS_CLASSUTILS_H
diff --git a/clang/include/clang/CodeGenUtils/ExprUtils.h b/clang/include/clang/CodeGenUtils/ExprUtils.h
new file mode 100644
index 0000000000000..e6a5248440d33
--- /dev/null
+++ b/clang/include/clang/CodeGenUtils/ExprUtils.h
@@ -0,0 +1,48 @@
+//===--- ExprUtils.h - Shared expression emission queries -------*- C++ -*-===//
+//
+// 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 holds the AST queries about expressions that both classic CodeGen
+// and CIR CodeGen need while emitting scalar, aggregate and lvalue
+// expressions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CODEGENUTILS_EXPRUTILS_H
+#define LLVM_CLANG_CODEGENUTILS_EXPRUTILS_H
+
+#include "clang/AST/ASTContext.h"
+
+namespace clang::CodeGenUtils {
+
+/// Strip off the variably-modified array types wrapping \p VLA and return the
+/// first element type that has a fixed size.
+QualType getFixedSizeElementType(const ASTContext &Ctx,
+ const VariableArrayType *VLA);
+
+/// Check whether the value of \p E is possibly a reference to or into a
+/// __block variable.
+bool isBlockVarRef(const Expr *E);
+
+/// Check whether \p E is cheap enough and side-effect-free enough to evaluate
+/// unconditionally instead of conditionally. This is used to convert control
+/// flow into selects in some cases.
+bool isCheapEnoughToEvaluateUnconditionally(const Expr *E,
+ const ASTContext &Ctx);
+
+/// Check whether \p E is a trivial array filler, that is, one that is
+/// equivalent to zero-initialization.
+bool isTrivialFiller(const Expr *E);
+
+/// Detect the unusual situation where an inline version of a builtin is
+/// shadowed by a non-inline version. In that case we should pick the external
+/// one everywhere. That's GCC behavior too.
+bool onlyHasInlineBuiltinDeclaration(const FunctionDecl *FD);
+
+} // namespace clang::CodeGenUtils
+
+#endif // LLVM_CLANG_CODEGENUTILS_EXPRUTILS_H
diff --git a/clang/include/clang/CodeGenUtils/FunctionUtils.h b/clang/include/clang/CodeGenUtils/FunctionUtils.h
new file mode 100644
index 0000000000000..f924874d829e0
--- /dev/null
+++ b/clang/include/clang/CodeGenUtils/FunctionUtils.h
@@ -0,0 +1,28 @@
+//===--- FunctionUtils.h - Shared function emission queries -----*- C++ -*-===//
+//
+// 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 holds the queries that both classic CodeGen and CIR CodeGen need
+// while emitting a function body.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CODEGENUTILS_FUNCTIONUTILS_H
+#define LLVM_CLANG_CODEGENUTILS_FUNCTIONUTILS_H
+
+#include "clang/Basic/CodeGenOptions.h"
+#include "clang/Basic/LangOptions.h"
+
+namespace clang::CodeGenUtils {
+
+/// Decide whether we need to emit the lifetime markers.
+bool shouldEmitLifetimeMarkers(const CodeGenOptions &CGOpts,
+ const LangOptions &LangOpts);
+
+} // namespace clang::CodeGenUtils
+
+#endif // LLVM_CLANG_CODEGENUTILS_FUNCTIONUTILS_H
diff --git a/clang/include/clang/CodeGenUtils/ItaniumCXXABIUtils.h b/clang/include/clang/CodeGenUtils/ItaniumCXXABIUtils.h
new file mode 100644
index 0000000000000..45b358ad343bb
--- /dev/null
+++ b/clang/include/clang/CodeGenUtils/ItaniumCXXABIUtils.h
@@ -0,0 +1,28 @@
+//===--- ItaniumCXXABIUtils.h - Shared Itanium C++ ABI queries --*- C++ -*-===//
+//
+// 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 holds the Itanium C++ ABI queries that both classic CodeGen and
+// CIR CodeGen need while lowering ABI constructs whose encoding the ABI
+// specifies in terms of the AST.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CODEGENUTILS_ITANIUMCXXABIUTILS_H
+#define LLVM_CLANG_CODEGENUTILS_ITANIUMCXXABIUTILS_H
+
+#include "clang/AST/ASTContext.h"
+
+namespace clang::CodeGenUtils {
+
+/// Compute the src2dst_offset hint as described in the Itanium C++ ABI [2.9.7].
+CharUnits computeOffsetHint(ASTContext &Ctx, const CXXRecordDecl *Src,
+ const CXXRecordDecl *Dst);
+
+} // namespace clang::CodeGenUtils
+
+#endif // LLVM_CLANG_CODEGENUTILS_ITANIUMCXXABIUTILS_H
diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
index 48dcadf9abd66..226bc0a0ed0d5 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
@@ -21,6 +21,7 @@
#include "clang/Basic/DiagnosticFrontend.h"
#include "clang/CIR/ABIArgInfo.h"
#include "clang/CIR/MissingFeatures.h"
+#include "clang/CodeGenUtils/CallUtils.h"
#include "llvm/ADT/FloatingPointMode.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/TypeSize.h"
@@ -628,16 +629,6 @@ static bool determineNoUndef(QualType clangTy, CIRGenTypes &types,
return false;
}
-/// Compute the nofpclass mask for FP types based on language options.
-static unsigned getNoFPClassTestMask(const LangOptions &langOpts) {
- unsigned mask = 0;
- if (langOpts.NoHonorInfs)
- mask |= llvm::fcInf;
- if (langOpts.NoHonorNaNs)
- mask |= llvm::fcNan;
- return mask;
-}
-
void CIRGenModule::constructFunctionReturnAttributes(
const CIRGenFunctionInfo &info, const Decl *targetDecl, bool isThunk,
mlir::NamedAttrList &retAttrs) {
@@ -653,7 +644,8 @@ void CIRGenModule::constructFunctionReturnAttributes(
mlir::UnitAttr::get(&getMLIRContext()));
if (retTy->hasFloatingRepresentation())
- if (unsigned mask = getNoFPClassTestMask(getLangOpts()))
+ if (llvm::FPClassTest mask =
+ CodeGenUtils::getNoFPClassTestMask(getLangOpts()))
retAttrs.set(mlir::LLVM::LLVMDialect::getNoFPClassAttrName(),
builder.getI64IntegerAttr(mask));
@@ -778,7 +770,8 @@ void CIRGenModule::constructFunctionArgumentAttributes(
}
if (argType->hasFloatingRepresentation())
- if (unsigned mask = getNoFPClassTestMask(getLangOpts()))
+ if (llvm::FPClassTest mask =
+ CodeGenUtils::getNoFPClassTestMask(getLangOpts()))
argAttrList.set(mlir::LLVM::LLVMDialect::getNoFPClassAttrName(),
builder.getI64IntegerAttr(mask));
@@ -802,13 +795,6 @@ void CIRGenModule::constructFunctionArgumentAttributes(
}
}
-/// Returns the canonical formal type of the given C++ method.
-static CanQual<FunctionProtoType> getFormalType(const CXXMethodDecl *md) {
- return md->getType()
- ->getCanonicalTypeUnqualified()
- .getAs<FunctionProtoType>();
-}
-
/// Adds the formal parameters in FPT to the given prefix. If any parameter in
/// FPT has pass_object_size attrs, then we'll add parameters for those, too.
/// TODO(cir): this should be shared with LLVM codegen
@@ -853,7 +839,7 @@ CIRGenTypes::arrangeCXXStructorDeclaration(GlobalDecl gd) {
passParams = inheritingCtorHasParams(inherited, gd.getCtorType());
}
- CanQual<FunctionProtoType> fpt = getFormalType(md);
+ CanQual<FunctionProtoType> fpt = CodeGenUtils::getFormalType(md);
if (passParams)
appendParameterTypes(*this, argTypes, fpt);
@@ -1003,7 +989,7 @@ const CIRGenFunctionInfo &CIRGenTypes::arrangeCXXConstructorCall(
// +1 for implicit this, which should always be args[0]
unsigned totalPrefixArgs = 1 + extraPrefixArgs;
- CanQual<FunctionProtoType> fpt = getFormalType(d);
+ CanQual<FunctionProtoType> fpt = CodeGenUtils::getFormalType(d);
RequiredArgs required = passProtoArgs
? RequiredArgs::getFromProtoWithExtraSlots(
fpt, totalPrefixArgs + extraSuffixArgs)
diff --git a/clang/lib/CIR/CodeGen/CIRGenClass.cpp b/clang/lib/CIR/CodeGen/CIRGenClass.cpp
index 8cd014415e4ee..c8edc1ccd02c6 100644
--- a/clang/lib/CIR/CodeGen/CIRGenClass.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp
@@ -14,12 +14,12 @@
#include "CIRGenFunction.h"
#include "CIRGenValue.h"
-#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/Type.h"
#include "clang/CIR/Dialect/IR/CIRDialect.h"
#include "clang/CIR/MissingFeatures.h"
+#include "clang/CodeGenUtils/ClassUtils.h"
#include "clang/CodeGenUtils/CodeGenUtils.h"
using namespace clang;
@@ -199,31 +199,8 @@ struct CallDelegatingCtorDtor final : EHScopeStack::Cleanup {
}
};
-/// A visitor which checks whether an initializer uses 'this' in a
-/// way which requires the vtable to be properly set.
-struct DynamicThisUseChecker
- : ConstEvaluatedExprVisitor<DynamicThisUseChecker> {
- using super = ConstEvaluatedExprVisitor<DynamicThisUseChecker>;
-
- bool usesThis = false;
-
- DynamicThisUseChecker(const ASTContext &c) : super(c) {}
-
- // Black-list all explicit and implicit references to 'this'.
- //
- // Do we need to worry about external references to 'this' derived
- // from arbitrary code? If so, then anything which runs arbitrary
- // external code might potentially access the vtable.
- void VisitCXXThisExpr(const CXXThisExpr *e) { usesThis = true; }
-};
} // end anonymous namespace
-static bool baseInitializerUsesThis(ASTContext &c, const Expr *init) {
- DynamicThisUseChecker checker(c);
- checker.Visit(init);
- return checker.usesThis;
-}
-
/// Gets the address of a direct base class within a complete object.
/// This should only be used for (1) non-virtual bases or (2) virtual bases
/// when the type is known to be complete (e.g. in complete destructors).
@@ -266,7 +243,7 @@ void CIRGenFunction::emitBaseInitializer(mlir::Location loc,
// If the initializer for the base (other than the constructor
// itself) accesses 'this' in any way, we need to initialize the
// vtables.
- if (baseInitializerUsesThis(getContext(), baseInit->getInit()))
+ if (CodeGenUtils::baseInitializerUsesThis(getContext(), baseInit->getInit()))
initializeVTablePointers(loc, classDecl);
// We can pretend to be a complete class because it only matters for
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index 7e9a4d9458c93..664425b20577f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -31,6 +31,7 @@
#include "clang/CIR/Dialect/IR/CIRTypes.h"
#include "clang/CIR/MissingFeatures.h"
#include "clang/CodeGenUtils/CodeGenUtils.h"
+#include "clang/CodeGenUtils/ExprUtils.h"
#include <optional>
using namespace clang;
@@ -1300,15 +1301,6 @@ static CharUnits getArrayElementAlign(CharUnits arrayAlign, mlir::Value idx,
return arrayAlign.alignmentOfArrayElement(eltSize);
}
-static QualType getFixedSizeElementType(const ASTContext &astContext,
- const VariableArrayType *vla) {
- QualType eltType;
- do {
- eltType = vla->getElementType();
- } while ((vla = astContext.getAsVariableArrayType(eltType)));
- return eltType;
-}
-
static mlir::Value emitArraySubscriptPtr(CIRGenFunction &cgf,
mlir::Location beginLoc,
mlir::Location endLoc, mlir::Value ptr,
@@ -1332,7 +1324,7 @@ static Address emitArraySubscriptPtr(CIRGenFunction &cgf,
// the thing that the indices are expressed in terms of.
if (const VariableArrayType *vla =
cgf.getContext().getAsVariableArrayType(eltType)) {
- eltType = getFixedSizeElementType(cgf.getContext(), vla);
+ eltType = CodeGenUtils::getFixedSizeElementType(cgf.getContext(), vla);
}
// We can use that to compute the best alignment of the element.
@@ -2218,16 +2210,6 @@ RValue CIRGenFunction::emitAnyExpr(const Expr *e, AggValueSlot aggSlot,
llvm_unreachable("bad evaluation kind");
}
-// Detect the unusual situation where an inline version is shadowed by a
-// non-inline version. In that case we should pick the external one
-// everywhere. That's GCC behavior too.
-static bool onlyHasInlineBuiltinDeclaration(const FunctionDecl *fd) {
- for (const FunctionDecl *pd = fd; pd; pd = pd->getPreviousDecl())
- if (!pd->isInlineBuiltinDeclaration())
- return false;
- return true;
-}
-
CIRGenCallee CIRGenFunction::emitDirectCallee(const GlobalDecl &gd) {
const auto *fd = cast<FunctionDecl>(gd.getDecl());
@@ -2249,7 +2231,7 @@ CIRGenCallee CIRGenFunction::emitDirectCallee(const GlobalDecl &gd) {
// name to make it clear it's not the actual builtin.
if (auto fn = dyn_cast<cir::FuncOp>(curFn);
(!fn || fn.getName() != fdInlineName) &&
- onlyHasInlineBuiltinDeclaration(fd)) {
+ CodeGenUtils::onlyHasInlineBuiltinDeclaration(fd)) {
cir::FuncOp clone =
mlir::cast_or_null<cir::FuncOp>(cgm.getGlobalValue(fdInlineName));
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
index 2fb66232d806c..f9a4eb2b2033a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
@@ -20,6 +20,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/CodeGenUtils/ExprUtils.h"
#include "llvm/IR/Value.h"
#include <cstdint>
@@ -27,73 +28,6 @@ using namespace clang;
using namespace clang::CIRGen;
namespace {
-// FIXME(cir): This should be a common helper between CIRGen
-// and traditional CodeGen
-/// Is the value of the given expression possibly a reference to or
-/// into a __block variable?
-static bool isBlockVarRef(const Expr *e) {
- // Make sure we look through parens.
- e = e->IgnoreParens();
-
- // Check for a direct reference to a __block variable.
- if (const DeclRefExpr *dre = dyn_cast<DeclRefExpr>(e)) {
- const VarDecl *var = dyn_cast<VarDecl>(dre->getDecl());
- return (var && var->hasAttr<BlocksAttr>());
- }
-
- // More complicated stuff.
-
- // Binary operators.
- if (const BinaryOperator *op = dyn_cast<BinaryOperator>(e)) {
- // For an assignment or pointer-to-member operation, just care
- // about the LHS.
- if (op->isAssignmentOp() || op->isPtrMemOp())
- return isBlockVarRef(op->getLHS());
-
- // For a comma, just care about the RHS.
- if (op->getOpcode() == BO_Comma)
- return isBlockVarRef(op->getRHS());
-
- // FIXME: pointer arithmetic?
- return false;
-
- // Check both sides of a conditional operator.
- } else if (const AbstractConditionalOperator *op =
- dyn_cast<AbstractConditionalOperator>(e)) {
- return isBlockVarRef(op->getTrueExpr()) ||
- isBlockVarRef(op->getFalseExpr());
-
- // OVEs are required to support BinaryConditionalOperators.
- } else if (const OpaqueValueExpr *op = dyn_cast<OpaqueValueExpr>(e)) {
- if (const Expr *src = op->getSourceExpr())
- return isBlockVarRef(src);
-
- // Casts are necessary to get things like (*(int*)&var) = foo().
- // We don't really care about the kind of cast here, except
- // we don't want to look through l2r casts, because it's okay
- // to get the *value* in a __block variable.
- } else if (const CastExpr *cast = dyn_cast<CastExpr>(e)) {
- if (cast->getCastKind() == CK_LValueToRValue)
- return false;
- return isBlockVarRef(cast->getSubExpr());
-
- // Handle unary operators. Again, just aggressively look through
- // it, ignoring the operation.
- } else if (const UnaryOperator *uop = dyn_cast<UnaryOperator>(e)) {
- return isBlockVarRef(uop->getSubExpr());
-
- // Look into the base of a field access.
- } else if (const MemberExpr *mem = dyn_cast<MemberExpr>(e)) {
- return isBlockVarRef(mem->getBase());
-
- // Look into the base of a subscript.
- } else if (const ArraySubscriptExpr *sub = dyn_cast<ArraySubscriptExpr>(e)) {
- return isBlockVarRef(sub->getBase());
- }
-
- return false;
-}
-
class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
CIRGenFunction &cgf;
@@ -172,7 +106,7 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
e->getRHS()->getType()) &&
"Invalid assignment");
- if (isBlockVarRef(e->getLHS()) &&
+ if (CodeGenUtils::isBlockVarRef(e->getLHS()) &&
e->getRHS()->HasSideEffects(cgf.getContext())) {
cgf.cgm.errorNYI(e->getSourceRange(),
"block var reference with side effects");
@@ -729,26 +663,6 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
} // namespace
-static bool isTrivialFiller(Expr *e) {
- if (!e)
- return true;
-
- if (isa<ImplicitValueInitExpr>(e))
- return true;
-
- if (auto *ile = dyn_cast<InitListExpr>(e)) {
- if (ile->getNumInits())
- return false;
- return isTrivialFiller(ile->getArrayFiller());
- }
-
- if (const auto *cons = dyn_cast_or_null<CXXConstructExpr>(e))
- return cons->getConstructor()->isDefaultConstructor() &&
- cons->getConstructor()->isTrivial();
-
- return false;
-}
-
/// Given an expression with aggregate type that represents a value lvalue, this
/// method emits the address of the lvalue, then loads the result into DestPtr.
void AggExprEmitter::emitAggLoadOfLValue(const Expr *e) {
@@ -863,7 +777,7 @@ void AggExprEmitter::emitArrayInit(Address destPtr, cir::ArrayType arrayTy,
const uint64_t numArrayElements = arrayTy.getSize();
// Check whether there's a non-trivial array-fill expression.
- const bool hasTrivialFiller = isTrivialFiller(arrayFiller);
+ const bool hasTrivialFiller = CodeGenUtils::isTrivialFiller(arrayFiller);
// Any remaining elements need to be zero-initialized, possibly
// using the filler expression. We can skip this if the we're
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index eaca334e88d07..4b59698326f08 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -19,6 +19,7 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/CIR/Dialect/IR/CIRTypes.h"
#include "clang/CIR/MissingFeatures.h"
+#include "clang/CodeGenUtils/ExprUtils.h"
#include "mlir/Dialect/Ptr/IR/MemorySpaceInterfaces.h"
#include "mlir/IR/Location.h"
@@ -3138,23 +3139,6 @@ mlir::Value ScalarExprEmitter::VisitUnaryExprOrTypeTraitExpr(
e->EvaluateKnownConstInt(cgf.getContext())));
}
-/// Return true if the specified expression is cheap enough and side-effect-free
-/// enough to evaluate unconditionally instead of conditionally. This is used
-/// to convert control flow into selects in some cases.
-/// TODO(cir): can be shared with LLVM codegen.
-static bool isCheapEnoughToEvaluateUnconditionally(const Expr *e,
- CIRGenFunction &cgf) {
- // Anything that is an integer or floating point constant is fine.
- return e->IgnoreParens()->isEvaluatable(cgf.getContext());
-
- // Even non-volatile automatic variables can't be evaluated unconditionally.
- // Referencing a thread_local may cause non-trivial initialization work to
- // occur. If we're inside a lambda and one of the variables is from the scope
- // outside the lambda, that function may have returned already. Reading its
- // locals is a bad idea. Also, these reads may introduce races there didn't
- // exist in the source-level program.
-}
-
mlir::Value ScalarExprEmitter::VisitAbstractConditionalOperator(
const AbstractConditionalOperator *e) {
CIRGenBuilderTy &builder = cgf.getBuilder();
@@ -3250,8 +3234,10 @@ mlir::Value ScalarExprEmitter::VisitAbstractConditionalOperator(
// If this is a really simple expression (like x ? 4 : 5), emit this as a
// select instead of as control flow. We can only do this if it is cheap
// and safe to evaluate the LHS and RHS unconditionally.
- if (isCheapEnoughToEvaluateUnconditionally(lhsExpr, cgf) &&
- isCheapEnoughToEvaluateUnconditionally(rhsExpr, cgf)) {
+ if (CodeGenUtils::isCheapEnoughToEvaluateUnconditionally(lhsExpr,
+ cgf.getContext()) &&
+ CodeGenUtils::isCheapEnoughToEvaluateUnconditionally(rhsExpr,
+ cgf.getContext())) {
bool lhsIsVoid = false;
mlir::Value condV = cgf.evaluateExprAsBool(condExpr);
assert(!cir::MissingFeatures::incrementProfileCounter());
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index a1bd15d88b118..9ba717ce7135f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -22,6 +22,7 @@
#include "clang/CIR/Dialect/IR/CIRDialect.h"
#include "clang/CIR/MissingFeatures.h"
#include "clang/CodeGenUtils/CodeGenUtils.h"
+#include "clang/CodeGenUtils/FunctionUtils.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/IR/FPEnv.h"
@@ -29,24 +30,6 @@
namespace clang::CIRGen {
-/// shouldEmitLifetimeMarkers - Decide whether we need emit the life-time
-/// markers. Mirror of CodeGenFunction::shouldEmitLifetimeMarkers.
-static bool shouldEmitLifetimeMarkers(const CodeGenOptions &cgOpts,
- const LangOptions &langOpts) {
-
- if (cgOpts.DisableLifetimeMarkers)
- return false;
-
- // Sanitizers may use markers.
- if (cgOpts.SanitizeAddressUseAfterScope ||
- langOpts.Sanitize.has(SanitizerKind::HWAddress) ||
- langOpts.Sanitize.has(SanitizerKind::Memory) ||
- langOpts.Sanitize.has(SanitizerKind::MemtagStack))
- return true;
-
- return cgOpts.OptimizationLevel != 0;
-}
-
/// Does the statement tree rooted at \p s contain a label, switch, or indirect
/// goto that could bypass a local's initialization? A coarse stand-in for
/// classic CodeGen's per-decl bypass analysis (PR28267).
@@ -66,7 +49,7 @@ CIRGenFunction::CIRGenFunction(CIRGenModule &cgm, CIRGenBuilderTy &builder,
: CIRGenTypeCache(cgm), cgm{cgm}, builder(builder),
curFPFeatures(cgm.getLangOpts()) {
ehStack.setCGF(this);
- shouldEmitLifetimeMarkers = CIRGen::shouldEmitLifetimeMarkers(
+ shouldEmitLifetimeMarkers = CodeGenUtils::shouldEmitLifetimeMarkers(
cgm.getCodeGenOpts(), getContext().getLangOpts());
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
index 4588576fd2ecf..59461a6c6de4a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
@@ -25,6 +25,7 @@
#include "clang/AST/TypeBase.h"
#include "clang/AST/VTableBuilder.h"
#include "clang/CIR/MissingFeatures.h"
+#include "clang/CodeGenUtils/ItaniumCXXABIUtils.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
@@ -2105,58 +2106,6 @@ void CIRGenItaniumCXXABI::emitBadCastCall(CIRGenFunction &cgf,
emitCallToBadCast(cgf, loc);
}
-// TODO(cir): This could be shared with classic codegen.
-static CharUnits computeOffsetHint(ASTContext &astContext,
- const CXXRecordDecl *src,
- const CXXRecordDecl *dst) {
- CXXBasePaths paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
- /*DetectVirtual=*/false);
-
- // If Dst is not derived from Src we can skip the whole computation below and
- // return that Src is not a public base of Dst. Record all inheritance paths.
- if (!dst->isDerivedFrom(src, paths))
- return CharUnits::fromQuantity(-2);
-
- unsigned numPublicPaths = 0;
- CharUnits offset;
-
- // Now walk all possible inheritance paths.
- for (const CXXBasePath &path : paths) {
- if (path.Access != AS_public) // Ignore non-public inheritance.
- continue;
-
- ++numPublicPaths;
-
- for (const CXXBasePathElement &pathElement : path) {
- // If the path contains a virtual base class we can't give any hint.
- // -1: no hint.
- if (pathElement.Base->isVirtual())
- return CharUnits::fromQuantity(-1);
-
- if (numPublicPaths > 1) // Won't use offsets, skip computation.
- continue;
-
- // Accumulate the base class offsets.
- const ASTRecordLayout &L =
- astContext.getASTRecordLayout(pathElement.Class);
- offset += L.getBaseClassOffset(
- pathElement.Base->getType()->getAsCXXRecordDecl());
- }
- }
-
- // -2: Src is not a public base of Dst.
- if (numPublicPaths == 0)
- return CharUnits::fromQuantity(-2);
-
- // -3: Src is a multiple public base type but never a virtual base type.
- if (numPublicPaths > 1)
- return CharUnits::fromQuantity(-3);
-
- // Otherwise, the Src type is a unique public nonvirtual base type of Dst.
- // Return the offset of Src from the origin of Dst.
- return offset;
-}
-
static cir::FuncOp getItaniumDynamicCastFn(CIRGenFunction &cgf) {
// Prototype:
// void *__dynamic_cast(const void *sub,
@@ -2337,7 +2286,8 @@ static cir::DynamicCastInfoAttr emitDynamicCastInfo(CIRGenFunction &cgf,
const CXXRecordDecl *srcDecl = srcRecordTy->getAsCXXRecordDecl();
const CXXRecordDecl *destDecl = destRecordTy->getAsCXXRecordDecl();
- CharUnits offsetHint = computeOffsetHint(cgf.getContext(), srcDecl, destDecl);
+ CharUnits offsetHint =
+ CodeGenUtils::computeOffsetHint(cgf.getContext(), srcDecl, destDecl);
mlir::Type ptr
diff Ty = cgf.convertType(cgf.getContext().getPointerDiffType());
auto offsetHintAttr = cir::IntAttr::get(ptr
diff Ty, offsetHint.getQuantity());
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 017b234535c70..2193a89203f29 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -34,6 +34,7 @@
#include "clang/Basic/TargetInfo.h"
#include "clang/CodeGen/CGFunctionInfo.h"
#include "clang/CodeGen/SwiftCallingConv.h"
+#include "clang/CodeGenUtils/CallUtils.h"
#include "llvm/ABI/FunctionInfo.h"
#include "llvm/ABI/IRTypeMapper.h"
#include "llvm/ABI/TargetInfo.h"
@@ -150,13 +151,6 @@ CanQualType CodeGenTypes::DeriveThisType(const CXXRecordDecl *RD,
return Context.getPointerType(RecTy);
}
-/// Returns the canonical formal type of the given C++ method.
-static CanQual<FunctionProtoType> GetFormalType(const CXXMethodDecl *MD) {
- return MD->getType()
- ->getCanonicalTypeUnqualified()
- .getAs<FunctionProtoType>();
-}
-
/// Returns the "extra-canonicalized" return type, which discards
/// qualifiers on the return type. Codegen doesn't care about them,
/// and it makes ABI code a little easier to be able to assume that
@@ -394,7 +388,7 @@ CodeGenTypes::arrangeCXXMethodDeclaration(const CXXMethodDecl *MD) {
assert(!isa<CXXConstructorDecl>(MD) && "wrong method for constructors!");
assert(!isa<CXXDestructorDecl>(MD) && "wrong method for destructors!");
- CanQualType FT = GetFormalType(MD).getAs<Type>();
+ CanQualType FT = CodeGenUtils::getFormalType(MD).getAs<Type>();
setCUDAKernelCallingConvention(FT, CGM, MD);
auto prototype = FT.getAs<FunctionProtoType>();
@@ -442,7 +436,7 @@ CodeGenTypes::arrangeCXXStructorDeclaration(GlobalDecl GD) {
PassParams = inheritingCtorHasParams(Inherited, GD.getCtorType());
}
- CanQual<FunctionProtoType> FTP = GetFormalType(MD);
+ CanQual<FunctionProtoType> FTP = CodeGenUtils::getFormalType(MD);
// Add the formal parameters.
if (PassParams)
@@ -518,7 +512,7 @@ const CGFunctionInfo &CodeGenTypes::arrangeCXXConstructorCall(
// +1 for implicit this, which should always be args[0].
unsigned TotalPrefixArgs = 1 + ExtraPrefixArgs;
- CanQual<FunctionProtoType> FPT = GetFormalType(D);
+ CanQual<FunctionProtoType> FPT = CodeGenUtils::getFormalType(D);
RequiredArgs Required = PassProtoArgs
? RequiredArgs::forPrototypePlus(
FPT, TotalPrefixArgs + ExtraSuffixArgs)
@@ -661,7 +655,7 @@ const CGFunctionInfo &CodeGenTypes::arrangeGlobalDeclaration(GlobalDecl GD) {
const CGFunctionInfo &
CodeGenTypes::arrangeUnprototypedMustTailThunk(const CXXMethodDecl *MD) {
assert(MD->isVirtual() && "only methods have thunks");
- CanQual<FunctionProtoType> FTP = GetFormalType(MD);
+ CanQual<FunctionProtoType> FTP = CodeGenUtils::getFormalType(MD);
CanQualType ArgTys[] = {DeriveThisType(MD->getParent(), MD)};
return arrangeLLVMFunctionInfo(Context.VoidTy, FnInfoOpts::None, ArgTys,
FTP->getExtInfo(), {}, RequiredArgs(1), MD);
@@ -672,7 +666,7 @@ CodeGenTypes::arrangeMSCtorClosure(const CXXConstructorDecl *CD,
CXXCtorType CT) {
assert(CT == Ctor_CopyingClosure || CT == Ctor_DefaultClosure);
- CanQual<FunctionProtoType> FTP = GetFormalType(CD);
+ CanQual<FunctionProtoType> FTP = CodeGenUtils::getFormalType(CD);
SmallVector<CanQualType, 2> ArgTys;
const CXXRecordDecl *RD = CD->getParent();
ArgTys.push_back(DeriveThisType(RD, CD));
@@ -2709,16 +2703,6 @@ static bool canApplyNoFPClass(const ABIArgInfo &AI, QualType ParamType,
return false;
}
-/// Return the nofpclass mask that can be applied to floating-point parameters.
-static llvm::FPClassTest getNoFPClassTestMask(const LangOptions &LangOpts) {
- llvm::FPClassTest Mask = llvm::fcNone;
- if (LangOpts.NoHonorInfs)
- Mask |= llvm::fcInf;
- if (LangOpts.NoHonorNaNs)
- Mask |= llvm::fcNan;
- return Mask;
-}
-
void CodeGenModule::AdjustMemoryAttribute(StringRef Name,
CGCalleeInfo CalleeInfo,
llvm::AttributeList &Attrs) {
@@ -3043,7 +3027,8 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
RetAttrs.addAttribute(llvm::Attribute::InReg);
if (canApplyNoFPClass(RetAI, RetTy, true))
- RetAttrs.addNoFPClassAttr(getNoFPClassTestMask(getLangOpts()));
+ RetAttrs.addNoFPClassAttr(
+ CodeGenUtils::getNoFPClassTestMask(getLangOpts()));
break;
case ABIArgInfo::Ignore:
@@ -3205,7 +3190,8 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
Attrs.addStackAlignmentAttr(llvm::MaybeAlign(AI.getDirectAlign()));
if (canApplyNoFPClass(AI, ParamType, false))
- Attrs.addNoFPClassAttr(getNoFPClassTestMask(getLangOpts()));
+ Attrs.addNoFPClassAttr(
+ CodeGenUtils::getNoFPClassTestMask(getLangOpts()));
break;
case ABIArgInfo::Indirect: {
assert(!ParamType->isIncompleteType() &&
diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp
index ffa1304253519..63f5d9ae13dbf 100644
--- a/clang/lib/CodeGen/CGClass.cpp
+++ b/clang/lib/CodeGen/CGClass.cpp
@@ -21,11 +21,11 @@
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtCXX.h"
#include "clang/Basic/CodeGenOptions.h"
#include "clang/CodeGen/CGFunctionInfo.h"
+#include "clang/CodeGenUtils/ClassUtils.h"
#include "clang/CodeGenUtils/CodeGenUtils.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Metadata.h"
@@ -513,31 +513,8 @@ struct CallBaseDtor final : EHScopeStack::Cleanup {
}
};
-/// A visitor which checks whether an initializer uses 'this' in a
-/// way which requires the vtable to be properly set.
-struct DynamicThisUseChecker
- : ConstEvaluatedExprVisitor<DynamicThisUseChecker> {
- typedef ConstEvaluatedExprVisitor<DynamicThisUseChecker> super;
-
- bool UsesThis;
-
- DynamicThisUseChecker(const ASTContext &C) : super(C), UsesThis(false) {}
-
- // Black-list all explicit and implicit references to 'this'.
- //
- // Do we need to worry about external references to 'this' derived
- // from arbitrary code? If so, then anything which runs arbitrary
- // external code might potentially access the vtable.
- void VisitCXXThisExpr(const CXXThisExpr *E) { UsesThis = true; }
-};
} // end anonymous namespace
-static bool BaseInitializerUsesThis(ASTContext &C, const Expr *Init) {
- DynamicThisUseChecker Checker(C);
- Checker.Visit(Init);
- return Checker.UsesThis;
-}
-
static void EmitBaseInitializer(CodeGenFunction &CGF,
const CXXRecordDecl *ClassDecl,
CXXCtorInitializer *BaseInit) {
@@ -552,7 +529,8 @@ static void EmitBaseInitializer(CodeGenFunction &CGF,
// If the initializer for the base (other than the constructor
// itself) accesses 'this' in any way, we need to initialize the
// vtables.
- if (BaseInitializerUsesThis(CGF.getContext(), BaseInit->getInit()))
+ if (CodeGenUtils::baseInitializerUsesThis(CGF.getContext(),
+ BaseInit->getInit()))
CGF.InitializeVTablePointers(ClassDecl);
// We can pretend to be a complete class because it only matters for
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index c93d3fd8c562e..2a28ae041cee0 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -40,6 +40,7 @@
#include "clang/Basic/Module.h"
#include "clang/Basic/SourceManager.h"
#include "clang/CodeGenUtils/CodeGenUtils.h"
+#include "clang/CodeGenUtils/ExprUtils.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/StringExtras.h"
@@ -4761,15 +4762,6 @@ static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr,
}
}
-static QualType getFixedSizeElementType(const ASTContext &ctx,
- const VariableArrayType *vla) {
- QualType eltType;
- do {
- eltType = vla->getElementType();
- } while ((vla = ctx.getAsVariableArrayType(eltType)));
- return eltType;
-}
-
static bool hasBPFPreserveStaticOffset(const RecordDecl *D) {
return D && D->hasAttr<BPFPreserveStaticOffsetAttr>();
}
@@ -4852,7 +4844,7 @@ static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr,
// Determine the element size of the statically-sized base. This is
// the thing that the indices are expressed in terms of.
if (auto vla = CGF.getContext().getAsVariableArrayType(eltType)) {
- eltType = getFixedSizeElementType(CGF.getContext(), vla);
+ eltType = CodeGenUtils::getFixedSizeElementType(CGF.getContext(), vla);
}
// We can use that to compute the best alignment of the element.
@@ -6616,16 +6608,6 @@ RValue CodeGenFunction::EmitSimpleCallExpr(const CallExpr *E,
/*Chain=*/nullptr, CallOrInvoke);
}
-// Detect the unusual situation where an inline version is shadowed by a
-// non-inline version. In that case we should pick the external one
-// everywhere. That's GCC behavior too.
-static bool OnlyHasInlineBuiltinDeclaration(const FunctionDecl *FD) {
- for (const FunctionDecl *PD = FD; PD; PD = PD->getPreviousDecl())
- if (!PD->isInlineBuiltinDeclaration())
- return false;
- return true;
-}
-
static CGCallee EmitDirectCallee(CodeGenFunction &CGF, GlobalDecl GD) {
const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
@@ -6645,7 +6627,7 @@ static CGCallee EmitDirectCallee(CodeGenFunction &CGF, GlobalDecl GD) {
// When directing calling an inline builtin, call it through it's mangled
// name to make it clear it's not the actual builtin.
if (CGF.CurFn->getName() != FDInlineName &&
- OnlyHasInlineBuiltinDeclaration(FD)) {
+ CodeGenUtils::onlyHasInlineBuiltinDeclaration(FD)) {
llvm::Constant *CalleePtr = CGF.CGM.getRawFunctionPointer(GD);
llvm::Function *Fn = llvm::cast<llvm::Function>(CalleePtr);
llvm::Module *M = Fn->getParent();
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index f18978c7a936e..ff0ed1473d7df 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -25,6 +25,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/CodeGenUtils/ExprUtils.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalVariable.h"
@@ -490,29 +491,6 @@ void AggExprEmitter::VisitCXXStdInitializerListExpr(
"Expected std::initializer_list to only have two fields");
}
-/// Determine if E is a trivial array filler, that is, one that is
-/// equivalent to zero-initialization.
-static bool isTrivialFiller(Expr *E) {
- if (!E)
- return true;
-
- if (isa<ImplicitValueInitExpr>(E))
- return true;
-
- if (auto *ILE = dyn_cast<InitListExpr>(E)) {
- if (ILE->getNumInits())
- return false;
- return isTrivialFiller(ILE->getArrayFiller());
- }
-
- if (auto *Cons = dyn_cast_or_null<CXXConstructExpr>(E))
- return Cons->getConstructor()->isDefaultConstructor() &&
- Cons->getConstructor()->isTrivial();
-
- // FIXME: Are there other cases where we can avoid emitting an initializer?
- return false;
-}
-
// emit an elementwise cast where the RHS is a scalar or vector
// or emit an aggregate splat cast
static void EmitHLSLScalarElementwiseAndSplatCasts(CodeGenFunction &CGF,
@@ -698,7 +676,7 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,
}
// Check whether there's a non-trivial array-fill expression.
- bool hasTrivialFiller = isTrivialFiller(ArrayFiller);
+ bool hasTrivialFiller = CodeGenUtils::isTrivialFiller(ArrayFiller);
// Any remaining elements need to be zero-initialized, possibly
// using the filler expression. We can skip this if the we're
@@ -1322,71 +1300,6 @@ void AggExprEmitter::VisitPointerToDataMemberBinaryOperator(
EmitFinalDestCopy(E->getType(), LV);
}
-/// Is the value of the given expression possibly a reference to or
-/// into a __block variable?
-static bool isBlockVarRef(const Expr *E) {
- // Make sure we look through parens.
- E = E->IgnoreParens();
-
- // Check for a direct reference to a __block variable.
- if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
- const VarDecl *var = dyn_cast<VarDecl>(DRE->getDecl());
- return (var && var->hasAttr<BlocksAttr>());
- }
-
- // More complicated stuff.
-
- // Binary operators.
- if (const BinaryOperator *op = dyn_cast<BinaryOperator>(E)) {
- // For an assignment or pointer-to-member operation, just care
- // about the LHS.
- if (op->isAssignmentOp() || op->isPtrMemOp())
- return isBlockVarRef(op->getLHS());
-
- // For a comma, just care about the RHS.
- if (op->getOpcode() == BO_Comma)
- return isBlockVarRef(op->getRHS());
-
- // FIXME: pointer arithmetic?
- return false;
-
- // Check both sides of a conditional operator.
- } else if (const AbstractConditionalOperator *op =
- dyn_cast<AbstractConditionalOperator>(E)) {
- return isBlockVarRef(op->getTrueExpr()) ||
- isBlockVarRef(op->getFalseExpr());
-
- // OVEs are required to support BinaryConditionalOperators.
- } else if (const OpaqueValueExpr *op = dyn_cast<OpaqueValueExpr>(E)) {
- if (const Expr *src = op->getSourceExpr())
- return isBlockVarRef(src);
-
- // Casts are necessary to get things like (*(int*)&var) = foo().
- // We don't really care about the kind of cast here, except
- // we don't want to look through l2r casts, because it's okay
- // to get the *value* in a __block variable.
- } else if (const CastExpr *cast = dyn_cast<CastExpr>(E)) {
- if (cast->getCastKind() == CK_LValueToRValue)
- return false;
- return isBlockVarRef(cast->getSubExpr());
-
- // Handle unary operators. Again, just aggressively look through
- // it, ignoring the operation.
- } else if (const UnaryOperator *uop = dyn_cast<UnaryOperator>(E)) {
- return isBlockVarRef(uop->getSubExpr());
-
- // Look into the base of a field access.
- } else if (const MemberExpr *mem = dyn_cast<MemberExpr>(E)) {
- return isBlockVarRef(mem->getBase());
-
- // Look into the base of a subscript.
- } else if (const ArraySubscriptExpr *sub = dyn_cast<ArraySubscriptExpr>(E)) {
- return isBlockVarRef(sub->getBase());
- }
-
- return false;
-}
-
void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
ApplyAtomGroup Grp(CGF.getDebugInfo());
// For an assignment to work, the value on the right has
@@ -1399,7 +1312,7 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
// potentially cause a block copy, we need to evaluate the RHS first
// so that the assignment goes the right place.
// This is pretty semantically fragile.
- if (isBlockVarRef(E->getLHS()) &&
+ if (CodeGenUtils::isBlockVarRef(E->getLHS()) &&
E->getRHS()->HasSideEffects(CGF.getContext())) {
// Ensure that we have a destination, and evaluate the RHS into that.
EnsureDest(E->getRHS()->getType());
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 7b90fac46be0a..1410433237c49 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -33,6 +33,7 @@
#include "clang/Basic/CodeGenOptions.h"
#include "clang/Basic/DiagnosticTrap.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/CodeGenUtils/ExprUtils.h"
#include "llvm/ADT/APFixedPoint.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/IR/Argument.h"
@@ -5878,24 +5879,6 @@ Value *ScalarExprEmitter::VisitBinComma(const BinaryOperator *E) {
// Other Operators
//===----------------------------------------------------------------------===//
-/// isCheapEnoughToEvaluateUnconditionally - Return true if the specified
-/// expression is cheap enough and side-effect-free enough to evaluate
-/// unconditionally instead of conditionally. This is used to convert control
-/// flow into selects in some cases.
-static bool isCheapEnoughToEvaluateUnconditionally(const Expr *E,
- CodeGenFunction &CGF) {
- // Anything that is an integer or floating point constant is fine.
- return E->IgnoreParens()->isEvaluatable(CGF.getContext());
-
- // Even non-volatile automatic variables can't be evaluated unconditionally.
- // Referencing a thread_local may cause non-trivial initialization work to
- // occur. If we're inside a lambda and one of the variables is from the scope
- // outside the lambda, that function may have returned already. Reading its
- // locals is a bad idea. Also, these reads may introduce races there didn't
- // exist in the source-level program.
-}
-
-
Value *ScalarExprEmitter::
VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
TestAndClearIgnoreResultAssign();
@@ -6001,8 +5984,10 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
// select instead of as control flow. We can only do this if it is cheap and
// safe to evaluate the LHS and RHS unconditionally.
if (!llvm::EnableSingleByteCoverage &&
- isCheapEnoughToEvaluateUnconditionally(lhsExpr, CGF) &&
- isCheapEnoughToEvaluateUnconditionally(rhsExpr, CGF)) {
+ CodeGenUtils::isCheapEnoughToEvaluateUnconditionally(lhsExpr,
+ CGF.getContext()) &&
+ CodeGenUtils::isCheapEnoughToEvaluateUnconditionally(rhsExpr,
+ CGF.getContext())) {
llvm::Value *CondV = CGF.EvaluateExprAsBool(condExpr);
llvm::Value *StepV = Builder.CreateZExtOrBitCast(CondV, CGF.Int64Ty);
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index fe39235fcd4f6..745423945ca83 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -37,6 +37,7 @@
#include "clang/Basic/TargetInfo.h"
#include "clang/CodeGen/CGFunctionInfo.h"
#include "clang/CodeGenUtils/CodeGenUtils.h"
+#include "clang/CodeGenUtils/FunctionUtils.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/Frontend/OpenMP/OMPIRBuilder.h"
@@ -59,32 +60,14 @@
using namespace clang;
using namespace CodeGen;
-/// shouldEmitLifetimeMarkers - Decide whether we need emit the life-time
-/// markers.
-static bool shouldEmitLifetimeMarkers(const CodeGenOptions &CGOpts,
- const LangOptions &LangOpts) {
- if (CGOpts.DisableLifetimeMarkers)
- return false;
-
- // Sanitizers may use markers.
- if (CGOpts.SanitizeAddressUseAfterScope ||
- LangOpts.Sanitize.has(SanitizerKind::HWAddress) ||
- LangOpts.Sanitize.has(SanitizerKind::Memory) ||
- LangOpts.Sanitize.has(SanitizerKind::MemtagStack))
- return true;
-
- // For now, only in optimized builds.
- return CGOpts.OptimizationLevel != 0;
-}
-
CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext)
: CodeGenTypeCache(cgm), CGM(cgm), Target(cgm.getTarget()),
Builder(cgm, cgm.getModule().getContext(), CGBuilderInserterTy(this)),
SanOpts(CGM.getLangOpts().Sanitize), CurFPFeatures(CGM.getLangOpts()),
DebugInfo(CGM.getModuleDebugInfo()),
PGO(std::make_unique<CodeGenPGO>(cgm)),
- ShouldEmitLifetimeMarkers(
- shouldEmitLifetimeMarkers(CGM.getCodeGenOpts(), CGM.getLangOpts())) {
+ ShouldEmitLifetimeMarkers(CodeGenUtils::shouldEmitLifetimeMarkers(
+ CGM.getCodeGenOpts(), CGM.getLangOpts())) {
if (!suppressNewContext)
CGM.getCXXABI().getMangleContext().startNewFunction();
EHStack.setCGF(this);
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index c17813140b10f..42d4a15adc46c 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -31,6 +31,7 @@
#include "clang/AST/Type.h"
#include "clang/Basic/PointerAuthOptions.h"
#include "clang/CodeGen/ConstantInitBuilder.h"
+#include "clang/CodeGenUtils/ItaniumCXXABIUtils.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/Instructions.h"
@@ -1554,58 +1555,6 @@ static llvm::FunctionCallee getBadCastFn(CodeGenFunction &CGF) {
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_bad_cast");
}
-/// Compute the src2dst_offset hint as described in the
-/// Itanium C++ ABI [2.9.7]
-static CharUnits computeOffsetHint(ASTContext &Context,
- const CXXRecordDecl *Src,
- const CXXRecordDecl *Dst) {
- CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
- /*DetectVirtual=*/false);
-
- // If Dst is not derived from Src we can skip the whole computation below and
- // return that Src is not a public base of Dst. Record all inheritance paths.
- if (!Dst->isDerivedFrom(Src, Paths))
- return CharUnits::fromQuantity(-2ULL);
-
- unsigned NumPublicPaths = 0;
- CharUnits Offset;
-
- // Now walk all possible inheritance paths.
- for (const CXXBasePath &Path : Paths) {
- if (Path.Access != AS_public) // Ignore non-public inheritance.
- continue;
-
- ++NumPublicPaths;
-
- for (const CXXBasePathElement &PathElement : Path) {
- // If the path contains a virtual base class we can't give any hint.
- // -1: no hint.
- if (PathElement.Base->isVirtual())
- return CharUnits::fromQuantity(-1ULL);
-
- if (NumPublicPaths > 1) // Won't use offsets, skip computation.
- continue;
-
- // Accumulate the base class offsets.
- const ASTRecordLayout &L = Context.getASTRecordLayout(PathElement.Class);
- Offset += L.getBaseClassOffset(
- PathElement.Base->getType()->getAsCXXRecordDecl());
- }
- }
-
- // -2: Src is not a public base of Dst.
- if (NumPublicPaths == 0)
- return CharUnits::fromQuantity(-2ULL);
-
- // -3: Src is a multiple public base type but never a virtual base type.
- if (NumPublicPaths > 1)
- return CharUnits::fromQuantity(-3ULL);
-
- // Otherwise, the Src type is a unique public nonvirtual base type of Dst.
- // Return the offset of Src from the origin of Dst.
- return Offset;
-}
-
static llvm::FunctionCallee getBadTypeidFn(CodeGenFunction &CGF) {
// void __cxa_bad_typeid();
llvm::FunctionType *FTy = llvm::FunctionType::get(CGF.VoidTy, false);
@@ -1667,7 +1616,8 @@ llvm::Value *ItaniumCXXABI::emitDynamicCastCall(
const CXXRecordDecl *DestDecl = DestRecordTy->getAsCXXRecordDecl();
llvm::Value *OffsetHint = llvm::ConstantInt::getSigned(
PtrDiffLTy,
- computeOffsetHint(CGF.getContext(), SrcDecl, DestDecl).getQuantity());
+ CodeGenUtils::computeOffsetHint(CGF.getContext(), SrcDecl, DestDecl)
+ .getQuantity());
// Emit the call to __dynamic_cast.
llvm::Value *Value = ThisAddr.emitRawPointer(CGF);
diff --git a/clang/lib/CodeGenUtils/CMakeLists.txt b/clang/lib/CodeGenUtils/CMakeLists.txt
index b87c83b42dd9b..e3328aa13c343 100644
--- a/clang/lib/CodeGenUtils/CMakeLists.txt
+++ b/clang/lib/CodeGenUtils/CMakeLists.txt
@@ -3,7 +3,12 @@ set(LLVM_LINK_COMPONENTS
)
add_clang_library(clangCodeGenUtils
+ CallUtils.cpp
+ ClassUtils.cpp
CodeGenUtils.cpp
+ ExprUtils.cpp
+ FunctionUtils.cpp
+ ItaniumCXXABIUtils.cpp
LINK_LIBS
clangAST
diff --git a/clang/lib/CodeGenUtils/CallUtils.cpp b/clang/lib/CodeGenUtils/CallUtils.cpp
new file mode 100644
index 0000000000000..9eb3c7cf0bc04
--- /dev/null
+++ b/clang/lib/CodeGenUtils/CallUtils.cpp
@@ -0,0 +1,28 @@
+//===--- CallUtils.cpp - Shared call emission queries ---------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/CodeGenUtils/CallUtils.h"
+
+namespace clang::CodeGenUtils {
+
+CanQual<FunctionProtoType> getFormalType(const CXXMethodDecl *MD) {
+ return MD->getType()
+ ->getCanonicalTypeUnqualified()
+ .getAs<FunctionProtoType>();
+}
+
+llvm::FPClassTest getNoFPClassTestMask(const LangOptions &LangOpts) {
+ llvm::FPClassTest Mask = llvm::fcNone;
+ if (LangOpts.NoHonorInfs)
+ Mask |= llvm::fcInf;
+ if (LangOpts.NoHonorNaNs)
+ Mask |= llvm::fcNan;
+ return Mask;
+}
+
+} // namespace clang::CodeGenUtils
diff --git a/clang/lib/CodeGenUtils/ClassUtils.cpp b/clang/lib/CodeGenUtils/ClassUtils.cpp
new file mode 100644
index 0000000000000..90bab38280c30
--- /dev/null
+++ b/clang/lib/CodeGenUtils/ClassUtils.cpp
@@ -0,0 +1,39 @@
+//===--- ClassUtils.cpp - Shared C++ class emission queries ---------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/CodeGenUtils/ClassUtils.h"
+#include "clang/AST/EvaluatedExprVisitor.h"
+
+namespace clang::CodeGenUtils {
+namespace {
+/// A visitor which checks whether an initializer uses 'this' in a
+/// way which requires the vtable to be properly set.
+struct DynamicThisUseChecker
+ : ConstEvaluatedExprVisitor<DynamicThisUseChecker> {
+ using super = ConstEvaluatedExprVisitor<DynamicThisUseChecker>;
+
+ bool UsesThis = false;
+
+ DynamicThisUseChecker(const ASTContext &C) : super(C) {}
+
+ // Black-list all explicit and implicit references to 'this'.
+ //
+ // Do we need to worry about external references to 'this' derived
+ // from arbitrary code? If so, then anything which runs arbitrary
+ // external code might potentially access the vtable.
+ void VisitCXXThisExpr(const CXXThisExpr *E) { UsesThis = true; }
+};
+} // namespace
+
+bool baseInitializerUsesThis(ASTContext &Ctx, const Expr *Init) {
+ DynamicThisUseChecker Checker(Ctx);
+ Checker.Visit(Init);
+ return Checker.UsesThis;
+}
+
+} // namespace clang::CodeGenUtils
diff --git a/clang/lib/CodeGenUtils/ExprUtils.cpp b/clang/lib/CodeGenUtils/ExprUtils.cpp
new file mode 100644
index 0000000000000..69924572c3d77
--- /dev/null
+++ b/clang/lib/CodeGenUtils/ExprUtils.cpp
@@ -0,0 +1,128 @@
+//===--- ExprUtils.cpp - Shared expression emission queries ---------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/CodeGenUtils/ExprUtils.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/ExprCXX.h"
+
+namespace clang::CodeGenUtils {
+
+QualType getFixedSizeElementType(const ASTContext &Ctx,
+ const VariableArrayType *VLA) {
+ QualType EltType;
+ do {
+ EltType = VLA->getElementType();
+ } while ((VLA = Ctx.getAsVariableArrayType(EltType)));
+ return EltType;
+}
+
+bool isBlockVarRef(const Expr *E) {
+ // Make sure we look through parens.
+ E = E->IgnoreParens();
+
+ // Check for a direct reference to a __block variable.
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
+ const VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl());
+ return (Var && Var->hasAttr<BlocksAttr>());
+ }
+
+ // More complicated stuff.
+
+ // Binary operators.
+ if (const BinaryOperator *Op = dyn_cast<BinaryOperator>(E)) {
+ // For an assignment or pointer-to-member operation, just care
+ // about the LHS.
+ if (Op->isAssignmentOp() || Op->isPtrMemOp())
+ return isBlockVarRef(Op->getLHS());
+
+ // For a comma, just care about the RHS.
+ if (Op->getOpcode() == BO_Comma)
+ return isBlockVarRef(Op->getRHS());
+
+ // FIXME: pointer arithmetic?
+ return false;
+
+ // Check both sides of a conditional operator.
+ } else if (const AbstractConditionalOperator *Op =
+ dyn_cast<AbstractConditionalOperator>(E)) {
+ return isBlockVarRef(Op->getTrueExpr()) ||
+ isBlockVarRef(Op->getFalseExpr());
+
+ // OVEs are required to support BinaryConditionalOperators.
+ } else if (const OpaqueValueExpr *Op = dyn_cast<OpaqueValueExpr>(E)) {
+ if (const Expr *Src = Op->getSourceExpr())
+ return isBlockVarRef(Src);
+
+ // Casts are necessary to get things like (*(int*)&var) = foo().
+ // We don't really care about the kind of cast here, except
+ // we don't want to look through l2r casts, because it's okay
+ // to get the *value* in a __block variable.
+ } else if (const CastExpr *Cast = dyn_cast<CastExpr>(E)) {
+ if (Cast->getCastKind() == CK_LValueToRValue)
+ return false;
+ return isBlockVarRef(Cast->getSubExpr());
+
+ // Handle unary operators. Again, just aggressively look through
+ // it, ignoring the operation.
+ } else if (const UnaryOperator *UOp = dyn_cast<UnaryOperator>(E)) {
+ return isBlockVarRef(UOp->getSubExpr());
+
+ // Look into the base of a field access.
+ } else if (const MemberExpr *Mem = dyn_cast<MemberExpr>(E)) {
+ return isBlockVarRef(Mem->getBase());
+
+ // Look into the base of a subscript.
+ } else if (const ArraySubscriptExpr *Sub = dyn_cast<ArraySubscriptExpr>(E)) {
+ return isBlockVarRef(Sub->getBase());
+ }
+
+ return false;
+}
+
+bool isCheapEnoughToEvaluateUnconditionally(const Expr *E,
+ const ASTContext &Ctx) {
+ // Anything that is an integer or floating point constant is fine.
+ return E->IgnoreParens()->isEvaluatable(Ctx);
+
+ // Even non-volatile automatic variables can't be evaluated unconditionally.
+ // Referencing a thread_local may cause non-trivial initialization work to
+ // occur. If we're inside a lambda and one of the variables is from the scope
+ // outside the lambda, that function may have returned already. Reading its
+ // locals is a bad idea. Also, these reads may introduce races there didn't
+ // exist in the source-level program.
+}
+
+bool isTrivialFiller(const Expr *E) {
+ if (!E)
+ return true;
+
+ if (isa<ImplicitValueInitExpr>(E))
+ return true;
+
+ if (const auto *ILE = dyn_cast<InitListExpr>(E)) {
+ if (ILE->getNumInits())
+ return false;
+ return isTrivialFiller(ILE->getArrayFiller());
+ }
+
+ if (const auto *Cons = dyn_cast_or_null<CXXConstructExpr>(E))
+ return Cons->getConstructor()->isDefaultConstructor() &&
+ Cons->getConstructor()->isTrivial();
+
+ // FIXME: Are there other cases where we can avoid emitting an initializer?
+ return false;
+}
+
+bool onlyHasInlineBuiltinDeclaration(const FunctionDecl *FD) {
+ for (const FunctionDecl *PD = FD; PD; PD = PD->getPreviousDecl())
+ if (!PD->isInlineBuiltinDeclaration())
+ return false;
+ return true;
+}
+
+} // namespace clang::CodeGenUtils
diff --git a/clang/lib/CodeGenUtils/FunctionUtils.cpp b/clang/lib/CodeGenUtils/FunctionUtils.cpp
new file mode 100644
index 0000000000000..9f01745abbf82
--- /dev/null
+++ b/clang/lib/CodeGenUtils/FunctionUtils.cpp
@@ -0,0 +1,29 @@
+//===--- FunctionUtils.cpp - Shared function emission queries -------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/CodeGenUtils/FunctionUtils.h"
+
+namespace clang::CodeGenUtils {
+
+bool shouldEmitLifetimeMarkers(const CodeGenOptions &CGOpts,
+ const LangOptions &LangOpts) {
+ if (CGOpts.DisableLifetimeMarkers)
+ return false;
+
+ // Sanitizers may use markers.
+ if (CGOpts.SanitizeAddressUseAfterScope ||
+ LangOpts.Sanitize.has(SanitizerKind::HWAddress) ||
+ LangOpts.Sanitize.has(SanitizerKind::Memory) ||
+ LangOpts.Sanitize.has(SanitizerKind::MemtagStack))
+ return true;
+
+ // For now, only in optimized builds.
+ return CGOpts.OptimizationLevel != 0;
+}
+
+} // namespace clang::CodeGenUtils
diff --git a/clang/lib/CodeGenUtils/ItaniumCXXABIUtils.cpp b/clang/lib/CodeGenUtils/ItaniumCXXABIUtils.cpp
new file mode 100644
index 0000000000000..9640bd23cca54
--- /dev/null
+++ b/clang/lib/CodeGenUtils/ItaniumCXXABIUtils.cpp
@@ -0,0 +1,64 @@
+//===--- ItaniumCXXABIUtils.cpp - Shared Itanium C++ ABI queries ----------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/CodeGenUtils/ItaniumCXXABIUtils.h"
+#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/RecordLayout.h"
+
+namespace clang::CodeGenUtils {
+
+CharUnits computeOffsetHint(ASTContext &Ctx, const CXXRecordDecl *Src,
+ const CXXRecordDecl *Dst) {
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
+ /*DetectVirtual=*/false);
+
+ // If Dst is not derived from Src we can skip the whole computation below and
+ // return that Src is not a public base of Dst. Record all inheritance paths.
+ if (!Dst->isDerivedFrom(Src, Paths))
+ return CharUnits::fromQuantity(-2ULL);
+
+ unsigned NumPublicPaths = 0;
+ CharUnits Offset;
+
+ // Now walk all possible inheritance paths.
+ for (const CXXBasePath &Path : Paths) {
+ if (Path.Access != AS_public) // Ignore non-public inheritance.
+ continue;
+
+ ++NumPublicPaths;
+
+ for (const CXXBasePathElement &PathElement : Path) {
+ // If the path contains a virtual base class we can't give any hint.
+ // -1: no hint.
+ if (PathElement.Base->isVirtual())
+ return CharUnits::fromQuantity(-1ULL);
+
+ if (NumPublicPaths > 1) // Won't use offsets, skip computation.
+ continue;
+
+ // Accumulate the base class offsets.
+ const ASTRecordLayout &L = Ctx.getASTRecordLayout(PathElement.Class);
+ Offset += L.getBaseClassOffset(
+ PathElement.Base->getType()->getAsCXXRecordDecl());
+ }
+ }
+
+ // -2: Src is not a public base of Dst.
+ if (NumPublicPaths == 0)
+ return CharUnits::fromQuantity(-2ULL);
+
+ // -3: Src is a multiple public base type but never a virtual base type.
+ if (NumPublicPaths > 1)
+ return CharUnits::fromQuantity(-3ULL);
+
+ // Otherwise, the Src type is a unique public nonvirtual base type of Dst.
+ // Return the offset of Src from the origin of Dst.
+ return Offset;
+}
+
+} // namespace clang::CodeGenUtils
More information about the cfe-commits
mailing list