我在2009年首先注意到GCC(至少在我的项目和我的机器上)如果我优化尺寸(-Os
)而不是速度(-O2
或-O3
),则会产生明显更快的代码,我一直想知道为什么.
我设法创建(相当愚蠢)代码,显示这种令人惊讶的行为,并且足够小,无法在此处发布.
const int LOOP_BOUND = 200000000;
__attribute__((noinline))
static int add(const int& x, const int& y) {
return x + y;
}
__attribute__((noinline))
static int work(int xval, int yval) {
int sum(0);
for (int i=0; i<LOOP_BOUND; ++i) {
int x(xval+sum);
int y(yval+sum);
int z = add(x, y);
sum += z;
}
return sum;
}
int main(int , char* argv[]) {
int result = work(*argv[1], *argv[2]);
return result;
}
Run Code Online (Sandbox Code Playgroud)
如果我用-Os
它编译它,执行这个程序需要0.38秒,如果用-O2 …
我正在阅读Agner Fog的优化手册,并且遇到了这个例子:
double data[LEN];
void compute()
{
const double A = 1.1, B = 2.2, C = 3.3;
int i;
for(i=0; i<LEN; i++) {
data[i] = A*i*i + B*i + C;
}
}
Run Code Online (Sandbox Code Playgroud)
Agner 指出,有一种方法可以优化此代码 - 通过认识到循环可以避免使用昂贵的乘法,而是使用每次迭代应用的“增量”。
我用一张纸来证实这个理论,首先......
...当然,他是对的 - 在每次循环迭代中,我们可以通过添加“增量”,基于旧结果计算新结果。该增量从值“A+B”开始,然后每一步增加“2*A”。
所以我们将代码更新为如下所示:
void compute()
{
const double A = 1.1, B = 2.2, C = 3.3;
const double A2 = A+A;
double Z = A+B;
double Y = C;
int i;
for(i=0; i<LEN; i++) {
data[i] …
Run Code Online (Sandbox Code Playgroud) 我有一个任意的.NET程序集列表.
我需要以编程方式检查每个DLL是否是为x86构建的(而不是x64或任何CPU).这可能吗?
背景:
在使用嵌入式汇编语言优化某些Pascal代码时,我注意到了一条不必要的MOV
指令,并将其删除.
令我惊讶的是,删除不必要的指令会导致我的程序变慢.
我发现添加任意无用的MOV
指令可以进一步提高性能.
效果不稳定,并且基于执行顺序进行更改:相同的垃圾指令向上或向下移动一行会产生减速.
我知道CPU会进行各种优化和精简,但这看起来更像是黑魔法.
数据:
我的代码版本有条件地在运行时间的循环中编译三个垃圾操作2**20==1048576
.(周围的程序只计算SHA-256哈希值).
在我相当老的机器(英特尔(R)Core(TM)2 CPU 6400 @ 2.13 GHz)上的结果:
avg time (ms) with -dJUNKOPS: 1822.84 ms
avg time (ms) without: 1836.44 ms
Run Code Online (Sandbox Code Playgroud)
程序在循环中运行25次,每次运行顺序随机变化.
摘抄:
{$asmmode intel}
procedure example_junkop_in_sha256;
var s1, t2 : uint32;
begin
// Here are parts of the SHA-256 algorithm, in Pascal:
// s0 {r10d} := ror(a, 2) xor ror(a, 13) xor …
Run Code Online (Sandbox Code Playgroud) 我一直在阅读div
和mul
组装操作,我决定通过在C中编写一个简单的程序来实现它们:
#include <stdlib.h>
#include <stdio.h>
int main()
{
size_t i = 9;
size_t j = i / 5;
printf("%zu\n",j);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
然后生成汇编语言代码:
gcc -S division.c -O0 -masm=intel
Run Code Online (Sandbox Code Playgroud)
但是看生成的division.s
文件,它不包含任何div操作!相反,它通过位移和魔术数字来做某种黑魔法.这是一个计算代码片段i/5
:
mov rax, QWORD PTR [rbp-16] ; Move i (=9) to RAX
movabs rdx, -3689348814741910323 ; Move some magic number to RDX (?)
mul rdx ; Multiply 9 by magic number
mov rax, rdx ; Take only the upper 64 bits of the …
Run Code Online (Sandbox Code Playgroud) 我用 C 语言实现了一个冒泡排序,并在测试其性能时发现该-O3
标志使其运行速度甚至比没有标志时还要慢!与此同时-O2
,它的运行速度比预期的要快得多。
没有优化:
time ./sort 30000
./sort 30000 1.82s user 0.00s system 99% cpu 1.816 total
Run Code Online (Sandbox Code Playgroud)
-O2
:
time ./sort 30000
./sort 30000 1.00s user 0.00s system 99% cpu 1.005 total
Run Code Online (Sandbox Code Playgroud)
-O3
:
time ./sort 30000
./sort 30000 2.01s user 0.00s system 99% cpu 2.007 total
Run Code Online (Sandbox Code Playgroud)
代码:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <time.h>
int n;
void bubblesort(int *buf)
{
bool changed = true;
for (int i = n; changed == true; …
Run Code Online (Sandbox Code Playgroud) 以下链接解释了UNIX(BSD风格)和Linux的x86-32系统调用约定:
但是UNIX和Linux上的x86-64系统调用约定是什么?
我相信我在实现 O'Neill 的 PCG PRNG 时在 GCC 中发现了一个错误。(Godbolt 编译器资源管理器上的初始代码)
相乘后oldstate
通过MULTIPLIER
,(存储在RDI结果),GCC不该结果添加到INCREMENT
,movabs'ingINCREMENT
到RDX代替,然后把它用作rand32_ret.state的返回值
最小可重现示例(编译器资源管理器):
#include <stdint.h>
struct retstruct {
uint32_t a;
uint64_t b;
};
struct retstruct fn(uint64_t input)
{
struct retstruct ret;
ret.a = 0;
ret.b = input * 11111111111 + 111111111111;
return ret;
}
Run Code Online (Sandbox Code Playgroud)
生成的程序集(GCC 9.2、x86_64、-O3):
fn:
movabs rdx, 11111111111 # multiplier constant (doesn't fit in imm32)
xor eax, eax # ret.a = 0
imul rdi, rdx
movabs rdx, 111111111111 …
Run Code Online (Sandbox Code Playgroud) 我想确定本机程序集是否从托管代码应用程序(C#)编译为x64或x86 .
我认为它必须在PE头中的某处,因为OS加载器需要知道这些信息,但我找不到它.当然我更喜欢在托管代码中执行它,但如果有必要,我可以使用本机C++.
x86-64 ×10
assembly ×6
gcc ×4
c ×3
.net ×2
64-bit ×2
optimization ×2
performance ×2
x86 ×2
abi ×1
assemblies ×1
c# ×1
c++ ×1
compiler-bug ×1
freepascal ×1
linux ×1
simd ×1
unix ×1
winapi ×1
x86-16 ×1