[clang] [CIR] Lower calls to trivial copy constructor to cir::CopyOp (PR #168281)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Nov 16 10:36:14 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clangir
Author: Hendrik Hübner (HendrikHuebner)
<details>
<summary>Changes</summary>
This PR is a follow up to #<!-- -->167975 and replaces calls to trivial copy constructors with `cir::CopyOp`.
---
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:
- (modified) clang/include/clang/CIR/Dialect/IR/CIRAttrs.td (+114)
- (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+30-2)
- (modified) clang/lib/CIR/CodeGen/CIRGenClass.cpp (+3)
- (modified) clang/lib/CIR/CodeGen/CIRGenFunction.cpp (+7-1)
- (modified) clang/lib/CIR/CodeGen/CIRGenModule.cpp (+55)
- (modified) clang/lib/CIR/CodeGen/CIRGenModule.h (+4)
- (modified) clang/lib/CIR/Dialect/IR/CIRDialect.cpp (+76)
- (modified) clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp (+28-1)
- (added) clang/test/CIR/CodeGen/cxx-special-member-attr.cpp (+60)
- (modified) clang/test/CIR/CodeGen/struct.cpp (+1-1)
- (modified) clang/test/CIR/CodeGenOpenACC/combined-firstprivate-clause.cpp (+2-2)
- (modified) clang/test/CIR/CodeGenOpenACC/compute-firstprivate-clause-templates.cpp (+1-1)
- (modified) clang/test/CIR/CodeGenOpenACC/compute-firstprivate-clause.cpp (+3-3)
- (modified) clang/test/CIR/IR/func.cir (+34)
``````````diff
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]
``````````
</details>
https://github.com/llvm/llvm-project/pull/168281
More information about the cfe-commits
mailing list