ndk和clang ++中的ARM编译器错误?

no *_*ial 6 c++ arm compiler-errors android-ndk clang++

请考虑以下代码:

float test(int len, int* tab)
{
    for(int i = 0; i<len; i++)
        tab[i] = i;
}
Run Code Online (Sandbox Code Playgroud)

显然回报缺失。对于用于ARM处理器的clang和ndk编译器的这种情况,都会生成一个无限循环。拆卸之后,很明显编译器生成常规分支指令,而不是条件分支。

    mov     r0, #0
.LBB0_1:
    str     r0, [r1, r0, lsl #2]
    add     r0, r0, #1
    b       .LBB0_1
Run Code Online (Sandbox Code Playgroud)

可以在此处找到带有错误的示例:https : //godbolt.org/z/YDSFw-

请注意,c ++规范指出缺少返回值被视为未定义行为,但仅引用返回值。它不会影响前面的说明。

我在这里想念什么吗?有什么想法吗?

mst*_*sjo 3

不,你不能用未定义的行为来推理。

编译器可以自由地使用未定义的行为和围绕它的假设来进行优化。编译器可以自由地假设您的代码不会包含未定义的行为。

在这种情况下,编译器可以假设不会到达具有未定义行为的代码。由于函数末尾包含未定义的行为,编译器得出结论,实际上永远不会到达函数末尾,因此可以优化循环。

如果删除-Oz并添加-emit-llvm到编译器资源管理器命令,您将看到 LLVM IR clang 在不进行优化时最初生成的内容: https: //godbolt.org/z/-dbeNj

define dso_local float @_Z4testiPi(i32 %0, i32* %1) #0 {
  %3 = alloca i32, align 4
  %4 = alloca i32*, align 4
  %5 = alloca i32, align 4
  store i32 %0, i32* %3, align 4
  store i32* %1, i32** %4, align 4
  store i32 0, i32* %5, align 4
  br label %6

6:                                                ; preds = %15, %2
  %7 = load i32, i32* %5, align 4
  %8 = load i32, i32* %3, align 4
  %9 = icmp slt i32 %7, %8
  br i1 %9, label %10, label %18

10:                                               ; preds = %6
  %11 = load i32, i32* %5, align 4
  %12 = load i32*, i32** %4, align 4
  %13 = load i32, i32* %5, align 4
  %14 = getelementptr inbounds i32, i32* %12, i32 %13
  store i32 %11, i32* %14, align 4
  br label %15

15:                                               ; preds = %10
  %16 = load i32, i32* %5, align 4
  %17 = add nsw i32 %16, 1
  store i32 %17, i32* %5, align 4
  br label %6

18:                                               ; preds = %6
  call void @llvm.trap()
  unreachable
}
Run Code Online (Sandbox Code Playgroud)

循环的末尾,标签 18,包含unreachable。这可以用于进一步优化,消除循环开始时的分支和比较。

编辑:John Regehr 有一篇关于如何推理 C 和 C++ 中未定义行为的优秀博客文章。虽然有点长,但非常值得一读。