我对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 …
我发现了一个有趣的现象:
#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来编译代码 …
asm()在未使用但不受支持的架构中,代码块的行为是什么?例如,如果我在ARM上编译以下代码会发生什么
if (false) {
asm volatile("x86specificinstruction" ...);
}
Run Code Online (Sandbox Code Playgroud)
这是有效的C++吗?代码会编译吗?标准是否对此类情况有所说明?
这是一个简单的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) 我想知道是否值得进行一次计算并存储结果,或者进行两次计算是否更快?
例如在本例中:
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)
?我知道通常我们存储结果,但我想知道做加法而不是调用内存来存储/检索值是否不是更快。
我有一个带有两个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) 正如我上面所说,这是不好的做法吗?在 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)。
提前致谢。
我正在查看以下 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 也不应该是必要的,是吗?
我问这个是因为我对汇编语言不太熟悉,所以我不完全确定我是否在这里遗漏了一些东西。
我想知道为什么像这样的简单循环无法达到我的 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) 我可以使用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说它不能?对于使用这两个关键字的最基本示例,它将发出的汇编指令示例是什么?