- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
假设我有以下琐碎的 C 头文件:
// foo1.h
typedef int foo;
typedef struct {
foo a;
char const* b;
} bar;
bar baz(foo*, bar*, ...);
我的目标是获取这个文件,并生成一个看起来像这样的 LLVM 模块:
%struct.bar = type { i32, i8* }
declare { i32, i8* } @baz(i32*, %struct.bar*, ...)
换句话说,将带有声明的 C .h
文件转换为等效的 LLVM IR,包括类型解析、宏扩展等。
通过 Clang 传递它来生成 LLVM IR 会产生一个空模块(因为没有实际使用任何定义):
$ clang -cc1 -S -emit-llvm foo1.h -o -
; ModuleID = 'foo1.h'
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-darwin13.3.0"
!llvm.ident = !{!0}
!0 = metadata !{metadata !"clang version 3.5 (trunk 200156) (llvm/trunk 200155)"}
我的第一 react 是求助于谷歌,我遇到了两个相关的问题:one from a mailing list , 和 one from StackOverflow .两者都建议使用 -femit-all-decls
标志,所以我尝试了:
$ clang -cc1 -femit-all-decls -S -emit-llvm foo1.h -o -
; ModuleID = 'foo1.h'
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-darwin13.3.0"
!llvm.ident = !{!0}
!0 = metadata !{metadata !"clang version 3.5 (trunk 200156) (llvm/trunk 200155)"}
同样的结果。
我也尝试过禁用优化(使用 -O0
和 -disable-llvm-optzns
),但这对输出没有影响。使用以下变体确实产生了所需的 IR:
// foo2.h
typedef int foo;
typedef struct {
foo a;
char const* b;
} bar;
bar baz(foo*, bar*, ...);
void doThings() {
foo a = 0;
bar myBar;
baz(&a, &myBar);
}
然后运行:
$ clang -cc1 -S -emit-llvm foo2.h -o -
; ModuleID = 'foo2.h'
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-darwin13.3.0"
%struct.bar = type { i32, i8* }
; Function Attrs: nounwind
define void @doThings() #0 {
entry:
%a = alloca i32, align 4
%myBar = alloca %struct.bar, align 8
%coerce = alloca %struct.bar, align 8
store i32 0, i32* %a, align 4
%call = call { i32, i8* } (i32*, %struct.bar*, ...)* @baz(i32* %a, %struct.bar* %myBar)
%0 = bitcast %struct.bar* %coerce to { i32, i8* }*
%1 = getelementptr { i32, i8* }* %0, i32 0, i32 0
%2 = extractvalue { i32, i8* } %call, 0
store i32 %2, i32* %1, align 1
%3 = getelementptr { i32, i8* }* %0, i32 0, i32 1
%4 = extractvalue { i32, i8* } %call, 1
store i8* %4, i8** %3, align 1
ret void
}
declare { i32, i8* } @baz(i32*, %struct.bar*, ...) #1
attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
!llvm.ident = !{!0}
!0 = metadata !{metadata !"clang version 3.5 (trunk 200156) (llvm/trunk 200155)"}
除了占位符 doThings
,这正是我希望输出的样子!问题在于,这需要 1.) 使用修改后的 header 版本,以及 2.) 提前了解事物的类型。这导致我...
基本上,我正在为使用 LLVM 生成代码的语言构建一个实现。实现应该通过仅指定 C 头文件和关联的库(无手动声明)来支持 C 互操作,然后编译器将在链接时间之前使用它们来确保函数调用与其签名匹配。因此,我将问题缩小到 2 种可能的解决方案:
libclang
解析 header ,然后从生成的 AST 中查询类型(我的“最后手段”,以防这个问题没有足够的答案)我需要获取一个 C 头文件(例如上面的 foo1.h
),并且在不更改它的情况下,使用 Clang 生成上述预期的 LLVM IR,或者,找到另一种方法从 C 头文件中获取函数签名(最好使用 libclang
或构建 C 解析器)
最佳答案
也许是不太优雅的解决方案,但坚持使用 doThings
函数的想法,该函数会强制编译器发出 IR,因为使用了定义:
您使用这种方法发现的两个问题是它需要修改 header ,以及它需要更深入地了解所涉及的类型才能生成“使用”以放入函数中。这两个都可以相对简单地克服:
不是直接编译头文件,而是从包含所有“用途”的 .c 文件中 #include
它(或者更可能是它的预处理版本或多个头文件)代码。很简单:
// foo.c
#include "foo.h"
void doThings(void) {
...
}
您不需要详细的类型信息来生成名称的特定用法,将结构实例化与参数匹配,以及上面“使用”代码中的所有复杂性。 您实际上不需要自己收集函数签名。
您所需要的只是名称本身的列表,并跟踪它们是用于函数还是用于对象类型。然后,您可以重新定义您的“使用”函数,如下所示:
void * doThings(void) {
typedef void * (*vfun)(void);
typedef union v { void * o; vfun f; } v;
return (v[]) {
(v){ .o = &(bar){0} },
(v){ .f = (vfun)baz },
};
}
这大大简化了名称的必要“使用”,将其转换为统一的函数类型(并获取其指针而不是调用它),或将其包装在 &(
和 ){0}
(实例化它不管它是什么)。这意味着您根本不需要存储实际的类型信息,只需要存储您在标题中提取名称的那种 context。
(显然给虚拟函数和占位符类型扩展唯一名称,这样它们就不会与您实际想要保留的代码冲突)
这极大地简化了解析步骤,因为您只需要识别结构/union 或函数声明的上下文,而实际上不需要对周围信息做很多事情。
一个简单但粗俗的起点(我可能会使用它,因为我的标准低 :D )可能是:
#include
指令的 header (即您不想同时为其生成声明的已安装 header )。clang -E -I local-dummy-includes/-D"__attribute__(...)="foo.h > temp/foo_pp.h
或类似的东西)struct
或 union
后跟名称,}
后跟名称,或 name (
,并使用这种极其简化的非解析来构建虚拟函数中的使用列表,并发出 .c 文件的代码。它不会捕获所有的可能性;但是通过一些调整和扩展,它实际上可能会处理大量实际的 header 代码。您可以在稍后阶段将其替换为专用的简化解析器(仅用于查看所需上下文模式的解析器)。
关于c++ - Clang - 将 C header 编译为 LLVM IR/位码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24728901/
#include using namespace std; class C{ private: int value; public: C(){ value = 0;
这个问题已经有答案了: What is the difference between char a[] = ?string?; and char *p = ?string?;? (8 个回答) 已关闭
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 7 年前。 此帖子已于 8 个月
除了调试之外,是否有任何针对 c、c++ 或 c# 的测试工具,其工作原理类似于将独立函数复制粘贴到某个文本框,然后在其他文本框中输入参数? 最佳答案 也许您会考虑单元测试。我推荐你谷歌测试和谷歌模拟
我想在第二台显示器中移动一个窗口 (HWND)。问题是我尝试了很多方法,例如将分辨率加倍或输入负值,但它永远无法将窗口放在我的第二台显示器上。 关于如何在 C/C++/c# 中执行此操作的任何线索 最
我正在寻找 C/C++/C## 中不同类型 DES 的现有实现。我的运行平台是Windows XP/Vista/7。 我正在尝试编写一个 C# 程序,它将使用 DES 算法进行加密和解密。我需要一些实
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
有没有办法强制将另一个 窗口置于顶部? 不是应用程序的窗口,而是另一个已经在系统上运行的窗口。 (Windows, C/C++/C#) 最佳答案 SetWindowPos(that_window_ha
假设您可以在 C/C++ 或 Csharp 之间做出选择,并且您打算在 Windows 和 Linux 服务器上运行同一服务器的多个实例,那么构建套接字服务器应用程序的最明智选择是什么? 最佳答案 如
你们能告诉我它们之间的区别吗? 顺便问一下,有什么叫C++库或C库的吗? 最佳答案 C++ 标准库 和 C 标准库 是 C++ 和 C 标准定义的库,提供给 C++ 和 C 程序使用。那是那些词的共同
下面的测试代码,我将输出信息放在注释中。我使用的是 gcc 4.8.5 和 Centos 7.2。 #include #include class C { public:
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我的客户将使用名为 annoucement 的结构/类与客户通信。我想我会用 C++ 编写服务器。会有很多不同的类继承annoucement。我的问题是通过网络将这些类发送给客户端 我想也许我应该使用
我在 C# 中有以下函数: public Matrix ConcatDescriptors(IList> descriptors) { int cols = descriptors[0].Co
我有一个项目要编写一个函数来对某些数据执行某些操作。我可以用 C/C++ 编写代码,但我不想与雇主共享该函数的代码。相反,我只想让他有权在他自己的代码中调用该函数。是否可以?我想到了这两种方法 - 在
我使用的是编写糟糕的第 3 方 (C/C++) Api。我从托管代码(C++/CLI)中使用它。有时会出现“访问冲突错误”。这使整个应用程序崩溃。我知道我无法处理这些错误[如果指针访问非法内存位置等,
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,因为
我有一些 C 代码,将使用 P/Invoke 从 C# 调用。我正在尝试为这个 C 函数定义一个 C# 等效项。 SomeData* DoSomething(); struct SomeData {
这个问题已经有答案了: Why are these constructs using pre and post-increment undefined behavior? (14 个回答) 已关闭 6
我是一名优秀的程序员,十分优秀!