如何使用clang -emit-llvm

时间:2018-05-20 04:54:26

标签: c compiler-construction clang llvm bitcode

上下文

我正在为需要大量运行时函数的语言编写编译器。我正在使用LLVM作为我的后端,因此codegen需要所有运行时类型(函数,结构等)的类型,而不是使用LLVM API手动定义所有这些类型或手写LLVM IR我想编写C中的头文件并编译为编译器可以使用LLVMParseBitcodeInContext2拉入的bitcode。

问题

我遇到的问题是clang似乎没有保留任何任何函数 definitions 都没有使用的声明类型。 Clang有{{1>} 听起来就像它应该解决它一样,但遗憾的是它并没有,谷歌搜索表明它的名字错误,因为它只影响未使用的定义,而不是声明。

然后我想也许如果我只将头文件编译成-femit-all-decls个文件,我可以用.gch以同样的方式将它们引入(因为文档说他们使用“相同的”bitcode格式“,但是这样做的错误LLVMParseBitcodeInContext2所以必须有所不同。也许差异小到可以解决?

任何可以为复杂运行时自动化的建议或相对简单的解决方法?如果有人对接近这个一般用例有一个完全替代的建议,我也会感兴趣,记住我不想在运行时函数体中静态链接我生成的每个单个目标文件,只是类型。我想这也是其他编译器所需要的,所以如果我接近这个错误,我不会感到惊讶。

e.g。鉴于此输入:

runtime.h

error: Invalid bitcode signature

我需要一个带有等效IR的bitcode文件

runtime.ll

struct Foo {
  int a;
  int b;
};

struct Foo * something_with_foo(struct Foo *foo);

我可以手动编写它,但这也是重复的,因为我还需要为其他互操作创建C头,并且理想的是不必手动保持它们同步。运行时相当大。我想我也可以做相反的事情:在LLVM IR中编写声明并生成C头。

有人问过这些年,但是对于这种规模和类型复杂性的运行时来说,提议的解决方案相当苛刻且相当不切实际:Clang - Compiling a C header to LLVM IR/bitcode

2 个答案:

答案 0 :(得分:4)

Clang的precompiled headers实现似乎不输出LLVM IR,而只输出AST(抽象语法树),因此不需要再次解析标题:

  

AST文件本身包含Clang的序列化表示   抽象语法树和支持数据结构,使用存储   与LLVM的bitcode文件格式相同的压缩比特流。

底层二进制格式可能相同,但听起来内容不同,LLVM的bitcode格式在这种情况下仅仅是一个容器。这在网站的帮助页面上并不是很清楚,所以我只是在猜测。 LLVM / Clang专家可以帮助澄清这一点。

不幸的是,似乎并没有一种优雅的方式。我建议最小化实现所需的工作量是建立一个最小的C / C ++源文件,它以某种方式使用您要编译为LLVM IR的所有声明。例如,您只需要声明一个指向结构的指针,以确保它不会被优化掉,并且您可能只为函数提供一个空的定义以保持其签名。

获得最小的源文件后,使用clang -O0 -c -emit-llvm -o precompiled.ll进行编译,以获得包含LLVM IR格式的所有定义的模块。

您发布的代码段中的示例:

struct Foo {
  int a;
  int b;
};

// Fake function definition.
struct Foo *  something_with_foo(struct Foo *foo)
{
    return NULL;
}

// A global variable.
struct Foo* x;

显示保留定义的输出:https://godbolt.org/g/2F89BH

答案 1 :(得分:2)

因此,clang实际上并没有过滤掉未使用的声明。它推迟发出前向声明,直到第一次使用。每当使用一个函数时,它会检查它是否已经被发出,如果没有,它会发出函数声明。

您可以查看these lines中的clang repo

// Forward declarations are emitted lazily on first use.
if (!FD->doesThisDeclarationHaveABody()) {
  if (!FD->doesDeclarationForceExternallyVisibleDefinition())
    return;

这里的简单修复是对最后两行进行注释,或者只是将&& false添加到第二个条件。

// Forward declarations are emitted lazily on first use.
if (!FD->doesThisDeclarationHaveABody()) {
  if (!FD->doesDeclarationForceExternallyVisibleDefinition() && false)
    return;

这会导致clang在看到声明时立即发出声明,这也可能会更改定义在.ll(或.bc)文件中的显示顺序。假设这不是问题。

为了使其更清洁,您还可以添加命令行标志--emit-all-declarations并在继续之前检查此处。