标签: llvm-codegen

为什么LLVM会分配一个冗余变量?

这是一个带有枚举定义和main函数的简单 C 文件:

enum days {MON, TUE, WED, THU};

int main() {
    enum days d;
    d = WED;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

它转换为以下 LLVM IR:

define dso_local i32 @main() #0 {
  %1 = alloca i32, align 4
  %2 = alloca i32, align 4
  store i32 0, i32* %1, align 4
  store i32 2, i32* %2, align 4
  ret i32 0
}
Run Code Online (Sandbox Code Playgroud)

%2显然是d变量,它被分配了 2。%1直接返回零对应什么?

c llvm llvm-codegen

9
推荐指数
1
解决办法
183
查看次数

哪个整数操作在Rust中具有更高性能的替代方法?

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

虽然参考手册解释了行为的变化,但并不总是清楚哪种方法的性能高于标准(参见注释1)整数算术运算.我假设wrapping_add编译成等同于C的补充.

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


注意:

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

micro-optimization rust llvm-codegen

8
推荐指数
2
解决办法
305
查看次数

为什么在这个 Rust 代码中没有分支预测失败惩罚?

我写了这个非常简单的 Rust 函数:

fn iterate(nums: &Box<[i32]>) -> i32 {
    let mut total = 0;
    let len = nums.len();
    for i in 0..len {
        if nums[i] > 0 {
            total += nums[i];
        } else {
            total -= nums[i];
        }
    }

    total
}
Run Code Online (Sandbox Code Playgroud)

我编写了一个基本的基准测试,它使用一个有序数组和一个无序数组调用该方法:

fn criterion_benchmark(c: &mut Criterion) {
    const SIZE: i32 = 1024 * 1024;

    let mut group = c.benchmark_group("Branch Prediction");

    // setup benchmarking for an ordered array
    let mut ordered_nums: Vec<i32> = vec![];
    for i in 0..SIZE {
        ordered_nums.push(i - …
Run Code Online (Sandbox Code Playgroud)

performance compiler-optimization rust branch-prediction llvm-codegen

6
推荐指数
1
解决办法
320
查看次数

哪些LLVM传递负责浮点优化?

我正在研究一个改变舍入模式的Rust箱子(+ inf,-inf,最近或截断).

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

fn upward() {
    let cw: u32 = 0;
    unsafe {
    asm!("stmxcsr $0;
          mov $0, %eax;
          or $$0x4000, %eax;
          mov %eax, $0;
          ldmxcsr $0;"
          : "=*m"(&cw)
          : "*m"(&cw)
          : "{eax}"
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

floating-point rounding inline-assembly rust llvm-codegen

5
推荐指数
1
解决办法
247
查看次数

释放模式下安全 Rust 中的有符号整数溢出是否被视为未定义行为?

Rust 在调试和发布模式下以不同的方式处理有符号整数溢出。当它发生时,Rust 在调试模式下会发生恐慌,而在发布模式下默默地执行二进制补码包装。

据我所知,C/C++ 将有符号整数溢出视为未定义行为,部分原因是:

  1. 在 C 标准化的那个时候,表示有符号整数的不同底层体系结构,例如补码,可能仍在某处使用。编译器无法假设硬件中如何处理溢出。
  2. 后来的编译器因此做出假设,例如两个正整数之和也必须为正数才能生成优化的机器代码。

因此,如果 Rust 编译器确实在有符号整数方面执行与 C/C++ 编译器相同类型的优化,那么为什么The Rustonomicon指出:

无论如何,Safe Rust 不会导致未定义行为。

或者即使 Rust 编译器不执行这样的优化,Rust 程序员仍然不希望看到有符号整数环绕。不能称为“未定义行为”吗?

integer-overflow rust llvm-codegen

5
推荐指数
1
解决办法
1070
查看次数

LLVM opt mem2reg无效

我目前正在玩LLVM,我正在尝试编写一些优化器来熟悉opt和clang.我写了一个test.c文件,如下所示:

int foo(int aa, int bb, int cc){
    int sum = aa + bb;
    return sum/cc;
}
Run Code Online (Sandbox Code Playgroud)

我编译了源代码并生成了2个.ll文件,一个未经优化,一个用mem2reg优化器传递:

clang -emit-llvm -O0 -c test.c -o test.bc
llvm-dis test.bc
opt -mem2reg -S test.ll -o test-mem2reg.ll
Run Code Online (Sandbox Code Playgroud)

两个.ll文件都给了我以下输出:

ModuleID = 'test.bc'
source_filename = "test.c"
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

; Function Attrs: noinline nounwind optnone uwtable
define i32 @foo(i32 %aa, i32 %bb, i32 %cc) #0 {
entry:
  %aa.addr = alloca i32, align 4
  %bb.addr = alloca i32, align 4
  %cc.addr = …
Run Code Online (Sandbox Code Playgroud)

optimization clang ssa compiler-optimization llvm-codegen

4
推荐指数
2
解决办法
1562
查看次数

为什么clang用-O0生成效率低的asm(对于这个简单的浮点和)?

我在llvm clang Apple LLVM 8.0.0版(clang-800.0.42.1)上反汇编代码:

int main() {
    float a=0.151234;
    float b=0.2;
    float c=a+b;
    printf("%f", c);
}
Run Code Online (Sandbox Code Playgroud)

我编译时没有-O规范,但我也试过-O0(给出相同)和-O2(实际上计算值并存储它预先计算)

产生的反汇编如下(我删除了不相关的部分)

->  0x100000f30 <+0>:  pushq  %rbp
    0x100000f31 <+1>:  movq   %rsp, %rbp
    0x100000f34 <+4>:  subq   $0x10, %rsp
    0x100000f38 <+8>:  leaq   0x6d(%rip), %rdi       
    0x100000f3f <+15>: movss  0x5d(%rip), %xmm0           
    0x100000f47 <+23>: movss  0x59(%rip), %xmm1        
    0x100000f4f <+31>: movss  %xmm1, -0x4(%rbp)  
    0x100000f54 <+36>: movss  %xmm0, -0x8(%rbp)
    0x100000f59 <+41>: movss  -0x4(%rbp), %xmm0         
    0x100000f5e <+46>: addss  -0x8(%rbp), %xmm0
    0x100000f63 <+51>: movss  %xmm0, -0xc(%rbp)
    ...
Run Code Online (Sandbox Code Playgroud)

显然它正在做以下事情:

  1. 将两个浮点数加载到寄存器xmm0和xmm1上
  2. 把它们放在堆栈中
  3. 从堆栈加载一个值(不是之前的xmm0)到xmm0
  4. 执行添加. …

c assembly x86-64 compiler-optimization llvm-codegen

4
推荐指数
1
解决办法
333
查看次数

为什么 clang 发出 32 位 float ps 指令来获取 64 位 double 的绝对值?

为什么 clang 变成fabs(double)vandps而不是vandpd(像 GCC 一样)?


编译器资源管理器的示例:

#include <math.h>

double float_abs(double x) {
    return fabs(x);
}
Run Code Online (Sandbox Code Playgroud)

铿锵12.0.1-std=gnu++11 -Wall -O3 -march=znver3

.LCPI0_0:
        .quad   0x7fffffffffffffff              # double NaN
        .quad   0x7fffffffffffffff              # double NaN
float_abs(double):                          # @float_abs(double)
        vandps  xmm0, xmm0, xmmword ptr [rip + .LCPI0_0]
        ret
Run Code Online (Sandbox Code Playgroud)

海湾合作委员会11.2-std=gnu++11 -Wall -O3 -march=znver3

float_abs(double):
        vandpd  xmm0, xmm0, XMMWORD PTR .LC0[rip]
        ret
.LC0:
        .long   -1
        .long   2147483647
        .long   0
        .long   0
Run Code Online (Sandbox Code Playgroud)

(讽刺的是,GCC 使用vandpd但将常量定义为 32 位.long块(有趣的是上半部分为零),而 …

x86 assembly clang avx llvm-codegen

4
推荐指数
1
解决办法
316
查看次数

什么优化技术应用于Rust代码,总结了一个简单的算术序列?

代码很幼稚:

use std::time;

fn main() {
    const NUM_LOOP: u64 = std::u64::MAX;
    let mut sum = 0u64;
    let now = time::Instant::now();
    for i in 0..NUM_LOOP {
        sum += i;
    }
    let d = now.elapsed();
    println!("{}", sum);
    println!("loop: {}.{:09}s", d.as_secs(), d.subsec_nanos());
}
Run Code Online (Sandbox Code Playgroud)

输出是:

$ ./test.rs.out
9223372036854775809
loop: 0.000000060s
$ ./test.rs.out
9223372036854775809
loop: 0.000000052s
$ ./test.rs.out
9223372036854775809
loop: 0.000000045s
$ ./test.rs.out
9223372036854775809
loop: 0.000000041s
$ ./test.rs.out
9223372036854775809
loop: 0.000000046s
$ ./test.rs.out
9223372036854775809
loop: 0.000000047s
$ ./test.rs.out
9223372036854775809
loop: 0.000000045s
Run Code Online (Sandbox Code Playgroud)

该计划几乎立即结束.我还在C中使用for循环编写了一个等效代码,但它运行了很长时间.我想知道是什么让Rust代码如此之快.

C代码:

#include <stdint.h> …
Run Code Online (Sandbox Code Playgroud)

c rust llvm-codegen

1
推荐指数
3
解决办法
262
查看次数

为什么在Sw中交换[] float64的元素比在Rust中交换Vec <f64>的元素更快?

我有两个(相当于?)程序,一个在另一个在Rust中.平均执行时间是:

  • 去~169ms
  • 生锈~201ms

package main

import (
    "fmt"
    "time"
)

func main() {
    work := []float64{0.00, 1.00}
    start := time.Now()

    for i := 0; i < 100000000; i++ {
        work[0], work[1] = work[1], work[0]
    }

    elapsed := time.Since(start)
    fmt.Println("Execution time: ", elapsed)
}
Run Code Online (Sandbox Code Playgroud)

我编译了 --release

use std::time::Instant;

fn main() {
    let mut work: Vec<f64> = Vec::new();
    work.push(0.00);
    work.push(1.00);

    let now = Instant::now();

    for _x in 1..100000000 {
        work.swap(0, 1); 
    }

    let elapsed = now.elapsed();
    println!("Execution time: {:?}", elapsed); …
Run Code Online (Sandbox Code Playgroud)

performance go rust llvm-codegen

-6
推荐指数
1
解决办法
207
查看次数