标签: llvm-codegen

C++标准是否允许未初始化的bool使程序崩溃?

我知道C++ 中的"未定义行为"几乎可以让编译器做任何想做的事情.但是,我遇到了让我感到惊讶的崩溃,因为我认为代码足够安全.

在这种情况下,真正的问题仅发生在使用特定编译器的特定平台上,并且仅在启用了优化时才发生.

我尝试了几件事来重现问题并将其简化到最大程度.这是一个名为的函数的摘录Serialize,它将获取bool参数,并将字符串true或复制false到现有的目标缓冲区.

如果bool参数是未初始化的值,那么这个函数是否会在代码审查中,没有办法告诉它实际上可能会崩溃?

// Zero-filled global buffer of 16 characters
char destBuffer[16];

void Serialize(bool boolValue) {
    // Determine which string to print based on boolValue
    const char* whichString = boolValue ? "true" : "false";

    // Compute the length of the string we selected
    const size_t len = strlen(whichString);

    // Copy string into destination buffer, which is zero-filled (thus already null-terminated)
    memcpy(destBuffer, whichString, len);
}
Run Code Online (Sandbox Code Playgroud)

如果使用clang 5.0.0 +优化执行此代码,它将/可能崩溃.

boolValue ? "true" …

c++ abi llvm undefined-behavior llvm-codegen

482
推荐指数
5
解决办法
3万
查看次数

假设两个可变引用都不能别名,Rust编译器为什么不优化代码?

据我所知,引用/指针别名会阻碍编译器生成优化代码的能力,因为它们必须确保在两个引用/指针确实是别名的情况下,生成的二进制文件的行为正确。例如,在以下C代码中,

void adds(int  *a, int *b) {
    *a += *b;
    *a += *b;
}
Run Code Online (Sandbox Code Playgroud)

clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)-O3标志编译时,它发出

0000000000000000 <adds>:
   0:    8b 07                    mov    (%rdi),%eax
   2:    03 06                    add    (%rsi),%eax
   4:    89 07                    mov    %eax,(%rdi)  # The first time
   6:    03 06                    add    (%rsi),%eax
   8:    89 07                    mov    %eax,(%rdi)  # The second time
   a:    c3                       retq
Run Code Online (Sandbox Code Playgroud)

下面的代码存回(%rdi)两次的情况下,int *aint *b别名。

当我们明确告诉编译器这两个指针不能使用restrict关键字别名时:

void adds(int * restrict a, int * restrict …
Run Code Online (Sandbox Code Playgroud)

compiler-optimization rust llvm-codegen

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

在具有240个或更多元素的数组上循环时,为什么会对性能产生较大影响?

当在Rust中的一个数组上运行求和循环时,我发现CAPACITY> = 240 时性能会大幅下降。CAPACITY= 239的速度大约是80倍。

Rust对“短”数组进行了特殊的编译优化吗?

与编译rustc -C opt-level=3

use std::time::Instant;

const CAPACITY: usize = 240;
const IN_LOOPS: usize = 500000;

fn main() {
    let mut arr = [0; CAPACITY];
    for i in 0..CAPACITY {
        arr[i] = i;
    }
    let mut sum = 0;
    let now = Instant::now();
    for _ in 0..IN_LOOPS {
        let mut s = 0;
        for i in 0..arr.len() {
            s += arr[i];
        }
        sum += s;
    }
    println!("sum:{} time:{:?}", sum, …
Run Code Online (Sandbox Code Playgroud)

arrays performance rust llvm-codegen

214
推荐指数
2
解决办法
2万
查看次数

Rust的128位整数“ i128”如何在64位系统上工作?

Rust具有128位整数,这些整数用数据类型表示i128u128对于无符号整数):

let a: i128 = 170141183460469231731687303715884105727;
Run Code Online (Sandbox Code Playgroud)

Rust如何使这些i128值在64位系统上工作?例如,如何对这些进行算术运算?

据我所知,既然该值不能容纳在x86-64 CPU的一个寄存器中,那么编译器是否会以某种方式使用2个寄存器i128?还是他们改用某种大整数结构来表示它们?

x86-64 int128 bigint rust llvm-codegen

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

何时应该在Rust中使用内联?

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

#[inline]

#[inline(always)]

#[inline(never)]

什么时候应该使用它们?

在锈参考,我们看到了一个内嵌属性部分说法

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

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

但是我们在Rust源代码中看到了相当多的用法,包括标准库.许多内联属性被添加到单行函数中,编译器应该可以根据参考通过启发式查找和优化.那些实际上不需要吗?

inline rust llvm-codegen

54
推荐指数
1
解决办法
6820
查看次数

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

我在Rust写了一个线性代数库.

我有一个函数来获取给定行和列的矩阵单元格的引用.此函数以一对断言开始,行和列在边界内:

#[inline(always)]
pub fn get(&self, row: usize, col: usize) -> &T {
    assert!(col < self.num_cols.as_nat());
    assert!(row < self.num_rows.as_nat());
    unsafe {
        self.get_unchecked(row, col)
    }
}
Run Code Online (Sandbox Code Playgroud)

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

#[inline(always)]
pub unsafe fn get_unchecked(&self, row: usize, col: usize) -> &T {
    self.data.get_unchecked(self.row_col_index(row, col))
}
Run Code Online (Sandbox Code Playgroud)

奇怪的是,当我使用这些方法来实现矩阵乘法(通过行和列迭代器)时,我的基准测试显示,当我检查边界时它实际上快了大约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 …

optimization performance rust llvm-codegen

26
推荐指数
1
解决办法
740
查看次数

有没有办法让Rust将指针视为非别名,所以它可以将它们标记为LLVM优化器的"noalias"?

以下指针别名示例:

pub unsafe fn f(a: *mut i32, b: *mut i32, x: *const i32) {
  *a = *x;
  *b = *x;
}
Run Code Online (Sandbox Code Playgroud)

编译成以下程序集(with -C opt-level=s):

example::f:
        push    rbp
        mov     rbp, rsp
        mov     eax, dword ptr [rdx]
        mov     dword ptr [rdi], eax
        mov     eax, dword ptr [rdx]
        mov     dword ptr [rsi], eax
        pop     rbp
        ret
Run Code Online (Sandbox Code Playgroud)

请注意,x它被解除引用两次.LLVM没有将其视为noalias.我的第一个想法是避免在赋值中使用指针,而是使用安全引用(因为那些" 遵循LLVM的作用域noalias模型 ")来给优化器提示:

pub fn g(a: *mut i32, b: *mut i32, x: *const i32) {
  let safe_a = unsafe { …
Run Code Online (Sandbox Code Playgroud)

rust llvm-codegen

26
推荐指数
1
解决办法
417
查看次数

如何将Rust编译为机器代码?

我最近一直在研究Rust编程语言.它是如何工作的?Rust代码似乎被编译成ELF或PE(等)二进制文件,但我无法找到有关如何完成的任何信息?它被编译成中间格式,然后用gxx编译其余部分吗?任何帮助(或链接)将非常感激.

rust llvm-codegen

24
推荐指数
1
解决办法
4269
查看次数

什么优化级别`-Os`和`-Oz`在rustc中做什么?

执行rustc -C help节目(除其他外):

-C opt-level=val       -- optimize with possible levels 0-3, s, or z
Run Code Online (Sandbox Code Playgroud)

我认为级别0到3非常直观:级别越高,执行的优化程度越高.但是,我不知道这些sz选项正在做什么,我找不到与它相关的Rust相关信息.

rust llvm-codegen

23
推荐指数
2
解决办法
3337
查看次数

Rust可以在某天移动对象期间优化掉逐位复制吗?

考虑一下片段

struct Foo {
    dummy: [u8; 65536],
}

fn bar(foo: Foo) {
    println!("{:p}", &foo)
}

fn main() {
    let o = Foo { dummy: [42u8; 65536] };
    println!("{:p}", &o);
    bar(o);
}
Run Code Online (Sandbox Code Playgroud)

该计划的典型结果

0x7fffc1239890
0x7fffc1229890
Run Code Online (Sandbox Code Playgroud)

地址不同的地方.

显然,大型数组dummy已被复制,正如编译器的移动实现中所期望的那样.不幸的是,这可能会产生非平凡的性能影响,因为这dummy是一个非常大的阵列.这种影响可以迫使人们选择通过引用来传递参数,即使函数实际上在概念上"消耗"了参数.

由于Foo没有派生Copy,对象o被移动.由于Rust禁止访问被移动的对象,是什么阻止bar了"重用"原始对象o,迫使编译器生成一个可能昂贵的按位复制?是否存在根本性的困难,或者我们是否会看到编译器有一天会优化掉这个逐位复制?

move-semantics rust llvm-codegen

17
推荐指数
1
解决办法
2612
查看次数