我写了这个简单的C程序:
int main() {
int i;
int count = 0;
for(i = 0; i < 2000000000; i++){
count = count + 1;
}
}
Run Code Online (Sandbox Code Playgroud)
我想看看gcc编译器如何优化这个循环(显然添加1 2000000000次应该是"一次添加2000000000 ").所以:
GCC test.c的,然后time就a.out给出了:
real 0m7.717s
user 0m7.710s
sys 0m0.000s
Run Code Online (Sandbox Code Playgroud)
$ gcc -O2 test.c 然后time ona.out`给出:
real 0m0.003s
user 0m0.000s
sys 0m0.000s
Run Code Online (Sandbox Code Playgroud)
然后我用两个人拆开了gcc -S.第一个似乎很清楚:
.file "test.c"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
movq %rsp, %rbp
.cfi_offset 6, …Run Code Online (Sandbox Code Playgroud) 我有一个int x。为简单起见,假设ints 占据范围 -2^31 到 2^31-1。我想计算2*x-1. 我允许x为任何值 0 <= x<= 2^30。如果我计算 2*(2^30),我会得到 2^31,这是整数溢出。
一种解决方案是计算2*(x-1)+1. 比我想要的多了一项减法,但这不应该溢出。但是,编译器会将其优化为2*x-1. 这是源代码的问题吗?这是可执行文件的问题吗?
这是 Godbolt 的输出2*x-1:
func(int): # @func(int)
lea eax, [rdi + rdi]
dec eax
ret
Run Code Online (Sandbox Code Playgroud)
这是 Godbolt 的输出2*(x-1)+1:
func(int): # @func(int)
lea eax, [rdi + rdi]
dec eax
ret
Run Code Online (Sandbox Code Playgroud) c++ integer-overflow compiler-optimization undefined-behavior integer-arithmetic
就编译器优化而言,将堆分配更改为堆栈分配是否合法和/或可能?或者会破坏as-if规则?
例如,假设这是代码的原始版本
{
Foo* f = new Foo();
f->do_something();
delete f;
}
Run Code Online (Sandbox Code Playgroud)
编译器是否能够将此更改为以下内容
{
Foo f{};
f.do_something();
}
Run Code Online (Sandbox Code Playgroud)
我不这么认为,因为如果原始版本依赖于自定义分配器之类的东西,那将会产生影响.标准是否对此有具体说明?
我是一名 R 开发人员,使用 C 来实现算法目的,并且有一个问题:为什么看起来很慢的 C 循环实际上比其他方法更快。
在 R 中,我们的布尔类型实际上可以有三个值:true、false和,并且我们在 C 级别na使用 an 来表示。int
我正在研究一个向量化&&操作(是的,我们已经在 R 中使用了这个,但请耐心等待),它也可以处理这种na情况。标量结果如下所示:
F && F == F
F && T == F
F && N == F
T && F == F
T && T == T
T && N == N
N && F == F
N && T == N
N && N == N
Run Code Online (Sandbox Code Playgroud)
请注意,它的工作方式&&与 C 中类似,只不过当na与除 …
我知道在可能的情况下,在通过引用或指针传递参数时,应尽可能使用const关键字.如果我指定参数是常量,编译器可以做的任何优化吗?
可能有几种情况:
功能参数:
常量参考:
void foo(const SomeClass& obj)
Run Code Online (Sandbox Code Playgroud)
Constant SomeClass对象:
void foo(const SomeClass* pObj)
Run Code Online (Sandbox Code Playgroud)
并且指向SomeClass的常量指针:
void foo(SomeClass* const pObj)
Run Code Online (Sandbox Code Playgroud)
变量声明:
const int i = 1234
Run Code Online (Sandbox Code Playgroud)
函数声明:
const char* foo()
Run Code Online (Sandbox Code Playgroud)
每个提供什么样的编译器优化(如果有的话)?
问题
我们有一个用于模拟任务的中型程序,我们需要对其进行优化.我们已经尽最大努力优化我们的编程技能,包括使用Gprof和Valgrind进行分析.
最后完成后,我们希望在几个系统上运行该程序可能已有几个月了.因此,我们真的很有兴趣将优化推向极限.
所有系统都将在相对较新的硬件(Intel i5或i7)上运行Debian/Linux.
问题
使用最新版本的g ++有哪些可能的优化选项,超出-O3/-Ofast?
我们也对昂贵的小优化感兴趣,从长远来看,这将是非常重要的.
我们现在用的是什么
现在我们使用以下g ++优化选项:
-Ofast:最高"标准"优化级别.包含-ffast-math在我们的计算中没有引起任何问题,因此我们决定采用它,尽管非标准符合性.-march=native:启用所有CPU特定指令.-flto 允许跨不同编译单元的链接时间优化.Haskell功能强大且纯粹,所以基本上它具有编译器能够处理隐式并行性所需的所有属性.
考虑这个简单的例子:
f = do
a <- Just 1
b <- Just $ Just 2
-- ^ The above line does not utilize an `a` variable, so it can be safely
-- executed in parallel with the preceding line
c <- b
-- ^ The above line references a `b` variable, so it can only be executed
-- sequentially after it
return (a, c)
-- On the exit from a monad scope we wait for all computations to …Run Code Online (Sandbox Code Playgroud) parallel-processing concurrency haskell compiler-optimization
我在一个Java程序中观察到了一些奇怪的行为.我试图尽可能地删除代码,同时仍然能够复制行为.代码全部如下.
public class StrangeBehaviour {
static boolean recursionFlag = true;
public static void main(String[] args) {
long startTime = System.nanoTime();
for (int i = 0; i < 10000; i ++) {
functionA(6, 0);
}
long endTime = System.nanoTime();
System.out.format("%.2f seconds elapsed.\n", (endTime - startTime) / 1000.0 / 1000 / 1000);
}
static boolean functionA(int recursionDepth, int recursionSwitch) {
if (recursionDepth == 0) { return true; }
return functionB(recursionDepth, recursionSwitch);
}
static boolean functionB(int recursionDepth, int recursionSwitch) {
for (int i …Run Code Online (Sandbox Code Playgroud) 我偶然发现了这篇Reddit 帖子,它是对以下代码片段的一个玩笑,
void f(int& x) {
if (x != 1) {
x = 1;
}
}
void g(int& x) {
x = 1;
}
Run Code Online (Sandbox Code Playgroud)
说这两个函数不等同于“编译器”。我确信任何主要的 C++ 编译器都会将条件赋值优化为无条件存储,从而为f和发出相同的汇编代码g。
谁能向我解释为什么会这样?
我的想法是:无条件存储很可能会更快,因为无论如何我们都必须访问内存来读取比较值,并且分支代码会给分支预测器带来压力。此外,编译器不应将存储视为副作用(AFAIK),即使后续内存访问可能会更快或更慢,具体取决于是否f由于缓存局部性而采用分支。
那么编译器就无法弄清楚这一点吗?虽然证明f和 的等价性g可能并不容易,但我觉得这些编译器能够解决更困难的问题。那么我可能错了,这些功能毕竟不相等,或者这里发生了什么?
我正在尝试理解常规规则。根据cppreference:
as-if规则
允许进行任何和所有不改变程序可观察行为的代码转换解释
只要满足以下条件,C ++编译器就可以对程序进行任何更改:[...]
我很难理解“说明”部分的第二个技巧:
2)在程序终止时,写入文件的数据与在执行程序时完全一样。
我只是不明白“程序是按书面形式执行”的意思。
c++ ×6
c ×3
clang ×1
concurrency ×1
const ×1
disassembly ×1
g++ ×1
gcc ×1
haskell ×1
java ×1
performance ×1
recursion ×1