使用 LLVM c++ API 创建“类”定义

Posted

技术标签:

【中文标题】使用 LLVM c++ API 创建“类”定义【英文标题】:Creating a "class" definition using LLVM c++ API 【发布时间】:2021-02-14 06:49:34 【问题描述】:

我正在使用 LLVM c++ api 开发一种自定义前端语言,并向该语言添加“类”定义构造。词法分析器和解析器是用 C++ 编写的,LLVM c++ api 用于生成 IR 代码并编译到不同的机器后端。我已经可以使用自定义前端语言定义函数和变量、调用函数和评估基本算术。

为了给语言添加“类”定义,我遵循https://mapping-high-level-constructs-to-llvm-ir.readthedocs.io/en/latest/object-oriented-constructs/classes.html上的建议

这建议我们创建一个“structtype”来包含该类的所有数据成员,并为该类的方法单独定义一堆函数(如果我正确理解链接的话)。

因此,在我的编译器代码中,我定义了一个名为“ClassAST”的 AST 节点,其中包含类的数据成员的名称和类型以及前面定义的“类”方法的函数定义集合 -结束语。 AST节点的c++代码sn-p如下:

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);

在 sn-p 中,FunctionAST、ExprAST、PrototypeAST 是我定义的其他 AST 节点类型,用于分别表示函数、表达式和函数原型,并用于相同的 IR 代码生成。 “IRgen”是我定义的一个类,其中包含用于我的编译器的 llvm::Context、llvm::Module、llvm::IRBuilder 实例。

现在,要为 ClassAST 节点生成 IR 代码,我将“codegen”定义为

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;

上面的 codegen(..) 函数成功创建了 class_StructType 以包含适当的 data_member 类型,并为定义的 'function_members' 生成 IR 代码,并将函数定义添加到 'irgen' 中的 llvm::Module 实例。

但是,我不知道如何将 class_StructType 类型添加到 llvm::Module 实例中,以便以后的代码可以检索类型并创建 class_StructType 的实例。

有人能解释一下如何将新的 StructType 添加到 llvm:Module 实例吗?(我使用的是最新的 llvm 12.0 api,但更旧的 api 11.0 应该没问题)。

【问题讨论】:

【参考方案1】:

查看Module::getTypeByName 的源代码,它在LLVMContext 实例中查找名称。这意味着您不必将您的类型添加到模块中,并且名称查找应该可以正常工作,即使通过 Module 实例也是如此。

【讨论】:

谢谢@llCapitano!这似乎行得通。我会用类功能做更多的测试,让你知道。最好的问候。

以上是关于使用 LLVM c++ API 创建“类”定义的主要内容,如果未能解决你的问题,请参考以下文章

Llvm C++ API 将指向函数的指针传递给另一个函数

使用LLVM Alias和IFunc功能的任何实际示例?

如何使用 LLVM 在 Windows 上为 ARM 编译 C++ 程序?

VS2019 C++动态链接库的创建使用 - 如何导出类

使用 LLVM C API 生成对内部函数的调用

自定义创建一个芯片LLVM编译器分析