问题标签 [llvm-codegen]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
1 回答
10926 浏览

types - LLVM 的整数类型

LLVM 语言将整数类型指定为 iN,其中 N 是整数的位宽,范围从 1 到 2^23-1(根据: http: //llvm.org/docs/LangRef.html#integer-类型

我有两个问题:

  1. 将 C 程序编译到 LLVM IR 级别时,哪些类型可以降低到 i1、i2、i3 等?看起来 i8、i16、i32、i64 类型必须足够了,所以我想知道所有其他近 800 万个整数类型是干什么用的。

  2. 有符号和无符号整数类型都降低到 i32 是真的吗?这是什么原因,为什么它不适用于 32 位浮点数(在 LLVM 中表示为 f32)?

0 投票
2 回答
2431 浏览

c - 带有 LLVM 的 C ABI

我有一个用 LLVM 编写的编译器,我正在寻找我的 ABI 合规性。例如,我发现实际上很难在 Windows x86 或 Linux 上找到 C ABI 的规范文档。我发现的那些是用 RAX/EAX/etc 来解释的,而不是我可以使用的 IR 术语。

到目前为止,我想我已经发现 LLVM 以不可见的方式处理聚合——也就是说,它将它们的成员各自视为一个不同的参数。因此,例如,在 Windows x64 上,如果我想处理文档所说的聚合,我需要强制转换为该大小的单个整数,如果是 8、16、32 或 64 位。否则,按指针传递。

对于 Windows x86,似乎 __cdecl 和 __stdcall 不需要我的任何操作,因为所有参数都在堆栈上传递。__fastcall 表示前两个 32 位或更小的参数是寄存器传递的,所以我需要强制该大小或更小的聚合。__thiscall 在寄存器中传递这个,其余的在堆栈中,所以看起来我不需要在这里执行任何调整。

对于 __vectorcall,通过整数强制传递不超过 sizeof(void*) 的聚合。对于其他聚合,如果它们是 HVA,则按值传递;否则在 x86 上按值传递或在 x64 上按指针传递。

这看起来很简单(好吧,相对而言),但 LLVM 文档sext明确指出“这向代码生成器表明参数或返回值应符号扩展至目标 ABI 所需的范围(通常为 32 位)由调用者(对于参数)或被调用者(对于返回值)。”。x86 调用约定的 Microsoft 页面没有提到将任何内容扩展到任何宽度。

而且我观察到 Clang 生成的 LLVM IRbyval在 Windows 上生成属性。我从上面收集到的理解从来不需要byval' 的用法。

如何将各种平台 C ABI 降低到 LLVM IR?

0 投票
1 回答
739 浏览

llvm-clang - LLVM use of carry and zero flags

I'm starting to read LLVM docs and IR documentation.

In common architectures, an asm cmp instruction "result" value is -at least- 3 bits long, let's say the first bit is the SIGN flag, the second bit is the CARRY flag and the third bit is the ZERO flag.

Question 1)

Why the IR icmp instruction result value is only i1? (you can choose only one flag)

Why doesn't IR define, let's call it a icmp2 instruction returning an i3 having SIGN,CARRY and ZERO flags?

This i3 value can be acted upon with a switch instruction, or maybe a specific br2 instruction, like:

Question 2)

Does this make sense? Could this br2 instruction help create new optimizations? i.e. remove all jmps? it is necessary or the performance gains are negligible?

The reason I'm asking this -besides not being an expert in LLVM- is because in my first tests I was expecting some kind of optimization to be made by LLVM in order to avoid making the comparison twice and also avoid all branches by using asm conditional-move instructions.

My Tests:

I've compiled with clang-LLVM this:

Output asm is: ...

I expected (all jmps removed in the inner loop):

Performance difference (1s) seems to be negligible (on a VM under VirtualBox):

  • LLVM generated asm: 12.53s
  • hancoded asm: 11.53s
  • diff: 1s, in 500 millions iterations

Question 3)

Are my performance measures correct? Here's the makefile and the full hancoded.compare.s

makefile:

hand coded (fixed) asm:

0 投票
2 回答
1851 浏览

rust - 如何使用“ffast-math”进行编译?

我正在尝试对一些 Rust 代码进行基准测试,但我不知道如何设置“ffast-math”选项。

llvm-args='-ffast-math'llvm-args='-fast'没有工作。我应该使用什么标志?

0 投票
1 回答
420 浏览

rust - LLVM 优化器不尊重使用 Rust 内联 asm 设置非默认舍入模式?

我正在开发一个更改舍入模式(+inf、-inf、最近或截断)的 Rust 板条箱。

更改舍入模式的函数是使用内联汇编编写的:

当我在调试模式下编译代码时,它按预期工作,当向正无穷大舍入时,我得到 0.3333333333337 三分之一,但是当我在发布模式下编译时,无论我设置什么舍入模式,我都会得到相同的结果。我猜这种行为是由于 LLVM 后端所做的优化。

如果我知道哪些 LLVM 通道负责此优化,我可以禁用它们,因为目前我没有看到任何其他解决方法。

0 投票
1 回答
870 浏览

c - 为什么空函数不会作为 LLVM IR 中的死代码被删除?

从这个简单的 C 程序开始:

我的通行证输出如下:
注意:IR 语句为绿色。

红外

问题:使用O3最高级别的优化,为什么函数没有nothing作为死代码被淘汰?

0 投票
1 回答
1257 浏览

performance - 当我删除边界检查时,为什么我的代码运行速度变慢?

我正在用 Rust 编写一个线性代数库。

我有一个函数可以在给定的行和列中获取对矩阵单元的引用。此函数以行和列在界限内的一对断言开始:

在紧密循环中,我认为跳过边界检查可能会更快,所以我提供了一个get_unchecked方法:

奇怪的是,当我使用这些方法来实现矩阵乘法(通过行和列迭代器)时,我的基准测试表明,当我检查边界时,它实际上快了大约 33%。为什么会这样?

我在两台不同的计算机上试过这个,一台运行 Linux,另一台运行 OSX,都显示了效果。

完整代码在 github 上。相关文件是lib.rs。感兴趣的函数是:

  • get在第 68 行
  • get_unchecked在第 81 行
  • next在第 551 行
  • mul在第 796 行
  • matrix_mul(基准)在第 1038 行

请注意,我使用类型级别的数字来参数化我的矩阵(也可以通过虚拟标记类型选择动态大小),因此基准是两个 100x100 矩阵相乘。

更新:

我已经大大简化了代码,删除了基准测试中没有直接使用的东西并删除了通用参数。我还编写了一个不使用迭代器的乘法实现,并且该版本不会产生相同的效果。有关此版本的代码,请参见此处。克隆minimal-performance分支并运行cargo bench将对乘法的两种不同实现进行基准测试(请注意,断言在该分支开始时已被注释掉)。

另外值得注意的是,如果我更改get*函数以返回数据的副本而不是引用(f64而不是&f64),效果就会消失(但代码会稍微慢一点)。

0 投票
1 回答
20171 浏览

rust - 什么时候应该在 Rust 中使用 inline?

Rust 有一个“内联”属性,可以用于以下三种风格之一:

#[inline]

#[inline(always)]

#[inline(never)]

什么时候应该使用它们?

在 Rust 参考中,我们看到一个内联属性部分

编译器根据内部启发式自动内联函数。错误的内联函数实际上会使程序变慢,因此应谨慎使用。

在 Rust 内部论坛中,huon对于指定 inline 也很保守

但是我们在 Rust 源代码中看到了相当多的使用,包括标准库。在单行函数中添加了很多内联属性,编译器应该很容易根据参考通过启发式发现和优化。这些实际上不需要吗?

0 投票
1 回答
3724 浏览

rust - 有朝一日,Rust 可以在对象移动期间优化按位复制吗?

考虑片段

该程序的典型结果

地址不同的地方。

显然,大数组dummy已被复制,正如编译器的移动实现中所预期的那样。不幸的是,这可能会产生不小的性能影响,就像dummy一个非常大的数组一样。这种影响可能会迫使人们选择通过引用传递参数,即使函数实际上在概念上“消耗”了参数。

由于Foo不派生Copy,因此对象o被移动。由于 Rust 禁止访问移动的对象,是什么阻止bar了“重用”原始对象o,从而迫使编译器生成潜在的昂贵的逐位副本?有没有根本的困难,或者我们有一天会看到编译器优化掉这个按位复制?

0 投票
3 回答
600 浏览

rust - Rust 中哪些整数运算具有更高性能的替代方法?

当在 Rust 中编写将运行数百万次的整数函数时(想想像素处理),使用性能最高的操作很有用 - 类似于 C/C++。

虽然参考手册解释了行为的变化,但并不总是清楚哪些方法比标准(见注 1.)整数算术运算具有更高的性能。我假设wrapping_add编译成相当于 C 的加法的东西。

在标准操作(加/减/乘/模/除/移位/位操作...)中,哪些操作具有更高性能的替代方案,默认情况下不使用?


笔记:

  1. 按照标准 ,我的意思是使用符号或...等的整数算术a + b。编写数学表达式时您将使用什么 - 除非您特别需要使用包装或返回溢出的方法之一。i / kc % e
  2. 我意识到回答这个问题可能需要一些研究。所以我很高兴通过查看生成的程序集来进行一些检查,以查看哪些操作正在使用未经检查/原始操作。
  3. 可能是检查/未检查操作之间的速度差异并不显着,如果是这种情况,我仍然希望能够编写一个函数的“快速”版本来与“安全”版本进行比较,来我自己的结论是它是否是给定功能的合理选择。
  4. 在提到像素处理之后,SIMD 已经成为一种可能的解决方案。尽管这是一个很好的建议。这仍然给我们留下了无法使用 SIMD 优化的情况,因此仍然需要考虑快速整数运算的一般情况。