-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[CIR] Lower calls to trivial copy constructor to cir::CopyOp #168281
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
@llvm/pr-subscribers-clang Author: Hendrik Hübner (HendrikHuebner) ChangesThis PR is a follow up to #167975 and replaces calls to trivial copy constructors with Patch is 28.85 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/168281.diff 14 Files Affected:
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index 1e0fb038b19d8..07a5b1f3a06c8 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -822,6 +822,120 @@ def CIR_GlobalDtorAttr : CIR_GlobalCtorDtor<"Dtor", "dtor"> {
}];
}
+//===----------------------------------------------------------------------===//
+// CXX SpecialMemberAttr
+//===----------------------------------------------------------------------===//
+
+def CIR_CtorKind : CIR_I32EnumAttr<"CtorKind", "CXX Constructor Kind", [
+ I32EnumAttrCase<"Custom", 0, "custom">,
+ I32EnumAttrCase<"Default", 1, "default">,
+ I32EnumAttrCase<"Copy", 2, "copy">,
+ I32EnumAttrCase<"Move", 3, "move">,
+]> {
+ let genSpecializedAttr = 0;
+}
+
+
+def CIR_CXXCtorAttr : CIR_Attr<"CXXCtor", "cxx_ctor"> {
+ let summary = "Marks a function as a C++ constructor";
+ let description = [{
+ This attribute identifies a C++ constructor and classifies its kind:
+
+ - `custom`: a user-defined constructor
+ - `default`: a default constructor
+ - `copy`: a copy constructor
+ - `move`: a move constructor
+
+ Example:
+ ```mlir
+ #cir.cxx_ctor<!rec_a, copy>
+ #cir.cxx_ctor<!rec_b, default, trivial>
+ ```
+ }];
+
+ let parameters = (ins
+ "mlir::Type":$type,
+ EnumParameter<CIR_CtorKind>:$ctor_kind,
+ DefaultValuedParameter<"bool", "false">:$is_trivial
+ );
+
+ let builders = [
+ AttrBuilderWithInferredContext<(ins "mlir::Type":$type,
+ CArg<"CtorKind", "cir::CtorKind::Custom">:$ctorKind,
+ CArg<"bool", "false">:$isTrivial), [{
+ return $_get(type.getContext(), type, ctorKind, isTrivial);
+ }]>,
+ ];
+
+ let assemblyFormat = [{
+ `<` $type `,` $ctor_kind (`,` `trivial` $is_trivial^)? `>`
+ }];
+}
+
+def CIR_CXXDtorAttr : CIR_Attr<"CXXDtor", "cxx_dtor"> {
+ let summary = "Marks a function as a CXX destructor";
+ let description = [{
+ This attribute identifies a C++ destructor.
+ }];
+
+ let parameters = (ins
+ "mlir::Type":$type,
+ DefaultValuedParameter<"bool", "false">:$is_trivial
+ );
+
+ let builders = [
+ AttrBuilderWithInferredContext<(ins "mlir::Type":$type,
+ CArg<"bool", "false">:$isTrivial), [{
+ return $_get(type.getContext(), type, isTrivial);
+ }]>
+ ];
+
+ let assemblyFormat = [{
+ `<` $type (`,` `trivial` $is_trivial^)? `>`
+ }];
+}
+
+def CIR_AssignKind : CIR_I32EnumAttr<"AssignKind", "CXX Assignment Operator Kind", [
+ I32EnumAttrCase<"Copy", 0, "copy">,
+ I32EnumAttrCase<"Move", 1, "move">,
+]> {
+ let genSpecializedAttr = 0;
+}
+
+def CIR_CXXAssignAttr : CIR_Attr<"CXXAssign", "cxx_assign"> {
+ let summary = "Marks a function as a CXX assignment operator";
+ let description = [{
+ This attribute identifies a C++ assignment operator and classifies its kind:
+
+ - `copy`: a copy assignment
+ - `move`: a move assignment
+ }];
+
+ let parameters = (ins
+ "mlir::Type":$type,
+ EnumParameter<CIR_AssignKind>:$assign_kind,
+ DefaultValuedParameter<"bool", "false">:$is_trivial
+ );
+
+ let builders = [
+ AttrBuilderWithInferredContext<(ins "mlir::Type":$type,
+ CArg<"AssignKind">:$assignKind,
+ CArg<"bool", "false">:$isTrivial), [{
+ return $_get(type.getContext(), type, assignKind, isTrivial);
+ }]>
+ ];
+
+ let assemblyFormat = [{
+ `<` $type `,` $assign_kind (`,` `trivial` $is_trivial^)? `>`
+ }];
+}
+
+def CIR_CXXSpecialMemberAttr : AnyAttrOf<[
+ CIR_CXXCtorAttr,
+ CIR_CXXDtorAttr,
+ CIR_CXXAssignAttr
+]>;
+
//===----------------------------------------------------------------------===//
// BitfieldInfoAttr
//===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 2124b1dc62a81..3c7693979c403 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -2533,7 +2533,9 @@ def CIR_FuncOp : CIR_Op<"func", [
OptionalAttr<DictArrayAttr>:$res_attrs,
OptionalAttr<FlatSymbolRefAttr>:$aliasee,
CIR_OptionalPriorityAttr:$global_ctor_priority,
- CIR_OptionalPriorityAttr:$global_dtor_priority);
+ CIR_OptionalPriorityAttr:$global_dtor_priority,
+ OptionalAttr<CIR_CXXSpecialMemberAttr>:$cxx_special_member
+ );
let regions = (region AnyRegion:$body);
@@ -2572,7 +2574,33 @@ def CIR_FuncOp : CIR_Op<"func", [
//===------------------------------------------------------------------===//
bool isDeclaration();
- }];
+
+ //===------------------------------------------------------------------===//
+ // C++ Special Member Functions
+ //===------------------------------------------------------------------===//
+
+ /// Returns true if this function is a C++ special member function.
+ bool isCXXSpecialMemberFunction();
+
+ bool isCxxConstructor();
+
+ bool isCxxDestructor();
+
+ /// Returns true if this function is a copy or move assignment operator.
+ bool isCxxSpecialAssignment();
+
+ /// Returns the kind of constructor this function represents, if any.
+ std::optional<CtorKind> getCxxConstructorKind();
+
+ /// Returns the kind of assignment operator (move, copy) this function
+ /// represents, if any.
+ std::optional<AssignKind> getCxxSpecialAssignKind();
+
+ /// Returns true if the function is a trivial C++ member functions such as
+ /// trivial default constructor, copy/move constructor, copy/move assignment,
+ /// or destructor.
+ bool isCxxTrivialMemberFunction();
+}];
let hasCustomAssemblyFormat = 1;
let hasVerifier = 1;
diff --git a/clang/lib/CIR/CodeGen/CIRGenClass.cpp b/clang/lib/CIR/CodeGen/CIRGenClass.cpp
index a8296782ebc40..7e6050012b09d 100644
--- a/clang/lib/CIR/CodeGen/CIRGenClass.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp
@@ -18,6 +18,7 @@
#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"
using namespace clang;
@@ -786,6 +787,8 @@ void CIRGenFunction::emitImplicitAssignmentOperatorBody(FunctionArgList &args) {
"Body of an implicit assignment operator should be compound stmt.");
const auto *rootCS = cast<CompoundStmt>(rootS);
+ cgm.setCXXSpecialMemberAttr(cast<cir::FuncOp>(curFn), assignOp);
+
assert(!cir::MissingFeatures::incrementProfileCounter());
assert(!cir::MissingFeatures::runCleanupsScope());
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index 866fda3166f41..be80df3091655 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -560,7 +560,7 @@ static void eraseEmptyAndUnusedBlocks(cir::FuncOp func) {
cir::FuncOp CIRGenFunction::generateCode(clang::GlobalDecl gd, cir::FuncOp fn,
cir::FuncType funcType) {
- const auto funcDecl = cast<FunctionDecl>(gd.getDecl());
+ const auto *funcDecl = cast<FunctionDecl>(gd.getDecl());
curGD = gd;
if (funcDecl->isInlineBuiltinDeclaration()) {
@@ -630,6 +630,7 @@ cir::FuncOp CIRGenFunction::generateCode(clang::GlobalDecl gd, cir::FuncOp fn,
{
LexicalScope lexScope(*this, fusedLoc, entryBB);
+ // Emit the standard function prologue.
startFunction(gd, retTy, fn, funcType, args, loc, bodyRange.getBegin());
// Save parameters for coroutine function.
@@ -656,6 +657,7 @@ cir::FuncOp CIRGenFunction::generateCode(clang::GlobalDecl gd, cir::FuncOp fn,
// copy-constructors.
emitImplicitAssignmentOperatorBody(args);
} else if (body) {
+ // Emit standard function body.
if (mlir::failed(emitFunctionBody(body))) {
return nullptr;
}
@@ -683,6 +685,8 @@ void CIRGenFunction::emitConstructorBody(FunctionArgList &args) {
ctorType == Ctor_Complete) &&
"can only generate complete ctor for this ABI");
+ cgm.setCXXSpecialMemberAttr(cast<cir::FuncOp>(curFn), ctor);
+
if (ctorType == Ctor_Complete && isConstructorDelegationValid(ctor) &&
cgm.getTarget().getCXXABI().hasConstructorVariants()) {
emitDelegateCXXConstructorCall(ctor, Ctor_Base, args, ctor->getEndLoc());
@@ -721,6 +725,8 @@ void CIRGenFunction::emitDestructorBody(FunctionArgList &args) {
const CXXDestructorDecl *dtor = cast<CXXDestructorDecl>(curGD.getDecl());
CXXDtorType dtorType = curGD.getDtorType();
+ cgm.setCXXSpecialMemberAttr(cast<cir::FuncOp>(curFn), dtor);
+
// For an abstract class, non-base destructors are never used (and can't
// be emitted in general, because vbase dtors may not have been validated
// by Sema), but the Itanium ABI doesn't make them optional and Clang may
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index c1f2581eb96e3..3b9c5cfbb0243 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -2211,6 +2211,9 @@ CIRGenModule::createCIRFunction(mlir::Location loc, StringRef name,
assert(!cir::MissingFeatures::opFuncExtraAttrs());
+ // Mark C++ special member functions (Constructor, Destructor etc.)
+ setCXXSpecialMemberAttr(func, funcDecl);
+
if (!cgf)
theModule.push_back(func);
}
@@ -2226,6 +2229,58 @@ CIRGenModule::createCIRBuiltinFunction(mlir::Location loc, StringRef name,
return fnOp;
}
+static cir::CtorKind getCtorKindFromDecl(const CXXConstructorDecl *ctor) {
+ if (ctor->isDefaultConstructor())
+ return cir::CtorKind::Default;
+ if (ctor->isCopyConstructor())
+ return cir::CtorKind::Copy;
+ if (ctor->isMoveConstructor())
+ return cir::CtorKind::Move;
+ return cir::CtorKind::Custom;
+}
+
+static cir::AssignKind getAssignKindFromDecl(const CXXMethodDecl *method) {
+ if (method->isCopyAssignmentOperator())
+ return cir::AssignKind::Copy;
+ if (method->isMoveAssignmentOperator())
+ return cir::AssignKind::Move;
+ llvm_unreachable("not a copy or move assignment operator");
+}
+
+void CIRGenModule::setCXXSpecialMemberAttr(
+ cir::FuncOp funcOp, const clang::FunctionDecl *funcDecl) {
+ if (!funcDecl)
+ return;
+
+ if (const auto *dtor = dyn_cast<CXXDestructorDecl>(funcDecl)) {
+ auto cxxDtor = cir::CXXDtorAttr::get(
+ convertType(getASTContext().getCanonicalTagType(dtor->getParent())),
+ dtor->isTrivial());
+ funcOp.setCxxSpecialMemberAttr(cxxDtor);
+ return;
+ }
+
+ if (const auto *ctor = dyn_cast<CXXConstructorDecl>(funcDecl)) {
+ cir::CtorKind kind = getCtorKindFromDecl(ctor);
+ auto cxxCtor = cir::CXXCtorAttr::get(
+ convertType(getASTContext().getCanonicalTagType(ctor->getParent())),
+ kind, ctor->isTrivial());
+ funcOp.setCxxSpecialMemberAttr(cxxCtor);
+ return;
+ }
+
+ const auto *method = dyn_cast<CXXMethodDecl>(funcDecl);
+ if (method && (method->isCopyAssignmentOperator() ||
+ method->isMoveAssignmentOperator())) {
+ cir::AssignKind assignKind = getAssignKindFromDecl(method);
+ auto cxxAssign = cir::CXXAssignAttr::get(
+ convertType(getASTContext().getCanonicalTagType(method->getParent())),
+ assignKind, method->isTrivial());
+ funcOp.setCxxSpecialMemberAttr(cxxAssign);
+ return;
+ }
+}
+
cir::FuncOp CIRGenModule::createRuntimeFunction(cir::FuncType ty,
StringRef name, mlir::ArrayAttr,
[[maybe_unused]] bool isLocal,
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h
index dc28d9e8e9d33..3ac88c674d66e 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.h
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.h
@@ -497,6 +497,10 @@ class CIRGenModule : public CIRGenTypeCache {
cir::FuncType ty,
const clang::FunctionDecl *fd);
+ /// Mark the function as a special member (e.g. constructor, destructor)
+ void setCXXSpecialMemberAttr(cir::FuncOp funcOp,
+ const clang::FunctionDecl *funcDecl);
+
cir::FuncOp createRuntimeFunction(cir::FuncType ty, llvm::StringRef name,
mlir::ArrayAttr = {}, bool isLocal = false,
bool assumeConvergent = false);
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 9ac5efe0e41c7..26a7a6f2831dd 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -12,9 +12,11 @@
#include "clang/CIR/Dialect/IR/CIRDialect.h"
+#include "clang/CIR/Dialect/IR/CIRAttrs.h"
#include "clang/CIR/Dialect/IR/CIROpsEnums.h"
#include "clang/CIR/Dialect/IR/CIRTypes.h"
+#include "mlir/IR/Attributes.h"
#include "mlir/IR/DialectImplementation.h"
#include "mlir/Interfaces/ControlFlowInterfaces.h"
#include "mlir/Interfaces/FunctionImplementation.h"
@@ -1658,6 +1660,7 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) {
mlir::StringAttr visNameAttr = getSymVisibilityAttrName(state.name);
mlir::StringAttr visibilityNameAttr = getGlobalVisibilityAttrName(state.name);
mlir::StringAttr dsoLocalNameAttr = getDsoLocalAttrName(state.name);
+ mlir::StringAttr specialMemberAttr = getCxxSpecialMemberAttrName(state.name);
if (::mlir::succeeded(parser.parseOptionalKeyword(builtinNameAttr.strref())))
state.addAttribute(builtinNameAttr, parser.getBuilder().getUnitAttr());
@@ -1756,6 +1759,23 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) {
return success();
};
+ // Parse CXXSpecialMember attribute
+ if (parser.parseOptionalKeyword("special_member").succeeded()) {
+ cir::CXXCtorAttr ctorAttr;
+ cir::CXXDtorAttr dtorAttr;
+ cir::CXXAssignAttr assignAttr;
+ if (parser.parseLess().failed())
+ return failure();
+ if (parser.parseOptionalAttribute(ctorAttr).has_value())
+ state.addAttribute(specialMemberAttr, ctorAttr);
+ else if (parser.parseOptionalAttribute(dtorAttr).has_value())
+ state.addAttribute(specialMemberAttr, dtorAttr);
+ else if (parser.parseOptionalAttribute(assignAttr).has_value())
+ state.addAttribute(specialMemberAttr, assignAttr);
+ if (parser.parseGreater().failed())
+ return failure();
+ }
+
if (parseGlobalDtorCtor("global_ctor", [&](std::optional<int> priority) {
mlir::IntegerAttr globalCtorPriorityAttr =
builder.getI32IntegerAttr(priority.value_or(65535));
@@ -1833,6 +1853,56 @@ bool cir::FuncOp::isDeclaration() {
return false;
}
+bool cir::FuncOp::isCXXSpecialMemberFunction() {
+ return getCxxSpecialMemberAttr() != nullptr;
+}
+
+bool cir::FuncOp::isCxxConstructor() {
+ auto attr = getCxxSpecialMemberAttr();
+ return attr && dyn_cast<CXXCtorAttr>(attr);
+}
+
+bool cir::FuncOp::isCxxDestructor() {
+ auto attr = getCxxSpecialMemberAttr();
+ return attr && dyn_cast<CXXDtorAttr>(attr);
+}
+
+bool cir::FuncOp::isCxxSpecialAssignment() {
+ auto attr = getCxxSpecialMemberAttr();
+ return attr && dyn_cast<CXXAssignAttr>(attr);
+}
+
+std::optional<CtorKind> cir::FuncOp::getCxxConstructorKind() {
+ mlir::Attribute attr = getCxxSpecialMemberAttr();
+ if (attr) {
+ if (auto ctor = dyn_cast<CXXCtorAttr>(attr))
+ return ctor.getCtorKind();
+ }
+ return std::nullopt;
+}
+
+std::optional<AssignKind> cir::FuncOp::getCxxSpecialAssignKind() {
+ mlir::Attribute attr = getCxxSpecialMemberAttr();
+ if (attr) {
+ if (auto assign = dyn_cast<CXXAssignAttr>(attr))
+ return assign.getAssignKind();
+ }
+ return std::nullopt;
+}
+
+bool cir::FuncOp::isCxxTrivialMemberFunction() {
+ mlir::Attribute attr = getCxxSpecialMemberAttr();
+ if (attr) {
+ if (auto ctor = dyn_cast<CXXCtorAttr>(attr))
+ return ctor.getIsTrivial();
+ if (auto dtor = dyn_cast<CXXDtorAttr>(attr))
+ return dtor.getIsTrivial();
+ if (auto assign = dyn_cast<CXXAssignAttr>(attr))
+ return assign.getIsTrivial();
+ }
+ return false;
+}
+
mlir::Region *cir::FuncOp::getCallableRegion() {
// TODO(CIR): This function will have special handling for aliases and a
// check for an external function, once those features have been upstreamed.
@@ -1883,6 +1953,12 @@ void cir::FuncOp::print(OpAsmPrinter &p) {
p << ")";
}
+ if (auto specialMemberAttr = getCxxSpecialMember()) {
+ p << " special_member<";
+ p.printAttribute(*specialMemberAttr);
+ p << '>';
+ }
+
if (auto globalCtorPriority = getGlobalCtorPriority()) {
p << " global_ctor";
if (globalCtorPriority.value() != 65535)
diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
index 29b1211d2c351..5aa482a661ba5 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -8,10 +8,12 @@
#include "LoweringPrepareCXXABI.h"
#include "PassDetail.h"
+#include "mlir/IR/Attributes.h"
#include "clang/AST/ASTContext.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h"
+#include "clang/CIR/Dialect/IR/CIRAttrs.h"
#include "clang/CIR/Dialect/IR/CIRDialect.h"
#include "clang/CIR/Dialect/IR/CIROpsEnums.h"
#include "clang/CIR/Dialect/Passes.h"
@@ -72,6 +74,7 @@ struct LoweringPreparePass
void lowerDynamicCastOp(cir::DynamicCastOp op);
void lowerArrayDtor(cir::ArrayDtor op);
void lowerArrayCtor(cir::ArrayCtor op);
+ void lowerTrivialCopyCall(cir::CallOp op);
/// Build the function that initializes the specified global
cir::FuncOp buildCXXGlobalVarDeclInitFunc(cir::GlobalOp op);
@@ -984,6 +987,28 @@ void LoweringPreparePass::lowerArrayCtor(cir::ArrayCtor op) {
true);
}
+void LoweringPreparePass::lowerTrivialCopyCall(cir::CallOp op) {
+ FuncOp funcOp = getCalledFunction(op);
+ if (!funcOp)
+ return;
+
+ llvm::errs() << "Lower trivial copy call: " << funcOp.getName() << "\n";
+
+ std::optional<cir::CtorKind> ctorKind = funcOp.getCxxConstructorKind();
+ if (ctorKind && *ctorKind == cir::CtorKind::Copy
+ && funcOp.isCxxTrivialMemberFunction()) {
+ llvm::outs() << "success \n";
+ // Replace the trivial copy constructor call with a `CopyOp`
+ CIRBaseBuilderTy builder(getContext());
+ auto operands = op.getOperands();
+ mlir::Value dest = operands[0];
+ mlir::Value src = operands[1];
+ builder.setInsertionPoint(op);
+ builder.createCopy(dest, src);
+ op.erase();
+ }
+}
+
void LoweringPreparePass::runOnOp(mlir::Operation *op) {
if (auto arrayCtor = dyn_cast<cir::ArrayCtor>(op)) {
lowerArrayCtor(arrayCtor);
@@ -1001,6 +1026,8 @@ void LoweringPreparePass::runOnOp(mlir::Operation *op) {
lowerDynamicCastOp(dynamicCast);
} else if (auto unary = mlir::dyn_cast<cir::UnaryOp>(op)) {
lowerUnaryOp(unary);
+ } else if (auto callOp = dyn_cast<cir::CallOp>(op)) {
+ lowerTrivialCopyCall(callOp);
} else if (auto fnOp = dyn_cast<cir::FuncOp>(op)) {
if (auto globalCtor = fnOp.getGlobalCtorPriority())
globalCtorList.emplace_back(fnOp.getName(), globalCtor.value());
@@ -1019,7 +1046,7 @@ void LoweringPreparePass::runOnOperation() {
op->walk([&](mlir::Operation *op) {
if (mlir::isa<cir::ArrayCtor, cir::ArrayDtor, cir::CastOp,
cir::ComplexMulOp, cir::ComplexDivOp, cir::DynamicCastOp,
- cir::FuncOp, cir::GlobalOp, cir::UnaryOp>(op))
+ cir::FuncOp, cir::CallOp, cir::GlobalOp, cir::UnaryOp>(op))
opsToTransform.push_back(op);
});
diff --git a/clang/test/CIR/CodeGen/cxx-special-member-attr.cpp b/clang/test/CIR/CodeGen/cxx-special-member-attr.cpp
new file mode 100644
index 0000000000000..cd1377ac04eac
--- /dev/null
+++ b/clang/test/CIR/CodeGen/cxx-special-member-attr.cpp
@@ -0,0 +1,60 @@
+// RUN: %clang_cc1 -std=c++11 -triple aarch64-none-linux-android21 -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
+
+struct Flub {
+ int a = 123;
+ // COM: Trivial copy constructors/assignments are replaced with cir.cop...
[truncated]
|
|
@llvm/pr-subscribers-clangir Author: Hendrik Hübner (HendrikHuebner) ChangesThis PR is a follow up to #167975 and replaces calls to trivial copy constructors with Patch is 28.85 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/168281.diff 14 Files Affected:
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index 1e0fb038b19d8..07a5b1f3a06c8 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -822,6 +822,120 @@ def CIR_GlobalDtorAttr : CIR_GlobalCtorDtor<"Dtor", "dtor"> {
}];
}
+//===----------------------------------------------------------------------===//
+// CXX SpecialMemberAttr
+//===----------------------------------------------------------------------===//
+
+def CIR_CtorKind : CIR_I32EnumAttr<"CtorKind", "CXX Constructor Kind", [
+ I32EnumAttrCase<"Custom", 0, "custom">,
+ I32EnumAttrCase<"Default", 1, "default">,
+ I32EnumAttrCase<"Copy", 2, "copy">,
+ I32EnumAttrCase<"Move", 3, "move">,
+]> {
+ let genSpecializedAttr = 0;
+}
+
+
+def CIR_CXXCtorAttr : CIR_Attr<"CXXCtor", "cxx_ctor"> {
+ let summary = "Marks a function as a C++ constructor";
+ let description = [{
+ This attribute identifies a C++ constructor and classifies its kind:
+
+ - `custom`: a user-defined constructor
+ - `default`: a default constructor
+ - `copy`: a copy constructor
+ - `move`: a move constructor
+
+ Example:
+ ```mlir
+ #cir.cxx_ctor<!rec_a, copy>
+ #cir.cxx_ctor<!rec_b, default, trivial>
+ ```
+ }];
+
+ let parameters = (ins
+ "mlir::Type":$type,
+ EnumParameter<CIR_CtorKind>:$ctor_kind,
+ DefaultValuedParameter<"bool", "false">:$is_trivial
+ );
+
+ let builders = [
+ AttrBuilderWithInferredContext<(ins "mlir::Type":$type,
+ CArg<"CtorKind", "cir::CtorKind::Custom">:$ctorKind,
+ CArg<"bool", "false">:$isTrivial), [{
+ return $_get(type.getContext(), type, ctorKind, isTrivial);
+ }]>,
+ ];
+
+ let assemblyFormat = [{
+ `<` $type `,` $ctor_kind (`,` `trivial` $is_trivial^)? `>`
+ }];
+}
+
+def CIR_CXXDtorAttr : CIR_Attr<"CXXDtor", "cxx_dtor"> {
+ let summary = "Marks a function as a CXX destructor";
+ let description = [{
+ This attribute identifies a C++ destructor.
+ }];
+
+ let parameters = (ins
+ "mlir::Type":$type,
+ DefaultValuedParameter<"bool", "false">:$is_trivial
+ );
+
+ let builders = [
+ AttrBuilderWithInferredContext<(ins "mlir::Type":$type,
+ CArg<"bool", "false">:$isTrivial), [{
+ return $_get(type.getContext(), type, isTrivial);
+ }]>
+ ];
+
+ let assemblyFormat = [{
+ `<` $type (`,` `trivial` $is_trivial^)? `>`
+ }];
+}
+
+def CIR_AssignKind : CIR_I32EnumAttr<"AssignKind", "CXX Assignment Operator Kind", [
+ I32EnumAttrCase<"Copy", 0, "copy">,
+ I32EnumAttrCase<"Move", 1, "move">,
+]> {
+ let genSpecializedAttr = 0;
+}
+
+def CIR_CXXAssignAttr : CIR_Attr<"CXXAssign", "cxx_assign"> {
+ let summary = "Marks a function as a CXX assignment operator";
+ let description = [{
+ This attribute identifies a C++ assignment operator and classifies its kind:
+
+ - `copy`: a copy assignment
+ - `move`: a move assignment
+ }];
+
+ let parameters = (ins
+ "mlir::Type":$type,
+ EnumParameter<CIR_AssignKind>:$assign_kind,
+ DefaultValuedParameter<"bool", "false">:$is_trivial
+ );
+
+ let builders = [
+ AttrBuilderWithInferredContext<(ins "mlir::Type":$type,
+ CArg<"AssignKind">:$assignKind,
+ CArg<"bool", "false">:$isTrivial), [{
+ return $_get(type.getContext(), type, assignKind, isTrivial);
+ }]>
+ ];
+
+ let assemblyFormat = [{
+ `<` $type `,` $assign_kind (`,` `trivial` $is_trivial^)? `>`
+ }];
+}
+
+def CIR_CXXSpecialMemberAttr : AnyAttrOf<[
+ CIR_CXXCtorAttr,
+ CIR_CXXDtorAttr,
+ CIR_CXXAssignAttr
+]>;
+
//===----------------------------------------------------------------------===//
// BitfieldInfoAttr
//===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 2124b1dc62a81..3c7693979c403 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -2533,7 +2533,9 @@ def CIR_FuncOp : CIR_Op<"func", [
OptionalAttr<DictArrayAttr>:$res_attrs,
OptionalAttr<FlatSymbolRefAttr>:$aliasee,
CIR_OptionalPriorityAttr:$global_ctor_priority,
- CIR_OptionalPriorityAttr:$global_dtor_priority);
+ CIR_OptionalPriorityAttr:$global_dtor_priority,
+ OptionalAttr<CIR_CXXSpecialMemberAttr>:$cxx_special_member
+ );
let regions = (region AnyRegion:$body);
@@ -2572,7 +2574,33 @@ def CIR_FuncOp : CIR_Op<"func", [
//===------------------------------------------------------------------===//
bool isDeclaration();
- }];
+
+ //===------------------------------------------------------------------===//
+ // C++ Special Member Functions
+ //===------------------------------------------------------------------===//
+
+ /// Returns true if this function is a C++ special member function.
+ bool isCXXSpecialMemberFunction();
+
+ bool isCxxConstructor();
+
+ bool isCxxDestructor();
+
+ /// Returns true if this function is a copy or move assignment operator.
+ bool isCxxSpecialAssignment();
+
+ /// Returns the kind of constructor this function represents, if any.
+ std::optional<CtorKind> getCxxConstructorKind();
+
+ /// Returns the kind of assignment operator (move, copy) this function
+ /// represents, if any.
+ std::optional<AssignKind> getCxxSpecialAssignKind();
+
+ /// Returns true if the function is a trivial C++ member functions such as
+ /// trivial default constructor, copy/move constructor, copy/move assignment,
+ /// or destructor.
+ bool isCxxTrivialMemberFunction();
+}];
let hasCustomAssemblyFormat = 1;
let hasVerifier = 1;
diff --git a/clang/lib/CIR/CodeGen/CIRGenClass.cpp b/clang/lib/CIR/CodeGen/CIRGenClass.cpp
index a8296782ebc40..7e6050012b09d 100644
--- a/clang/lib/CIR/CodeGen/CIRGenClass.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp
@@ -18,6 +18,7 @@
#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"
using namespace clang;
@@ -786,6 +787,8 @@ void CIRGenFunction::emitImplicitAssignmentOperatorBody(FunctionArgList &args) {
"Body of an implicit assignment operator should be compound stmt.");
const auto *rootCS = cast<CompoundStmt>(rootS);
+ cgm.setCXXSpecialMemberAttr(cast<cir::FuncOp>(curFn), assignOp);
+
assert(!cir::MissingFeatures::incrementProfileCounter());
assert(!cir::MissingFeatures::runCleanupsScope());
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index 866fda3166f41..be80df3091655 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -560,7 +560,7 @@ static void eraseEmptyAndUnusedBlocks(cir::FuncOp func) {
cir::FuncOp CIRGenFunction::generateCode(clang::GlobalDecl gd, cir::FuncOp fn,
cir::FuncType funcType) {
- const auto funcDecl = cast<FunctionDecl>(gd.getDecl());
+ const auto *funcDecl = cast<FunctionDecl>(gd.getDecl());
curGD = gd;
if (funcDecl->isInlineBuiltinDeclaration()) {
@@ -630,6 +630,7 @@ cir::FuncOp CIRGenFunction::generateCode(clang::GlobalDecl gd, cir::FuncOp fn,
{
LexicalScope lexScope(*this, fusedLoc, entryBB);
+ // Emit the standard function prologue.
startFunction(gd, retTy, fn, funcType, args, loc, bodyRange.getBegin());
// Save parameters for coroutine function.
@@ -656,6 +657,7 @@ cir::FuncOp CIRGenFunction::generateCode(clang::GlobalDecl gd, cir::FuncOp fn,
// copy-constructors.
emitImplicitAssignmentOperatorBody(args);
} else if (body) {
+ // Emit standard function body.
if (mlir::failed(emitFunctionBody(body))) {
return nullptr;
}
@@ -683,6 +685,8 @@ void CIRGenFunction::emitConstructorBody(FunctionArgList &args) {
ctorType == Ctor_Complete) &&
"can only generate complete ctor for this ABI");
+ cgm.setCXXSpecialMemberAttr(cast<cir::FuncOp>(curFn), ctor);
+
if (ctorType == Ctor_Complete && isConstructorDelegationValid(ctor) &&
cgm.getTarget().getCXXABI().hasConstructorVariants()) {
emitDelegateCXXConstructorCall(ctor, Ctor_Base, args, ctor->getEndLoc());
@@ -721,6 +725,8 @@ void CIRGenFunction::emitDestructorBody(FunctionArgList &args) {
const CXXDestructorDecl *dtor = cast<CXXDestructorDecl>(curGD.getDecl());
CXXDtorType dtorType = curGD.getDtorType();
+ cgm.setCXXSpecialMemberAttr(cast<cir::FuncOp>(curFn), dtor);
+
// For an abstract class, non-base destructors are never used (and can't
// be emitted in general, because vbase dtors may not have been validated
// by Sema), but the Itanium ABI doesn't make them optional and Clang may
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index c1f2581eb96e3..3b9c5cfbb0243 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -2211,6 +2211,9 @@ CIRGenModule::createCIRFunction(mlir::Location loc, StringRef name,
assert(!cir::MissingFeatures::opFuncExtraAttrs());
+ // Mark C++ special member functions (Constructor, Destructor etc.)
+ setCXXSpecialMemberAttr(func, funcDecl);
+
if (!cgf)
theModule.push_back(func);
}
@@ -2226,6 +2229,58 @@ CIRGenModule::createCIRBuiltinFunction(mlir::Location loc, StringRef name,
return fnOp;
}
+static cir::CtorKind getCtorKindFromDecl(const CXXConstructorDecl *ctor) {
+ if (ctor->isDefaultConstructor())
+ return cir::CtorKind::Default;
+ if (ctor->isCopyConstructor())
+ return cir::CtorKind::Copy;
+ if (ctor->isMoveConstructor())
+ return cir::CtorKind::Move;
+ return cir::CtorKind::Custom;
+}
+
+static cir::AssignKind getAssignKindFromDecl(const CXXMethodDecl *method) {
+ if (method->isCopyAssignmentOperator())
+ return cir::AssignKind::Copy;
+ if (method->isMoveAssignmentOperator())
+ return cir::AssignKind::Move;
+ llvm_unreachable("not a copy or move assignment operator");
+}
+
+void CIRGenModule::setCXXSpecialMemberAttr(
+ cir::FuncOp funcOp, const clang::FunctionDecl *funcDecl) {
+ if (!funcDecl)
+ return;
+
+ if (const auto *dtor = dyn_cast<CXXDestructorDecl>(funcDecl)) {
+ auto cxxDtor = cir::CXXDtorAttr::get(
+ convertType(getASTContext().getCanonicalTagType(dtor->getParent())),
+ dtor->isTrivial());
+ funcOp.setCxxSpecialMemberAttr(cxxDtor);
+ return;
+ }
+
+ if (const auto *ctor = dyn_cast<CXXConstructorDecl>(funcDecl)) {
+ cir::CtorKind kind = getCtorKindFromDecl(ctor);
+ auto cxxCtor = cir::CXXCtorAttr::get(
+ convertType(getASTContext().getCanonicalTagType(ctor->getParent())),
+ kind, ctor->isTrivial());
+ funcOp.setCxxSpecialMemberAttr(cxxCtor);
+ return;
+ }
+
+ const auto *method = dyn_cast<CXXMethodDecl>(funcDecl);
+ if (method && (method->isCopyAssignmentOperator() ||
+ method->isMoveAssignmentOperator())) {
+ cir::AssignKind assignKind = getAssignKindFromDecl(method);
+ auto cxxAssign = cir::CXXAssignAttr::get(
+ convertType(getASTContext().getCanonicalTagType(method->getParent())),
+ assignKind, method->isTrivial());
+ funcOp.setCxxSpecialMemberAttr(cxxAssign);
+ return;
+ }
+}
+
cir::FuncOp CIRGenModule::createRuntimeFunction(cir::FuncType ty,
StringRef name, mlir::ArrayAttr,
[[maybe_unused]] bool isLocal,
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h
index dc28d9e8e9d33..3ac88c674d66e 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.h
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.h
@@ -497,6 +497,10 @@ class CIRGenModule : public CIRGenTypeCache {
cir::FuncType ty,
const clang::FunctionDecl *fd);
+ /// Mark the function as a special member (e.g. constructor, destructor)
+ void setCXXSpecialMemberAttr(cir::FuncOp funcOp,
+ const clang::FunctionDecl *funcDecl);
+
cir::FuncOp createRuntimeFunction(cir::FuncType ty, llvm::StringRef name,
mlir::ArrayAttr = {}, bool isLocal = false,
bool assumeConvergent = false);
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 9ac5efe0e41c7..26a7a6f2831dd 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -12,9 +12,11 @@
#include "clang/CIR/Dialect/IR/CIRDialect.h"
+#include "clang/CIR/Dialect/IR/CIRAttrs.h"
#include "clang/CIR/Dialect/IR/CIROpsEnums.h"
#include "clang/CIR/Dialect/IR/CIRTypes.h"
+#include "mlir/IR/Attributes.h"
#include "mlir/IR/DialectImplementation.h"
#include "mlir/Interfaces/ControlFlowInterfaces.h"
#include "mlir/Interfaces/FunctionImplementation.h"
@@ -1658,6 +1660,7 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) {
mlir::StringAttr visNameAttr = getSymVisibilityAttrName(state.name);
mlir::StringAttr visibilityNameAttr = getGlobalVisibilityAttrName(state.name);
mlir::StringAttr dsoLocalNameAttr = getDsoLocalAttrName(state.name);
+ mlir::StringAttr specialMemberAttr = getCxxSpecialMemberAttrName(state.name);
if (::mlir::succeeded(parser.parseOptionalKeyword(builtinNameAttr.strref())))
state.addAttribute(builtinNameAttr, parser.getBuilder().getUnitAttr());
@@ -1756,6 +1759,23 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) {
return success();
};
+ // Parse CXXSpecialMember attribute
+ if (parser.parseOptionalKeyword("special_member").succeeded()) {
+ cir::CXXCtorAttr ctorAttr;
+ cir::CXXDtorAttr dtorAttr;
+ cir::CXXAssignAttr assignAttr;
+ if (parser.parseLess().failed())
+ return failure();
+ if (parser.parseOptionalAttribute(ctorAttr).has_value())
+ state.addAttribute(specialMemberAttr, ctorAttr);
+ else if (parser.parseOptionalAttribute(dtorAttr).has_value())
+ state.addAttribute(specialMemberAttr, dtorAttr);
+ else if (parser.parseOptionalAttribute(assignAttr).has_value())
+ state.addAttribute(specialMemberAttr, assignAttr);
+ if (parser.parseGreater().failed())
+ return failure();
+ }
+
if (parseGlobalDtorCtor("global_ctor", [&](std::optional<int> priority) {
mlir::IntegerAttr globalCtorPriorityAttr =
builder.getI32IntegerAttr(priority.value_or(65535));
@@ -1833,6 +1853,56 @@ bool cir::FuncOp::isDeclaration() {
return false;
}
+bool cir::FuncOp::isCXXSpecialMemberFunction() {
+ return getCxxSpecialMemberAttr() != nullptr;
+}
+
+bool cir::FuncOp::isCxxConstructor() {
+ auto attr = getCxxSpecialMemberAttr();
+ return attr && dyn_cast<CXXCtorAttr>(attr);
+}
+
+bool cir::FuncOp::isCxxDestructor() {
+ auto attr = getCxxSpecialMemberAttr();
+ return attr && dyn_cast<CXXDtorAttr>(attr);
+}
+
+bool cir::FuncOp::isCxxSpecialAssignment() {
+ auto attr = getCxxSpecialMemberAttr();
+ return attr && dyn_cast<CXXAssignAttr>(attr);
+}
+
+std::optional<CtorKind> cir::FuncOp::getCxxConstructorKind() {
+ mlir::Attribute attr = getCxxSpecialMemberAttr();
+ if (attr) {
+ if (auto ctor = dyn_cast<CXXCtorAttr>(attr))
+ return ctor.getCtorKind();
+ }
+ return std::nullopt;
+}
+
+std::optional<AssignKind> cir::FuncOp::getCxxSpecialAssignKind() {
+ mlir::Attribute attr = getCxxSpecialMemberAttr();
+ if (attr) {
+ if (auto assign = dyn_cast<CXXAssignAttr>(attr))
+ return assign.getAssignKind();
+ }
+ return std::nullopt;
+}
+
+bool cir::FuncOp::isCxxTrivialMemberFunction() {
+ mlir::Attribute attr = getCxxSpecialMemberAttr();
+ if (attr) {
+ if (auto ctor = dyn_cast<CXXCtorAttr>(attr))
+ return ctor.getIsTrivial();
+ if (auto dtor = dyn_cast<CXXDtorAttr>(attr))
+ return dtor.getIsTrivial();
+ if (auto assign = dyn_cast<CXXAssignAttr>(attr))
+ return assign.getIsTrivial();
+ }
+ return false;
+}
+
mlir::Region *cir::FuncOp::getCallableRegion() {
// TODO(CIR): This function will have special handling for aliases and a
// check for an external function, once those features have been upstreamed.
@@ -1883,6 +1953,12 @@ void cir::FuncOp::print(OpAsmPrinter &p) {
p << ")";
}
+ if (auto specialMemberAttr = getCxxSpecialMember()) {
+ p << " special_member<";
+ p.printAttribute(*specialMemberAttr);
+ p << '>';
+ }
+
if (auto globalCtorPriority = getGlobalCtorPriority()) {
p << " global_ctor";
if (globalCtorPriority.value() != 65535)
diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
index 29b1211d2c351..5aa482a661ba5 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -8,10 +8,12 @@
#include "LoweringPrepareCXXABI.h"
#include "PassDetail.h"
+#include "mlir/IR/Attributes.h"
#include "clang/AST/ASTContext.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h"
+#include "clang/CIR/Dialect/IR/CIRAttrs.h"
#include "clang/CIR/Dialect/IR/CIRDialect.h"
#include "clang/CIR/Dialect/IR/CIROpsEnums.h"
#include "clang/CIR/Dialect/Passes.h"
@@ -72,6 +74,7 @@ struct LoweringPreparePass
void lowerDynamicCastOp(cir::DynamicCastOp op);
void lowerArrayDtor(cir::ArrayDtor op);
void lowerArrayCtor(cir::ArrayCtor op);
+ void lowerTrivialCopyCall(cir::CallOp op);
/// Build the function that initializes the specified global
cir::FuncOp buildCXXGlobalVarDeclInitFunc(cir::GlobalOp op);
@@ -984,6 +987,28 @@ void LoweringPreparePass::lowerArrayCtor(cir::ArrayCtor op) {
true);
}
+void LoweringPreparePass::lowerTrivialCopyCall(cir::CallOp op) {
+ FuncOp funcOp = getCalledFunction(op);
+ if (!funcOp)
+ return;
+
+ llvm::errs() << "Lower trivial copy call: " << funcOp.getName() << "\n";
+
+ std::optional<cir::CtorKind> ctorKind = funcOp.getCxxConstructorKind();
+ if (ctorKind && *ctorKind == cir::CtorKind::Copy
+ && funcOp.isCxxTrivialMemberFunction()) {
+ llvm::outs() << "success \n";
+ // Replace the trivial copy constructor call with a `CopyOp`
+ CIRBaseBuilderTy builder(getContext());
+ auto operands = op.getOperands();
+ mlir::Value dest = operands[0];
+ mlir::Value src = operands[1];
+ builder.setInsertionPoint(op);
+ builder.createCopy(dest, src);
+ op.erase();
+ }
+}
+
void LoweringPreparePass::runOnOp(mlir::Operation *op) {
if (auto arrayCtor = dyn_cast<cir::ArrayCtor>(op)) {
lowerArrayCtor(arrayCtor);
@@ -1001,6 +1026,8 @@ void LoweringPreparePass::runOnOp(mlir::Operation *op) {
lowerDynamicCastOp(dynamicCast);
} else if (auto unary = mlir::dyn_cast<cir::UnaryOp>(op)) {
lowerUnaryOp(unary);
+ } else if (auto callOp = dyn_cast<cir::CallOp>(op)) {
+ lowerTrivialCopyCall(callOp);
} else if (auto fnOp = dyn_cast<cir::FuncOp>(op)) {
if (auto globalCtor = fnOp.getGlobalCtorPriority())
globalCtorList.emplace_back(fnOp.getName(), globalCtor.value());
@@ -1019,7 +1046,7 @@ void LoweringPreparePass::runOnOperation() {
op->walk([&](mlir::Operation *op) {
if (mlir::isa<cir::ArrayCtor, cir::ArrayDtor, cir::CastOp,
cir::ComplexMulOp, cir::ComplexDivOp, cir::DynamicCastOp,
- cir::FuncOp, cir::GlobalOp, cir::UnaryOp>(op))
+ cir::FuncOp, cir::CallOp, cir::GlobalOp, cir::UnaryOp>(op))
opsToTransform.push_back(op);
});
diff --git a/clang/test/CIR/CodeGen/cxx-special-member-attr.cpp b/clang/test/CIR/CodeGen/cxx-special-member-attr.cpp
new file mode 100644
index 0000000000000..cd1377ac04eac
--- /dev/null
+++ b/clang/test/CIR/CodeGen/cxx-special-member-attr.cpp
@@ -0,0 +1,60 @@
+// RUN: %clang_cc1 -std=c++11 -triple aarch64-none-linux-android21 -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
+
+struct Flub {
+ int a = 123;
+ // COM: Trivial copy constructors/assignments are replaced with cir.cop...
[truncated]
|
You can test this locally with the following command:git-clang-format --diff origin/main HEAD --extensions h,cpp -- clang/test/CIR/CodeGen/cxx-special-member-attr.cpp clang/lib/CIR/CodeGen/CIRGenClass.cpp clang/lib/CIR/CodeGen/CIRGenFunction.cpp clang/lib/CIR/CodeGen/CIRGenModule.cpp clang/lib/CIR/CodeGen/CIRGenModule.h clang/lib/CIR/Dialect/IR/CIRDialect.cpp clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp clang/test/CIR/CodeGen/struct.cpp clang/test/CIR/CodeGenOpenACC/combined-firstprivate-clause.cpp clang/test/CIR/CodeGenOpenACC/compute-firstprivate-clause-templates.cpp clang/test/CIR/CodeGenOpenACC/compute-firstprivate-clause.cpp --diff_from_common_commit
View the diff from clang-format here.diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
index 5aa482a66..86db27d4a 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -995,8 +995,8 @@ void LoweringPreparePass::lowerTrivialCopyCall(cir::CallOp op) {
llvm::errs() << "Lower trivial copy call: " << funcOp.getName() << "\n";
std::optional<cir::CtorKind> ctorKind = funcOp.getCxxConstructorKind();
- if (ctorKind && *ctorKind == cir::CtorKind::Copy
- && funcOp.isCxxTrivialMemberFunction()) {
+ if (ctorKind && *ctorKind == cir::CtorKind::Copy &&
+ funcOp.isCxxTrivialMemberFunction()) {
llvm::outs() << "success \n";
// Replace the trivial copy constructor call with a `CopyOp`
CIRBaseBuilderTy builder(getContext());
|
|
View the diff without the previous PR here Right now a bunch of tests are failing, but it will take quite a while to fix them all, so before I spend 2 hours+ doing that let me know your thoughts on this. Do we also want to replace trivial copy assignment operators? |
|
@HendrikHuebner once this is updated and pass tests let me know and I'll do one round of review |
| llvm::errs() << "Lower trivial copy call: " << funcOp.getName() << "\n"; | ||
|
|
||
| std::optional<cir::CtorKind> ctorKind = funcOp.getCxxConstructorKind(); | ||
| if (ctorKind && *ctorKind == cir::CtorKind::Copy |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are also cases we could handle for trivial assign operators.
This PR is a follow up to #167975 and replaces calls to trivial copy constructors with
cir::CopyOp.