GCC让我很难为以下源代码生成最佳程序集:
memset(X, 0, 16);
for (int i= 0; i < 16; ++i) {
X[0] ^= table[i][Y[i]].asQWord;
}
Run Code Online (Sandbox Code Playgroud)
X作为一个uint64_t[2]数组,并且
Y是一个unsigned char[16]数组,并且
table是一个双维数组union qword_t:
union qword_t {
uint8_t asBytes[8];
uint64_t asQWord;
};
const union qword_t table[16][256] = /* ... */;
Run Code Online (Sandbox Code Playgroud)
使用选项时,-m64 -Ofast -mno-sse它会展开循环,每个xor和赋值会产生3条指令(因此发出的指令总数为3*16 = 48):
movzx r9d, byte ptr [Y + i] ; extracting byte
xor rax, qword ptr [table + r9*8 + SHIFT] ; xoring, SHIFT = i …Run Code Online (Sandbox Code Playgroud) 我正在阅读有关空基优化(EBO)的内容.在阅读时,我脑海中浮现出以下问题:
当对类派生类没有任何贡献时(无论是功能方面还是数据方面),使用Empty类作为基类有什么意义?
在本文中,我读到了这个:
// S是空
类struct T:S
{
int x;
};[...]
请注意,我们没有丢失任何数据或代码准确性:当您创建S类型的独立对象时,对象的大小仍然是之前的1(或更多); 只有当S被用作另一个类的基类时,它的内存占用量才会缩小到零.为了实现这种节省的影响,想象一个包含125,000个对象的向量.仅EBO就可以节省半兆内存!
这是否意味着如果我们不使用"S"作为"T"的基类,我们必然会消耗两倍的兆字节内存?我认为,这篇文章比较了我认为不正确的两种不同情景.
我想知道一个真实的情景时,EBO可以证明是有用的.(手段,在相同的情况下,我们就一定是在亏损,如果我们不使用EBO!).
整点是一个空类的大小非零,但是当派生或派生时它的大小为零,那么我就不会问这个,正如我所知道的那样.我的问题是,为什么有人会从一个空洞的班级中获得他的班级?即使他没有衍生出来并简单地写出他的课程(没有任何空基础),他是否会以任何方式迷失?
c++ optimization memory-management class compiler-optimization
我很好奇是否有人可以为我阐明这一点.我正在研究一些数字数据转换的东西,我有几个执行数据转换的函数,我用两个宏定义:
#define CONV_VIA_CAST(name, dtype, vtype) \
static inline void name(void *data, void *view, size_t len) { \
vtype *vptr = (vtype*)view; \
dtype *dptr = (dtype*)data; \
for (size_t ii=0; ii < len/sizeof(vtype); ii++) { \
*vptr++ = (vtype)*dptr++; \
} \
}
#define CONV_VIA_FUNC(name, dtype, vtype, via) \
static inline void name(void *data, void *view, size_t len) { \
vtype *vptr = (vtype*)view; \
dtype *dptr = (dtype*)data; \
for (size_t ii=0; ii < len/sizeof(vtype); ii++) { \
*vptr++ …Run Code Online (Sandbox Code Playgroud) 我碰巧有几次将部分程序与OpenMP并行化,只是为了注意到最终,尽管具有良好的可扩展性,但由于单线程情况的性能较差,大多数预见的加速都会丢失(如果与串行版).
网络上出现的这种行为的常见解释是编译器生成的代码在多线程情况下可能更糟糕.无论如何,我无法在任何地方找到解释为什么装配可能更糟的参考.
那么,我想问问编译器的人是:
多线程可以抑制编译器优化吗?万一,性能怎么会受到影响?
如果它可以帮助缩小问题,我主要对高性能计算感兴趣.
免责声明:正如评论中所述,以下部分答案可能在将来过时,因为它们简要讨论了在提出问题时编译器处理优化的方式.
我目前正在编写一个ECMAScipt5编译器,它在解析树上执行各种给定的优化/转换,并编译回ECMAScipt5.
一个功能是在EnvironmentRecord中重命名绑定.
这种转换可以自动执行,例如作为旨在减少代码大小的优化的一部分,其中每个变量(不在全局范围内)将被赋予下一个最短可用名称,或者在引入引用的语句之后通过注释手动执行.新范围.
但是,我必须将(自动)进程仅限制为变量声明.
考虑这两个例子.第一个,编译,指定[Minify]为转换,第二个使用[Directives, PrettyPrint]
句法: Compiler.fromSource (src).compile ([/*Array of transformations*/]);
var bar,foo;
(function exampleMin () {
var bar="foo",
foo="bar";
function fooBar () {
return foo + bar;
}
})
Run Code Online (Sandbox Code Playgroud)
编译成
var bar,foo;function exampleMin(){var A="foo",B="bar";function fooBar(){return B+A}}
和
var bar,foo;
(function exampleMin () {
@Rename bar:A
@Rename foo:B
@Rename fooBar:C
var bar="foo",
foo="bar";
function fooBar () {
return foo + bar;
}
})
Run Code Online (Sandbox Code Playgroud)
编译成
var bar,foo;
function exampleMin(){
var A="foo",B="bar";
function C(){ …Run Code Online (Sandbox Code Playgroud) 这是我的代码:
int f(double x, double y)
{
return std::isnan(x) || std::isnan(y);
}
Run Code Online (Sandbox Code Playgroud)
如果您使用的是C而不是C++,只需替换std::为__builtin_(不要简单地删除std::,原因如下所示:为什么GCC对C++ <cmath>比C <math.h>更有效地实现isnan()?).
这是集会:
ucomisd %xmm0, %xmm0 ; set parity flag if x is NAN
setp %dl ; copy parity flag to %edx
ucomisd %xmm1, %xmm1 ; set parity flag if y is NAN
setp %al ; copy parity flag to %eax
orl %edx, %eax ; OR one byte of each result into a full-width register
Run Code Online (Sandbox Code Playgroud)
现在让我们尝试另一种做同样事情的配方:
int f(double x, …Run Code Online (Sandbox Code Playgroud) 考虑下面的C++ 11片段.对于GCC和clang,这会编译为两个(顺序一致的)foo.C++内存模型是否允许编译器将这两个加载合并到一个加载中并对x和y使用相同的值?
我认为它不能合并这些负载,因为这意味着轮询原子不再起作用,但我找不到内存模型文档中的相关部分.
#include <atomic>
#include <cstdio>
std::atomic<int> foo;
int main(int argc, char **argv)
{
int x = foo;
int y = foo;
printf("%d %d\n", x, y);
return 0;
}
Run Code Online (Sandbox Code Playgroud) c++ memory-model compiler-optimization language-lawyer stdatomic
取决于这个问题浮点除法与浮点乘法.由于某些原因,除法比乘法慢.
如果可能的话,编译器通常会用乘法代替除法吗?
例如:
float a;
// During runtime a=5.4f
float b = a/10.f;
Run Code Online (Sandbox Code Playgroud)
那将会:
float a;
// During runtime a=5.4f
float b = a*0.1f;
Run Code Online (Sandbox Code Playgroud)
如果它被认为是编译器可靠的问题,我使用VS2013默认编译器.但是,如果我得到一个通用的答案(这个优化的理论有效性)会很好
我正在研究一种以大端格式将64位值存储到内存中的函数.我希望我能编写可在小端和大端平台上运行的可移植C99代码,并让现代x86编译器bswap自动生成指令而不需要任何内置函数或内在函数.所以我开始使用以下功能:
#include <stdint.h>
void
encode_bigend_u64(uint64_t value, void *vdest) {
uint64_t bigend;
uint8_t *bytes = (uint8_t*)&bigend;
bytes[0] = value >> 56;
bytes[1] = value >> 48;
bytes[2] = value >> 40;
bytes[3] = value >> 32;
bytes[4] = value >> 24;
bytes[5] = value >> 16;
bytes[6] = value >> 8;
bytes[7] = value;
uint64_t *dest = (uint64_t*)vdest;
*dest = bigend;
}
Run Code Online (Sandbox Code Playgroud)
这适用于clang,它将此函数编译为:
bswapq %rdi
movq %rdi, (%rsi)
retq
Run Code Online (Sandbox Code Playgroud)
但是GCC 无法检测到字节交换 …
我编写了这个简单的汇编代码,运行它并使用GDB查看内存位置:
.text
.global _main
_main:
pushq %rbp
movl $5, -4(%rbp)
addl $6, -4(%rbp)
popq %rbp
ret
Run Code Online (Sandbox Code Playgroud)
它直接在内存中添加5到6个,根据GDB它可以工作.所以这是直接在内存中执行数学运算而不是CPU寄存器.
现在在C中编写相同的东西并将其编译为汇编,结果如下:
... # clang output
xorl %eax, %eax
movl $0, -4(%rbp)
movl $5, -8(%rbp)
movl -8(%rbp), %ecx # load a
addl $6, %ecx # a += 6
movl %ecx, -8(%rbp) # store a
....
Run Code Online (Sandbox Code Playgroud)
在将它们添加到一起之前,它会将它们移动到寄存器中.
那么为什么我们不直接在内存中添加?
它慢了吗?如果是这样,为什么直接在内存中添加甚至允许,为什么汇编程序在开始时没有抱怨我的汇编代码?
编辑:这是第二个程序集块的C代码,我在编译时禁用了优化.
#include <iostream>
int main(){
int a = 5;
a+=6;
return 0;
}
Run Code Online (Sandbox Code Playgroud) c ×6
c++ ×5
gcc ×4
assembly ×3
optimization ×2
c++11 ×1
clang ×1
class ×1
endianness ×1
javascript ×1
memory-model ×1
openmp ×1
stdatomic ×1
x86 ×1