简体   繁体   中英

Creating a "class" definition using LLVM c++ API

I am working on a custom front-end language using the LLVM c++ api and am adding a "class" definition construct to the language. The lexer and parser are written in C++ and LLVM c++ api is being used to generate IR code and compile to different machine backends. I can already define functions and variables, call functions and evaluate basic arithmetic with the custom front-end language.

In order to do add a "class" definition to the language, I am following the suggestion on https://mapping-high-level-constructs-to-llvm-ir.readthedocs.io/en/latest/object-oriented-constructs/classes.html

This suggests that we create a "structtype" to contain all the data members of the class and separately define a bunch of functions for the methods of the class (if I understand the link correctly).

Thus in my compiler code, I defined an AST node called "ClassAST" which contains the names and types for data members of the class and a collection of function definitions for the methods for the "class" being defined in the front-end language. The c++ code snippet for the AST node is as follows:

class ClassAST {
public:
  std::vector<std::unique_ptr<FunctionAST>> function_members;
  std::vector<std::unique_ptr<ExprAST>> data_members;
  std::unique_ptr<PrototypeAST> Proto;
  ClassAST(std::unique_ptr<PrototypeAST> Proto,std::vector<std::unique_ptr<FunctionAST>> function_members,
              std::vector<std::unique_ptr<ExprAST>> data_members)
    : Proto(std::move(Proto)),function_members(std::move(function_members)), data_members(std::move(data_members)) {}

  llvm::Type *codegen(IRgen *irgen);
}

In the snippet, FunctionAST, ExprAST, PrototypeAST are other AST node types I have defined in order to represent functions, expressions and function prototypes respectively and are used for IR code generation of the same. "IRgen" is a class I defined to contain the llvm::Context, llvm::Module, llvm::IRBuilder instances for my compiler.

Now, to generate the IR code for the ClassAST node I define the "codegen", function as

llvm::Type *ClassAST::codegen(IRgen *irgen){
  // create a struct type with all the data_members
  llvm::StructType *class_StructType = llvm::StructType::create(irgen->TheContext);
  class_StructType->setName(Proto->Name);
  std::vector<llvm::Type *> DataTypes;
  for(int i=0;i<data_members.size();i++){
    DataTypes.push_back(llvm::Type::getDoubleTy(irgen->TheContext)); // assume all data types are doubles for now
  }
  class_StructType->setBody(DataTypes);
  // add the type to the symbol table (How to do this?)
  // .. ????? ..
  // codegen the function members
  for (int i=0;i<function_members.size();i++){
    auto RetVal = function_members[i]->codegen(irgen);
    if(!RetVal){
      // Error reading body, remove function.
      LogErrorV(("Error generating code for "+Proto->Name+"."+function_members[i]->Proto->Name).c_str());
    }
  }
  return class_StructType;
}

The above codegen(..) function successfully creates the class_StructType to contain the appropriate data_member types and generates the IR code for the defined 'function_members' and adds the function definitions to the llvm::Module instance in 'irgen'.

However, I have no idea how to add the class_StructType type to the llvm::Module instance, so that later code can retrieve the type and create instances of the class_StructType.

Could someone shed some light on how a new StructType is added to a llvm:Module instance? (I am using the latest llvm 12.0 api, but even older api 11.0 should be fine).

Looking at the source code of Module::getTypeByName , it looks up the name in the LLVMContext instance. This means you don't have to add your type to the module and name lookup should work just fine, even through a Module instance.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM