[mlir][Interfaces] Generate a struct containing function pointers instead of a class...
authorRiver Riddle <riddleriver@gmail.com>
Tue, 27 Oct 2020 23:03:07 +0000 (16:03 -0700)
committerRiver Riddle <riddleriver@gmail.com>
Tue, 27 Oct 2020 23:16:51 +0000 (16:16 -0700)
When compiling for code size, the use of a vtable causes a destructor(and constructor in certain cases) to be generated for the class. Interface models don't need a complex constructor or a destructor, so this can lead to many megabytes of code size increase(even in opt). This revision switches to a simpler struct of function pointers approach that accomplishes the same API requirements as before. This change requires no updates to user code, or any other code aside from the generator, as the user facing API is still exactly the same.

Differential Revision: https://reviews.llvm.org/D90085

mlir/tools/mlir-tblgen/OpInterfacesGen.cpp

index 54826f4..1b0cb27 100644 (file)
@@ -189,17 +189,19 @@ bool InterfaceGenerator::emitInterfaceDefs() {
 //===----------------------------------------------------------------------===//
 
 void InterfaceGenerator::emitConceptDecl(Interface &interface) {
-  os << "  class Concept {\n"
-     << "  public:\n"
-     << "    virtual ~Concept() = default;\n";
+  os << "  struct Concept {\n";
 
   // Insert each of the pure virtual concept methods.
   for (auto &method : interface.getMethods()) {
-    os << "    virtual ";
+    os << "    ";
     emitCPPType(method.getReturnType(), os);
-    emitMethodNameAndArgs(method, os, valueType,
-                          /*addThisArg=*/!method.isStatic(), /*addConst=*/true);
-    os << " = 0;\n";
+    os << "(*" << method.getName() << ")(";
+    if (!method.isStatic())
+      emitCPPType(valueType, os) << (method.arg_empty() ? "" : ", ");
+    llvm::interleaveComma(
+        method.getArguments(), os,
+        [&](const InterfaceMethod::Argument &arg) { os << arg.type; });
+    os << ");\n";
   }
   os << "  };\n";
 }
@@ -207,13 +209,19 @@ void InterfaceGenerator::emitConceptDecl(Interface &interface) {
 void InterfaceGenerator::emitModelDecl(Interface &interface) {
   os << "  template<typename " << valueTemplate << ">\n";
   os << "  class Model : public Concept {\n  public:\n";
+  os << "    Model() : Concept{";
+  llvm::interleaveComma(
+      interface.getMethods(), os,
+      [&](const InterfaceMethod &method) { os << method.getName(); });
+  os << "} {}\n\n";
 
   // Insert each of the virtual method overrides.
   for (auto &method : interface.getMethods()) {
-    emitCPPType(method.getReturnType(), os << "    ");
+    emitCPPType(method.getReturnType(), os << "    static ");
     emitMethodNameAndArgs(method, os, valueType,
-                          /*addThisArg=*/!method.isStatic(), /*addConst=*/true);
-    os << " final {\n      ";
+                          /*addThisArg=*/!method.isStatic(),
+                          /*addConst=*/false);
+    os << " {\n      ";
 
     // Check for a provided body to the function.
     if (Optional<StringRef> body = method.getBody()) {