-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[CIR] Add CxxCTorAttr, CxxDTorAttr, CxxAssignAttr, CxxSpecialMemberAttr to cir::FuncOp #167975
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
Conversation
|
@llvm/pr-subscribers-clang Author: Hendrik Hübner (HendrikHuebner) ChangesThis PR adds a special member attribute to TODO: Tests Full diff: https://github.com/llvm/llvm-project/pull/167975.diff 8 Files Affected:
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index 1e0fb038b19d8..94abe318388e7 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -822,6 +822,104 @@ 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 CXX constructor";
+ let description = [{
+ Functions with this attribute are CXX constructors.
+ The `custom` kind is used if the constructor is a custom constructor.
+ The `default` kind is used if the constructor is a default constructor.
+ The `copy` kind is used if the constructor is a copy constructor.
+ The `move` kind is used if the constructor is a move constructor.
+ }];
+ let parameters = (ins "mlir::Type":$type,
+ EnumParameter<CIR_CtorKind>:$ctorKind,
+ "bool":$is_trivial);
+
+ let assemblyFormat = [{
+ `<` $type `,` $ctorKind `,` $is_trivial `>`
+ }];
+
+ let builders = [
+ AttrBuilderWithInferredContext<(ins "mlir::Type":$type,
+ CArg<"CtorKind", "cir::CtorKind::Custom">:$ctorKind,
+ CArg<"bool", "false">:$is_trivial), [{
+ return $_get(type.getContext(), type, ctorKind, is_trivial);
+ }]>
+ ];
+}
+
+def CIR_CXXDtorAttr : CIR_Attr<"CXXDtor", "cxx_dtor"> {
+ let summary = "Marks a function as a CXX destructor";
+ let description = [{
+ Functions with this attribute are CXX destructors
+ }];
+ let parameters = (ins "mlir::Type":$type,
+ "bool":$is_trivial);
+
+ let assemblyFormat = [{
+ `<` $type `,` $is_trivial `>`
+ }];
+
+ let builders = [
+ AttrBuilderWithInferredContext<(ins "mlir::Type":$type,
+ CArg<"bool", "false">:$is_trivial), [{
+ return $_get(type.getContext(), type, 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 = [{
+ Functions with this attribute are CXX assignment operators.
+ The `copy` kind is used if the assignment operator is a copy assignment operator.
+ The `move` kind is used if the assignment operator is a move assignment operator.
+ }];
+ let parameters = (ins
+ "mlir::Type":$type,
+ EnumParameter<CIR_AssignKind>:$assignKind,
+ "bool":$is_trivial
+ );
+
+ let assemblyFormat = [{
+ `<` $type `,` $assignKind `,` $is_trivial `>`
+ }];
+
+ let builders = [
+ AttrBuilderWithInferredContext<(ins "mlir::Type":$type,
+ CArg<"AssignKind">:$assignKind,
+ CArg<"bool", "false">:$is_trivial), [{
+ return $_get(type.getContext(), type, assignKind, 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 16258513239d9..4314dea050275 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -2521,7 +2521,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);
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 b73071af2a5d4..7ecb21d7ba159 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..8d0919869ca12 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,52 @@ CIRGenModule::createCIRBuiltinFunction(mlir::Location loc, StringRef name,
return fnOp;
}
+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 ctorKind = cir::CtorKind::Custom;
+ if (ctor->isDefaultConstructor())
+ ctorKind = cir::CtorKind::Default;
+ if (ctor->isCopyConstructor())
+ ctorKind = cir::CtorKind::Copy;
+ if (ctor->isMoveConstructor())
+ ctorKind = cir::CtorKind::Move;
+
+ auto cxxCtor = cir::CXXCtorAttr::get(
+ convertType(getASTContext().getCanonicalTagType(ctor->getParent())),
+ ctorKind, ctor->isTrivial());
+ funcOp.setCxxSpecialMemberAttr(cxxCtor);
+ return;
+ }
+
+ const auto *method = dyn_cast<CXXMethodDecl>(funcDecl);
+ if (method && (method->isCopyAssignmentOperator() ||
+ method->isMoveAssignmentOperator())) {
+ cir::AssignKind assignKind;
+ if (method->isCopyAssignmentOperator())
+ assignKind = cir::AssignKind::Copy;
+ if (method->isMoveAssignmentOperator())
+ assignKind = cir::AssignKind::Move;
+
+ 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..88b93d3c0e8d4 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -1658,6 +1658,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 +1757,20 @@ 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;
+ if (parser.parseLess().failed())
+ return failure();
+ if (parser.parseOptionalAttribute(ctorAttr).has_value())
+ state.addAttribute(specialMemberAttr, ctorAttr);
+ if (parser.parseOptionalAttribute(dtorAttr).has_value())
+ state.addAttribute(specialMemberAttr, dtorAttr);
+ if (parser.parseGreater().failed())
+ return failure();
+ }
+
if (parseGlobalDtorCtor("global_ctor", [&](std::optional<int> priority) {
mlir::IntegerAttr globalCtorPriorityAttr =
builder.getI32IntegerAttr(priority.value_or(65535));
@@ -1883,6 +1898,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..17e13e65e37ec 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -12,6 +12,7 @@
#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 +73,7 @@ struct LoweringPreparePass
void lowerDynamicCastOp(cir::DynamicCastOp op);
void lowerArrayDtor(cir::ArrayDtor op);
void lowerArrayCtor(cir::ArrayCtor op);
+ void lowerTrivialConstructorCall(cir::CallOp op);
/// Build the function that initializes the specified global
cir::FuncOp buildCXXGlobalVarDeclInitFunc(cir::GlobalOp op);
@@ -984,6 +986,29 @@ void LoweringPreparePass::lowerArrayCtor(cir::ArrayCtor op) {
true);
}
+void LoweringPreparePass::lowerTrivialConstructorCall(cir::CallOp op) {
+ FuncOp funcOp = getCalledFunction(op);
+ if (!funcOp)
+ return;
+
+ auto cxxSpecialMember = funcOp.getCxxSpecialMemberAttr();
+ if (!cxxSpecialMember)
+ return;
+
+ if (auto cxxCtor = dyn_cast<cir::CXXCtorAttr>(cxxSpecialMember)) {
+ if (cxxCtor.getCtorKind() == cir::CtorKind::Copy) {
+ // 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);
@@ -1006,6 +1031,8 @@ void LoweringPreparePass::runOnOp(mlir::Operation *op) {
globalCtorList.emplace_back(fnOp.getName(), globalCtor.value());
else if (auto globalDtor = fnOp.getGlobalDtorPriority())
globalDtorList.emplace_back(fnOp.getName(), globalDtor.value());
+ } else if (auto callOp = dyn_cast<cir::CallOp>(op)) {
+ lowerTrivialConstructorCall(callOp);
}
}
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..7df64aaebee5a
--- /dev/null
+++ b/clang/test/CIR/CodeGen/cxx-special-member-attr.cpp
@@ -0,0 +1,56 @@
+// 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;
+ // CIR: @_ZN4FlubC1ERKS_(%arg0: !cir.ptr<!rec_Flub> loc({{.*}}), %arg1: !cir.ptr<!rec_Flub> loc({{.*}})) special_member<#cir.cxx_ctor<!rec_Flub, copy, true>>
+ // CIR: @_ZN4FlubC2EOS_(%arg0: !cir.ptr<!rec_Flub> loc({{.*}}), %arg1: !cir.ptr<!rec_Flub> loc({{.*}})) special_member<#cir.cxx_ctor<!rec_Flub, move, true>>
+ // CIR: @_ZN4FlubaSERKS_(%arg0: !cir.ptr<!rec_Flub> loc({{.*}}), %arg1: !cir.ptr<!rec_Flub> loc({{.*}})) -> !cir.ptr<!rec_Flub> special_member<#cir.cxx_assign<!rec_Flub, copy, true>>
+ // CIR: @_ZN4FlubaSEOS_(%arg0: !cir.ptr<!rec_Flub> loc({{.*}}), %arg1: !cir.ptr<!rec_Flub> loc({{.*}})) -> !cir.ptr<!rec_Flub> special_member<#cir.cxx_assign<!rec_Flub, move, true>>
+};
+
+struct Foo {
+ int a;
+
+ // CIR: @_ZN3FooC2Ev(%arg0: !cir.ptr<!rec_Foo> loc({{.*}})) special_member<#cir.cxx_ctor<!rec_Foo, default, false>>
+ Foo() : a(123) {}
+
+ // CIR: @_ZN3FooC2ERKS_(%arg0: !cir.ptr<!rec_Foo> loc({{.*}}), %arg1: !cir.ptr<!rec_Foo> loc({{.*}})) special_member<#cir.cxx_ctor<!rec_Foo, copy, false>>
+ Foo(const Foo &other) : a(other.a) {}
+
+ // CIR: @_ZN3FooC2EOS_(%arg0: !cir.ptr<!rec_Foo> loc({{.*}}), %arg1: !cir.ptr<!rec_Foo> loc({{.*}})) special_member<#cir.cxx_ctor<!rec_Foo, move, false>>
+ Foo(Foo &&other) noexcept : a(other.a) { other.a = 0; }
+
+ // CIR: @_ZN3FooaSERKS_(%arg0: !cir.ptr<!rec_Foo> loc({{.*}}), %arg1: !cir.ptr<!rec_Foo> loc({{.*}})) -> !cir.ptr<!rec_Foo> special_member<#cir.cxx_assign<!rec_Foo, copy, false>>
+ Foo &operator=(const Foo &other) {
+ if (this != &other) {
+ a = other.a;
+ }
+ return *this;
+ }
+
+ // CIR: @_ZN3FooaSEOS_(%arg0: !cir.ptr<!rec_Foo> loc({{.*}}), %arg1: !cir.ptr<!rec_Foo> loc({{.*}})) -> !cir.ptr<!rec_Foo> special_member<#cir.cxx_assign<!rec_Foo, move, false>>
+ Foo &operator=(Foo &&other) noexcept {
+ if (this != &other) {
+ a = other.a;
+ other.a = 0;
+ }
+ return *this;
+ }
+};
+
+void trivial() {
+ Flub f1{};
+ Flub f2 = f1;
+ Flub f3 = static_cast<Flub&&>(f1);
+ f2 = f1;
+ f1 = static_cast<Flub&&>(f3);
+}
+
+void non_trivial() {
+ Foo f1{};
+ Foo f2 = f1;
+ Foo f3 = static_cast<Foo&&>(f1);
+ f2 = f1;
+ f1 = static_cast<Foo&&>(f3);
+}
|
|
@llvm/pr-subscribers-clangir Author: Hendrik Hübner (HendrikHuebner) ChangesThis PR adds a special member attribute to TODO: Tests Full diff: https://github.com/llvm/llvm-project/pull/167975.diff 8 Files Affected:
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index 1e0fb038b19d8..94abe318388e7 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -822,6 +822,104 @@ 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 CXX constructor";
+ let description = [{
+ Functions with this attribute are CXX constructors.
+ The `custom` kind is used if the constructor is a custom constructor.
+ The `default` kind is used if the constructor is a default constructor.
+ The `copy` kind is used if the constructor is a copy constructor.
+ The `move` kind is used if the constructor is a move constructor.
+ }];
+ let parameters = (ins "mlir::Type":$type,
+ EnumParameter<CIR_CtorKind>:$ctorKind,
+ "bool":$is_trivial);
+
+ let assemblyFormat = [{
+ `<` $type `,` $ctorKind `,` $is_trivial `>`
+ }];
+
+ let builders = [
+ AttrBuilderWithInferredContext<(ins "mlir::Type":$type,
+ CArg<"CtorKind", "cir::CtorKind::Custom">:$ctorKind,
+ CArg<"bool", "false">:$is_trivial), [{
+ return $_get(type.getContext(), type, ctorKind, is_trivial);
+ }]>
+ ];
+}
+
+def CIR_CXXDtorAttr : CIR_Attr<"CXXDtor", "cxx_dtor"> {
+ let summary = "Marks a function as a CXX destructor";
+ let description = [{
+ Functions with this attribute are CXX destructors
+ }];
+ let parameters = (ins "mlir::Type":$type,
+ "bool":$is_trivial);
+
+ let assemblyFormat = [{
+ `<` $type `,` $is_trivial `>`
+ }];
+
+ let builders = [
+ AttrBuilderWithInferredContext<(ins "mlir::Type":$type,
+ CArg<"bool", "false">:$is_trivial), [{
+ return $_get(type.getContext(), type, 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 = [{
+ Functions with this attribute are CXX assignment operators.
+ The `copy` kind is used if the assignment operator is a copy assignment operator.
+ The `move` kind is used if the assignment operator is a move assignment operator.
+ }];
+ let parameters = (ins
+ "mlir::Type":$type,
+ EnumParameter<CIR_AssignKind>:$assignKind,
+ "bool":$is_trivial
+ );
+
+ let assemblyFormat = [{
+ `<` $type `,` $assignKind `,` $is_trivial `>`
+ }];
+
+ let builders = [
+ AttrBuilderWithInferredContext<(ins "mlir::Type":$type,
+ CArg<"AssignKind">:$assignKind,
+ CArg<"bool", "false">:$is_trivial), [{
+ return $_get(type.getContext(), type, assignKind, 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 16258513239d9..4314dea050275 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -2521,7 +2521,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);
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 b73071af2a5d4..7ecb21d7ba159 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..8d0919869ca12 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,52 @@ CIRGenModule::createCIRBuiltinFunction(mlir::Location loc, StringRef name,
return fnOp;
}
+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 ctorKind = cir::CtorKind::Custom;
+ if (ctor->isDefaultConstructor())
+ ctorKind = cir::CtorKind::Default;
+ if (ctor->isCopyConstructor())
+ ctorKind = cir::CtorKind::Copy;
+ if (ctor->isMoveConstructor())
+ ctorKind = cir::CtorKind::Move;
+
+ auto cxxCtor = cir::CXXCtorAttr::get(
+ convertType(getASTContext().getCanonicalTagType(ctor->getParent())),
+ ctorKind, ctor->isTrivial());
+ funcOp.setCxxSpecialMemberAttr(cxxCtor);
+ return;
+ }
+
+ const auto *method = dyn_cast<CXXMethodDecl>(funcDecl);
+ if (method && (method->isCopyAssignmentOperator() ||
+ method->isMoveAssignmentOperator())) {
+ cir::AssignKind assignKind;
+ if (method->isCopyAssignmentOperator())
+ assignKind = cir::AssignKind::Copy;
+ if (method->isMoveAssignmentOperator())
+ assignKind = cir::AssignKind::Move;
+
+ 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..88b93d3c0e8d4 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -1658,6 +1658,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 +1757,20 @@ 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;
+ if (parser.parseLess().failed())
+ return failure();
+ if (parser.parseOptionalAttribute(ctorAttr).has_value())
+ state.addAttribute(specialMemberAttr, ctorAttr);
+ if (parser.parseOptionalAttribute(dtorAttr).has_value())
+ state.addAttribute(specialMemberAttr, dtorAttr);
+ if (parser.parseGreater().failed())
+ return failure();
+ }
+
if (parseGlobalDtorCtor("global_ctor", [&](std::optional<int> priority) {
mlir::IntegerAttr globalCtorPriorityAttr =
builder.getI32IntegerAttr(priority.value_or(65535));
@@ -1883,6 +1898,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..17e13e65e37ec 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -12,6 +12,7 @@
#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 +73,7 @@ struct LoweringPreparePass
void lowerDynamicCastOp(cir::DynamicCastOp op);
void lowerArrayDtor(cir::ArrayDtor op);
void lowerArrayCtor(cir::ArrayCtor op);
+ void lowerTrivialConstructorCall(cir::CallOp op);
/// Build the function that initializes the specified global
cir::FuncOp buildCXXGlobalVarDeclInitFunc(cir::GlobalOp op);
@@ -984,6 +986,29 @@ void LoweringPreparePass::lowerArrayCtor(cir::ArrayCtor op) {
true);
}
+void LoweringPreparePass::lowerTrivialConstructorCall(cir::CallOp op) {
+ FuncOp funcOp = getCalledFunction(op);
+ if (!funcOp)
+ return;
+
+ auto cxxSpecialMember = funcOp.getCxxSpecialMemberAttr();
+ if (!cxxSpecialMember)
+ return;
+
+ if (auto cxxCtor = dyn_cast<cir::CXXCtorAttr>(cxxSpecialMember)) {
+ if (cxxCtor.getCtorKind() == cir::CtorKind::Copy) {
+ // 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);
@@ -1006,6 +1031,8 @@ void LoweringPreparePass::runOnOp(mlir::Operation *op) {
globalCtorList.emplace_back(fnOp.getName(), globalCtor.value());
else if (auto globalDtor = fnOp.getGlobalDtorPriority())
globalDtorList.emplace_back(fnOp.getName(), globalDtor.value());
+ } else if (auto callOp = dyn_cast<cir::CallOp>(op)) {
+ lowerTrivialConstructorCall(callOp);
}
}
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..7df64aaebee5a
--- /dev/null
+++ b/clang/test/CIR/CodeGen/cxx-special-member-attr.cpp
@@ -0,0 +1,56 @@
+// 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;
+ // CIR: @_ZN4FlubC1ERKS_(%arg0: !cir.ptr<!rec_Flub> loc({{.*}}), %arg1: !cir.ptr<!rec_Flub> loc({{.*}})) special_member<#cir.cxx_ctor<!rec_Flub, copy, true>>
+ // CIR: @_ZN4FlubC2EOS_(%arg0: !cir.ptr<!rec_Flub> loc({{.*}}), %arg1: !cir.ptr<!rec_Flub> loc({{.*}})) special_member<#cir.cxx_ctor<!rec_Flub, move, true>>
+ // CIR: @_ZN4FlubaSERKS_(%arg0: !cir.ptr<!rec_Flub> loc({{.*}}), %arg1: !cir.ptr<!rec_Flub> loc({{.*}})) -> !cir.ptr<!rec_Flub> special_member<#cir.cxx_assign<!rec_Flub, copy, true>>
+ // CIR: @_ZN4FlubaSEOS_(%arg0: !cir.ptr<!rec_Flub> loc({{.*}}), %arg1: !cir.ptr<!rec_Flub> loc({{.*}})) -> !cir.ptr<!rec_Flub> special_member<#cir.cxx_assign<!rec_Flub, move, true>>
+};
+
+struct Foo {
+ int a;
+
+ // CIR: @_ZN3FooC2Ev(%arg0: !cir.ptr<!rec_Foo> loc({{.*}})) special_member<#cir.cxx_ctor<!rec_Foo, default, false>>
+ Foo() : a(123) {}
+
+ // CIR: @_ZN3FooC2ERKS_(%arg0: !cir.ptr<!rec_Foo> loc({{.*}}), %arg1: !cir.ptr<!rec_Foo> loc({{.*}})) special_member<#cir.cxx_ctor<!rec_Foo, copy, false>>
+ Foo(const Foo &other) : a(other.a) {}
+
+ // CIR: @_ZN3FooC2EOS_(%arg0: !cir.ptr<!rec_Foo> loc({{.*}}), %arg1: !cir.ptr<!rec_Foo> loc({{.*}})) special_member<#cir.cxx_ctor<!rec_Foo, move, false>>
+ Foo(Foo &&other) noexcept : a(other.a) { other.a = 0; }
+
+ // CIR: @_ZN3FooaSERKS_(%arg0: !cir.ptr<!rec_Foo> loc({{.*}}), %arg1: !cir.ptr<!rec_Foo> loc({{.*}})) -> !cir.ptr<!rec_Foo> special_member<#cir.cxx_assign<!rec_Foo, copy, false>>
+ Foo &operator=(const Foo &other) {
+ if (this != &other) {
+ a = other.a;
+ }
+ return *this;
+ }
+
+ // CIR: @_ZN3FooaSEOS_(%arg0: !cir.ptr<!rec_Foo> loc({{.*}}), %arg1: !cir.ptr<!rec_Foo> loc({{.*}})) -> !cir.ptr<!rec_Foo> special_member<#cir.cxx_assign<!rec_Foo, move, false>>
+ Foo &operator=(Foo &&other) noexcept {
+ if (this != &other) {
+ a = other.a;
+ other.a = 0;
+ }
+ return *this;
+ }
+};
+
+void trivial() {
+ Flub f1{};
+ Flub f2 = f1;
+ Flub f3 = static_cast<Flub&&>(f1);
+ f2 = f1;
+ f1 = static_cast<Flub&&>(f3);
+}
+
+void non_trivial() {
+ Foo f1{};
+ Foo f2 = f1;
+ Foo f3 = static_cast<Foo&&>(f1);
+ f2 = f1;
+ f1 = static_cast<Foo&&>(f3);
+}
|
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
andykaylor
left a comment
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.
Thanks for working on this!
| }; | ||
|
|
||
| // Parse CXXSpecialMember attribute | ||
| if (parser.parseOptionalKeyword("special_member").succeeded()) { |
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.
Can you add tests in clang/test/CIR/IR/func.cir to verify the parsing and printing of these attributes?
xlauko
left a comment
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.
This also adds CXXCtorAttr and CXXAssignAttr please make the PR name and description more precise.
xlauko
left a comment
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.
In general it would be nice to have more helper methods on operation and attributes like isCtor, isMoveCtor etc.
| "bool":$is_trivial); | ||
|
|
||
| let assemblyFormat = [{ | ||
| `<` $type `,` $ctorKind `,` $is_trivial `>` |
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.
Make this print trivial if is_trivial is set or nothing otherwise, not ambiguous true/false.
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.
Thanks, for the review. Unfortunately it seems like there is not much documentation on how to use tablegen, so I'm not sure how to do this. What does the assemblyFormat actually do? So far I have just been copying this from other implementations
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.
I would suggest the following representation:
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^)? `>`
}];
}
assembly format allows to delaratively synthesize printer and parser for IR representation.
In this case prints the attribute prints , trivial in case is_trivial parameter is not default.
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.
Ohh right, this generates the special_member<#cir.cxx_ctor<!rec_Something, kind, trivial>> in the CIR output
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.
Only #cir.cxx_ctor<!rec_Something, kind, trivial> but yes :) It creates a prefix using dialect name and attribute mnemonic (cir.cxx_ctor) and concatenates it with assembly format.
Should I add this to the |
d0309eb to
afa84ef
Compare
|
Hmm it looks like there is a linker error on windows with the objdump tool. Seems unrelated. |
82c9ed6 to
78ee0b9
Compare
🐧 Linux x64 Test Results
|
Yes, that would be probably best. |
Already done :) (Although slightly differently) |
bcardosolopes
left a comment
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.
LGTM a few extra ultra nits
andykaylor
left a comment
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.
lgtm, once other comments are addressed
7f65075 to
13edd0d
Compare
|
Done, can this be merged? |
This PR adds a special member attribute to
cir::FuncOp. This attribute is also present in the incubator repo. Additionally, I added a "is_trivial" flag, to mark trivial members. I think that might be useful when trying to replace calls to the copy constructor with memcpy for example, but please let me know your thoughts on this. Here in the incubator repo this function is calledLowerTrivialConstructorCall, but I don't see a check that ensures the constructor is actually trivial.