相关疑难解决方法(0)

为什么gcc会生成详细的汇编代码?

我对GCC生成的汇编代码有疑问(-S选项).因为,我是汇编语言的新手并且对它知之甚少,这个问题将是非常原始的.不过,我希望有人会回答:

假设,我有这个C代码:

main(){

    int x = 15; 

    int y = 6;

    int z = x - y;


    return 0;
}
Run Code Online (Sandbox Code Playgroud)

如果我们查看汇编代码(特别是对应于int z = x - y的部分),我们会看到:

主要:

...
subl    $16, %esp
movl    $15, -4(%ebp)
movl    $6, -8(%ebp)
movl    -8(%ebp), %eax
movl    -4(%ebp), %edx
movl    %edx, %ecx
subl    %eax, %ecx
movl    %ecx, %eax
movl    %eax, -12(%ebp)
...
Run Code Online (Sandbox Code Playgroud)

为什么GCC不能生成类似这样的东西,这样可以减少复制内容.

主要:

...
movl    $15, -4(%ebp)
movl    $6, -8(%ebp)
movl    -8(%ebp), %edx          
movl    -4(%ebp), %eax          
subl    %edx, %eax              
movl    %eax, -12(%ebp)
...
Run Code Online (Sandbox Code Playgroud)

PS

Linux …

linux assembly gcc

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

添加冗余分配可在编译时加速代码而无需优化

我发现了一个有趣的现象:

#include<stdio.h>
#include<time.h>

int main() {
    int p, q;
    clock_t s,e;
    s=clock();
    for(int i = 1; i < 1000; i++){
        for(int j = 1; j < 1000; j++){
            for(int k = 1; k < 1000; k++){
                p = i + j * k;
                q = p;  //Removing this line can increase running time.
            }
        }
    }
    e = clock();
    double t = (double)(e - s) / CLOCKS_PER_SEC;
    printf("%lf\n", t);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我在i5-5257U Mac OS上使用GCC 7.3.0来编译代码 …

performance x86 assembly

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

未使用的asm()在不支持的体系结构上的行为

asm()在未使用但不受支持的架构中,代码块的行为是什么?例如,如果我在ARM上编译以下代码会发生什么

if (false) {
    asm volatile("x86specificinstruction" ...);
}
Run Code Online (Sandbox Code Playgroud)

这是有效的C++吗?代码会编译吗?标准是否对此类情况有所说明?

c++ x86 assembly arm

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

静态值存储在程序集中的哪个位置

这是一个简单的C代码

#include <stdio.h>

int a = 5;

static int b = 20;

int main(){

 int c = 30;

 return 0;
}
Run Code Online (Sandbox Code Playgroud)

编译为无需优化的组合:

    .section    __TEXT,__text,regular,pure_instructions
    .macosx_version_min 10, 13
    .globl  _main                   ## -- Begin function main
    .p2align    4, 0x90
_main:                                  ## @main
    .cfi_startproc
## %bb.0:
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    xorl    %eax, %eax
    movl    $0, -4(%rbp)
    movl    $30, -8(%rbp)
    popq    %rbp
    retq
    .cfi_endproc
                                        ## -- End function
    .section    __DATA,__data
    .globl  _a                      ## @a
    .p2align    2 …
Run Code Online (Sandbox Code Playgroud)

c assembly

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

重复计算的性能

我想知道是否值得进行一次计算并存储结果,或者进行两次计算是否更快?

例如在本例中:

float n1 = a - b;
float n2 = a + b;
float result = n1 * n2 / (n1 * n2);
Run Code Online (Sandbox Code Playgroud)

最好这样做:

float result = (a - b) * (a + b) / ((a - b) * (a + b));
Run Code Online (Sandbox Code Playgroud)

?我知道通常我们存储结果,但我想知道做加法而不是调用内存来存储/检索值是否不是更快。

c++ optimization compiler-optimization

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

简单构造函数的复杂编译器输出

我有一个带有两个64位整数成员的struct X和一个构造函数:

struct X
{
    X(uint64_t a, uint64_t b)
    {
        a_ = a; b_ = b;
    }

    uint64_t a_, b_;
};
Run Code Online (Sandbox Code Playgroud)

当我查看编译器输出(在64位Linux上为x86-64 gcc 8.3和x86-64 clang 8.0.0)时,未启用任何优化,我看到了以下针对构造函数的代码。

x86-64 gcc 8.3:

X::X(unsigned long, unsigned long):
    push    rbp
    mov     rbp, rsp
    mov     QWORD PTR [rbp-8], rdi
    mov     QWORD PTR [rbp-16], rsi
    mov     QWORD PTR [rbp-24], rdx
    mov     rax, QWORD PTR [rbp-8]
    mov     QWORD PTR [rax], 0
    mov     rax, QWORD PTR [rbp-8]
    mov     QWORD PTR [rax+8], 0
    mov     rax, QWORD PTR [rbp-8]
    mov     rdx, …
Run Code Online (Sandbox Code Playgroud)

c++ assembly gcc clang compiler-optimization

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

arr[0] = arr[1] = C 中的值是不好的做法吗?

正如我上面所说,这是不好的做法吗?在 ASM 中它会是什么样子?我的意思是,我不知道它是否被翻译成这样:

arr[0] = value;
arr[1] = value;
Run Code Online (Sandbox Code Playgroud)

或者像这样:

arr[1] = value;
arr[0] = arr[1];
Run Code Online (Sandbox Code Playgroud)

其中第二个显然效率更低(imm vs mem)。

提前致谢。

c operators operator-precedence assignment-operator

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

x86 ASM:无用的条件跳转?

我正在查看以下 x86 汇编代码(英特尔语法):

movzx   eax, al
and     eax, 3
cmp     eax, 3
ja      loc_6BE9A0
Run Code Online (Sandbox Code Playgroud)

在我看来,这在 C 中应该是这样的:

eax &= 0xFF;
eax &= 3;
if (eax > 3)
   loc_6BE9A0();
Run Code Online (Sandbox Code Playgroud)

这似乎没有多大意义,因为此条件永远不会为真(因为eax如果之前与 3 进行了与运算,则永远不会大于 3)。我在这里遗漏了什么还是这真的只是一个不必要的条件?

而且:movzx eax, al如果之后它被 3 和-ed 也不应该是必要的,是吗?

我问这个是因为我对汇编语言不太熟悉,所以我不完全确定我是否在这里遗漏了一些东西。

x86 assembly intel

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

为什么 CPU 不能在一个简单的循环中实现相当于 Ghz 的 FLOP 性能?

我想知道为什么像这样的简单循环无法达到我的 CPU 时钟速度(4,2Ghz):

float sum = 0;    
for (int i = 0; i < 1000000; i+=1) {
    sum = sum * 1 + 1;
}
Run Code Online (Sandbox Code Playgroud)

凭直觉,我希望在不到 1 毫秒(例如 0,238 毫秒)的时间内实现这一目标,每秒进行 42 亿次迭代。但我得到的时间约为 3 毫秒,即每秒约 3.33 亿次迭代。

我假设做数学运算需要 2 个周期,一个用于乘法,另一个用于求和。假设我正在执行 6.66 亿次操作……看起来仍然很慢。然后我假设循环比较需要一个周期,循环计数器需要另一个周期......

所以我创建了以下代码来删除循环......

void listOfSums() {
    float internalSum = 0;
    internalSum = internalSum * 1 + 1;
    internalSum = internalSum * 1 + 1;
    internalSum = internalSum * 1 + 1;
    internalSum = internalSum * 1 + 1;
    // Repeated 100k …
Run Code Online (Sandbox Code Playgroud)

c cpu assembly

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

受限是 volatile 的对立面吗?

我可以使用volatile类似以下的内容,其中的值可能会被外部函数/信号/等修改:

volatile int exit = 0;
while (!exit)
{
    /* something */
}
Run Code Online (Sandbox Code Playgroud)

并且编译器/程序集不会缓存该值。另一方面,使用restrict关键字,我可以告诉编译器一个变量没有别名/只在当前范围内被引用一次,编译器可以尝试优化它:

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

这是对两者的正确理解,它们基本上是彼此对立的吗?volatile说该变量可以在当前范围之外修改并restrict说它不能?对于使用这两个关键字的最基本示例,它将发出的汇编指令示例是什么?

c x86 assembly volatile restrict-qualifier

2
推荐指数
1
解决办法
187
查看次数