From bd6b10ecac901f16cf102c2f9dd705c219f4e018 Mon Sep 17 00:00:00 2001 From: Francesco Bertolaccini Date: Fri, 21 Jul 2023 10:55:22 +0200 Subject: [PATCH] hl: Add `DtorOp` for C++ destructors. --- .../vast/Dialect/HighLevel/HighLevelOpsCxx.td | 21 +++++++++- include/vast/Translation/CodeGen.hpp | 3 ++ include/vast/Translation/CodeGenContext.hpp | 32 +++++++++++++++- .../vast/Translation/CodeGenDeclVisitor.hpp | 38 +++++++++++-------- lib/vast/Dialect/HighLevel/HighLevelOps.cpp | 4 ++ test/vast/Dialect/HighLevel/Cxx/class-a.cpp | 7 +++- 6 files changed, 86 insertions(+), 19 deletions(-) diff --git a/include/vast/Dialect/HighLevel/HighLevelOpsCxx.td b/include/vast/Dialect/HighLevel/HighLevelOpsCxx.td index 6a18f70d60..fcc3961cad 100644 --- a/include/vast/Dialect/HighLevel/HighLevelOpsCxx.td +++ b/include/vast/Dialect/HighLevel/HighLevelOpsCxx.td @@ -101,7 +101,7 @@ def RefQualifier : I32EnumAttr< let cppNamespace = "::vast::hl"; } -def MethodOp +def MethodOp : FuncLikeOp< "method", (ins UnitAttr:$is_virtual, UnitAttr:$is_const, @@ -138,4 +138,23 @@ def MethodOp }]; } +def DtorOp + : FuncLikeOp< "dtor", + (ins UnitAttr:$is_virtual), + (ins CArg< "bool", "false" >:$is_virtual), + [{ + if (is_virtual) { + $_state.addAttribute( + "is_virtual", mlir::UnitAttr::get($_builder.getContext()) + ); + } + }] > +{ + let summary = "VAST high-level destructor definintion or declaration"; + + let assemblyFormat = [{ + $linkage (`virtual` $is_virtual^)? $sym_name custom< FunctionSignatureAndBody >($function_type, attr-dict, $body) + }]; +} + #endif // VAST_DIALECT_HIGHLEVEL_IR_HIGHLEVELOPS_CXX \ No newline at end of file diff --git a/include/vast/Translation/CodeGen.hpp b/include/vast/Translation/CodeGen.hpp index 4a41b3b3ce..cd9f3dcefc 100644 --- a/include/vast/Translation/CodeGen.hpp +++ b/include/vast/Translation/CodeGen.hpp @@ -105,6 +105,7 @@ namespace vast::cg using LabelTable = ScopedSymbolTable< const clang::LabelDecl*, hl::LabelDeclOp >; using FunctionsScope = ScopedSymbolTable< mangled_name_ref, hl::FuncOp >; using MethodsScope = ScopedSymbolTable< mangled_name_ref, hl::MethodOp >; + using DtorsScope = ScopedSymbolTable< mangled_name_ref, hl::DtorOp >; using VariablesScope = ScopedSymbolTable< const clang::VarDecl *, Value >; struct CodegenScope { @@ -115,6 +116,7 @@ namespace vast::cg LabelTable labels; FunctionsScope funcdecls; MethodsScope methdecls; + DtorsScope dtordecls; VariablesScope globs; }; @@ -623,6 +625,7 @@ namespace vast::cg .labels = _cgctx->labels, .funcdecls = _cgctx->funcdecls, .methdecls = _cgctx->methdecls, + .dtordecls = _cgctx->dtordecls, .globs = _cgctx->vars }); diff --git a/include/vast/Translation/CodeGenContext.hpp b/include/vast/Translation/CodeGenContext.hpp index 90aa25adf9..9acbcd6dbc 100644 --- a/include/vast/Translation/CodeGenContext.hpp +++ b/include/vast/Translation/CodeGenContext.hpp @@ -65,6 +65,9 @@ namespace vast::cg using MethodDeclTable = scoped_table< mangled_name_ref, hl::MethodOp >; MethodDeclTable methdecls; + using DtorDeclTable = scoped_table< mangled_name_ref, hl::DtorOp >; + DtorDeclTable dtordecls; + using EnumDecls = scoped_table< const clang::EnumDecl *, hl::EnumDeclOp >; EnumDecls enumdecls; @@ -198,13 +201,40 @@ namespace vast::cg return symbol(methdecls, mangled, "undeclared method '" + mangled.name + "'", with_error); } + hl::DtorOp lookup_destructor(mangled_name_ref mangled, bool with_error = true) { + return symbol(dtordecls, mangled, "undeclared destructor '" + mangled.name + "'", with_error); + } + + template< typename Op > + struct is_funclike { + static constexpr bool value = false; + }; + + template<> + struct is_funclike< hl::FuncOp > { + static constexpr bool value = true; + }; + + template<> + struct is_funclike< hl::MethodOp > { + static constexpr bool value = true; + }; + + template<> + struct is_funclike< hl::DtorOp > { + static constexpr bool value = true; + }; + template< typename Op > Op declare(mangled_name_ref mangled, auto vast_decl_builder) { if constexpr (std::is_same_v< Op, hl::FuncOp >) { return declare< Op >(funcdecls, mangled, vast_decl_builder, mangled.name); - } else { + } else if constexpr (std::is_same_v< Op, hl::MethodOp >) { return declare< Op >(methdecls, mangled, vast_decl_builder, mangled.name); + } else if constexpr (std::is_same_v< Op, hl::DtorOp >) { + return declare< Op >(dtordecls, mangled, vast_decl_builder, mangled.name); } + static_assert(is_funclike< Op >::value, "Declaring unknown operation type"); } mlir_value declare(const clang::VarDecl *decl, mlir_value vast_value) { diff --git a/include/vast/Translation/CodeGenDeclVisitor.hpp b/include/vast/Translation/CodeGenDeclVisitor.hpp index 4471d2ba95..285f6bfedb 100644 --- a/include/vast/Translation/CodeGenDeclVisitor.hpp +++ b/include/vast/Translation/CodeGenDeclVisitor.hpp @@ -292,22 +292,32 @@ namespace vast::cg { return clang::GlobalDecl(decl, clang::CXXDtorType::Dtor_Complete); } + template< typename Op > + operation lookup_funclike(mangled_name_ref mangled); + + template< > + operation lookup_funclike< hl::FuncOp >(mangled_name_ref mangled) { + return context().lookup_function(mangled, false /* emit no error */); + } + + template< > + operation lookup_funclike< hl::MethodOp >(mangled_name_ref mangled) { + return context().lookup_method(mangled, false /* emit no error */); + } + + template< > + operation lookup_funclike< hl::DtorOp >(mangled_name_ref mangled) { + return context().lookup_destructor(mangled, false /* emit no error */); + } + // FIXME: remove as this duplicates logic from codegen driver template< typename Op, typename Decl, typename Builder > operation VisitFunctionLikeDecl(const Decl *decl, Builder builder_callback) { auto gdecl = get_gdecl(decl); auto mangled = context().get_mangled_name(gdecl); - if constexpr (std::is_same_v< Op, hl::FuncOp >) { - if (auto fn = context().lookup_function(mangled, false /* emit no error */)) { - return fn; - } - } - - if constexpr (std::is_same_v< Op, hl::MethodOp >) { - if (auto fn = context().lookup_method(mangled, false /* emit no error */)) { - return fn; - } + if (auto fn = lookup_funclike< Op >(mangled)) { + return fn; } InsertionGuard guard(builder()); @@ -460,12 +470,8 @@ namespace vast::cg { } operation VisitCXXDestructorDecl(const clang::CXXDestructorDecl *decl) { - return VisitFunctionLikeDecl< hl::MethodOp >(decl, [&](auto loc, auto name, auto type, auto linkage) { - return make< hl::MethodOp >(loc, name, type, linkage, - decl->isVirtual(), - decl->isConst(), - decl->isVolatile(), - convert_ref_qual(decl->getRefQualifier())); + return VisitFunctionLikeDecl< hl::DtorOp >(decl, [&](auto loc, auto name, auto type, auto linkage) { + return make< hl::DtorOp >(loc, name, type, linkage, decl->isVirtual()); }); } diff --git a/lib/vast/Dialect/HighLevel/HighLevelOps.cpp b/lib/vast/Dialect/HighLevel/HighLevelOps.cpp index a3857e1634..b737f86f7d 100644 --- a/lib/vast/Dialect/HighLevel/HighLevelOps.cpp +++ b/lib/vast/Dialect/HighLevel/HighLevelOps.cpp @@ -71,6 +71,10 @@ namespace vast::hl return verify_funclike(this); } + logical_result DtorOp::verify() { + return verify_funclike(this); + } + ParseResult parseFunctionSignatureAndBody( Parser &parser, Attribute &funcion_type, mlir::NamedAttrList &attr_dict, Region &body ) { diff --git a/test/vast/Dialect/HighLevel/Cxx/class-a.cpp b/test/vast/Dialect/HighLevel/Cxx/class-a.cpp index 2bb19cb414..5339183452 100644 --- a/test/vast/Dialect/HighLevel/Cxx/class-a.cpp +++ b/test/vast/Dialect/HighLevel/Cxx/class-a.cpp @@ -2,7 +2,12 @@ // RUN: vast-cc --from-source %s > %t && vast-opt %t | diff -B %t - // CHECK: hl.class "A" : -class A {}; +class A { +// CHECK: hl.access protected +protected: + // CHECK: hl.dtor external virtual @_ZN1AD1Ev () + virtual ~A(); +}; // CHECK: hl.class "B" : class B {};