我面临一个相当特殊的问题.我正在研究一种不支持按位运算的体系结构的编译器.但是,它处理签名的16位整数算术,我想知道是否有可能只使用以下方式实现按位运算:
我希望能够支持的按位操作是:
discrete-mathematics bitwise-operators compiler-optimization
下面的代码段中的函数'foo'将只加载一个结构成员A或B; 至少这是未经优化的代码的意图.
typedef struct {
int A;
int B;
} Pair;
int foo(const Pair *P, int c) {
int x;
if (c)
x = P->A;
else
x = P->B;
return c/102 + x;
}
Run Code Online (Sandbox Code Playgroud)
这是gcc -O3给出的:
mov eax, esi
mov edx, -1600085855
test esi, esi
mov ecx, DWORD PTR [rdi+4] <-- ***load P->B**
cmovne ecx, DWORD PTR [rdi] <-- ***load P->A***
imul edx
lea eax, [rdx+rsi]
sar esi, 31
sar eax, 6
sub eax, esi
add eax, ecx
ret …Run Code Online (Sandbox Code Playgroud) 代码的目的是找到32位浮点位模式的总数,它代表0到1之间的值.在我看来这应该可行,但由于某种原因,Clang的汇编输出基本上相当于return 0;.
我使用-std=c++1y -Wall -Wextra -pedantic -O2和编译了Clang 3.3和Clang 3.4.1-std=c++1y -Wall -Wextra -pedantic -O3
Clang 3.4使用-O2和-O3优化一切.
Clang 3.3仅使用-O3优化一切.
通过"优化一切",我的意思是这是程序的汇编输出:
main: # @main
xorl %eax, %eax
ret
Run Code Online (Sandbox Code Playgroud)
#include <limits>
#include <cstring>
#include <cstdint>
template <class TO, class FROM>
inline TO punning_cast(const FROM &input)
{
TO out;
std::memcpy(&out, &input, sizeof(TO));
return out;
}
int main()
{
uint32_t i = std::numeric_limits<uint32_t>::min();
uint32_t count = 0;
while (1)
{
float n = punning_cast<float>(i);
if(n >= 0.0f && n <= 1.0f) …Run Code Online (Sandbox Code Playgroud) 在写另一个问题的答案时,我注意到JIT优化的一个奇怪的边界情况.
以下程序不是 "Microbenchmark",也不是为了可靠地测量执行时间(如另一个问题的答案中所指出的).它仅用作MCVE来重现该问题:
class MissedLoopOptimization
{
public static void main(String args[])
{
for (int j=0; j<3; j++)
{
for (int i=0; i<5; i++)
{
long before = System.nanoTime();
runWithMaxValue();
long after = System.nanoTime();
System.out.println("With MAX_VALUE : "+(after-before)/1e6);
}
for (int i=0; i<5; i++)
{
long before = System.nanoTime();
runWithMaxValueMinusOne();
long after = System.nanoTime();
System.out.println("With MAX_VALUE-1 : "+(after-before)/1e6);
}
}
}
private static void runWithMaxValue()
{
final int n = Integer.MAX_VALUE;
int i = …Run Code Online (Sandbox Code Playgroud) 一般来说,默认构造函数应该是创建空容器的最快方法。这就是为什么我惊讶地发现它比初始化为空字符串文字更糟糕:
#include <string>
std::string make_default() {
return {};
}
std::string make_empty() {
return "";
}
Run Code Online (Sandbox Code Playgroud)
编译为:(clang 16,libc++)
make_default():
mov rax, rdi
xorps xmm0, xmm0
movups xmmword ptr [rdi], xmm0
mov qword ptr [rdi + 16], 0
ret
make_empty():
mov rax, rdi
mov word ptr [rdi], 0
ret
Run Code Online (Sandbox Code Playgroud)
请参阅编译器资源管理器中的实时示例。
请注意,返回{}总共将 24 个字节归零,但返回""仅将 2 个字节归零。怎么会return "";好很多呢?
我们有一个烦人的错误,我无法解释这段代码:
unsigned char bitmap[K_BITMAP_SIZE] = {0} ;
SetBit(bitmap, K_18); // Sets the bit #18 to 1
for(size_t i = 0; i < K_END; ++i)
{
if(TestBit(bitmap, i)) // true for 18
{
size_t i2 = getData(i); // for 18, will return 15
SetBit(bitmap, i2); // BUG: IS SUPPOSED TO set the bit #15 to 1
}
}
Run Code Online (Sandbox Code Playgroud)
__forceinline使用getData函数时才会在Visual C++ 2008上发生(默认情况下,VC++ 2008不会内联该函数,而VC++ 2010会这样做)奖金信息:
1- BenJ评论说这个问题没有出现在Visual C++ 2012上,这意味着这可能是编译器中的一个错误
2-如果我们 …
c++ visual-studio-2010 compiler-optimization undefined-behavior visual-studio
GCC,MSVC,LLVM以及可能的其他工具链支持链接时(整个程序)优化,以允许编译单元之间的调用优化.
在编译生产软件时是否有理由不启用此选项?
在内部,编译器应该将lambda表达式转换为方法.在这种情况下,这些方法是私有还是公共(或其他),是否可以改变它?
我想知道为什么没有编译器准备将相同值的连续写入合并到单个原子变量,例如:
#include <atomic>
std::atomic<int> y(0);
void f() {
auto order = std::memory_order_relaxed;
y.store(1, order);
y.store(1, order);
y.store(1, order);
}
Run Code Online (Sandbox Code Playgroud)
我尝试过的每个编译器都会发出三次上面的编写.什么合法的,无种族的观察者可以看到上述代码与具有单次写入的优化版本之间的差异(即,不是"假设"规则适用)?
如果变量是易变的,那么显然不适用优化.在我的情况下有什么阻止它?
这是编译器资源管理器中的代码.
考虑一个简单的程序:
int main() {
int* ptr = nullptr;
delete ptr;
}
Run Code Online (Sandbox Code Playgroud)
对于GCC(7.2),在结果程序中有call关于的指令operator delete.对于Clang和Intel编译器,没有这样的指令,空指针删除被完全优化(-O2在所有情况下).你可以在这里测试:https://godbolt.org/g/JmdoJi.
我想知道这样的优化能否以某种方式与GCC一起开启?(我更广泛的动机源于自定义swapvs std::swap可移动类型的问题,其中删除空指针可能代表第二种情况下的性能损失; 有关详细信息,请参阅/sf/answers/3198249771/.)
UPDATE
为了澄清我对这个问题的动机:如果我在移动赋值运算符和某个类的析构函数中使用delete ptr;无if (ptr)保护,那么该类的对象将产生3个GCC指令.这可能是相当大的性能损失,例如,在对这些对象的数组进行排序时.std::swapcall
此外,我可以if (ptr) delete ptr;在任何地方写作,但是想知道,这是否也不能成为性能损失,因为delete表达式也需要检查ptr.但是,在这里,我想,编译器只会生成一个检查.
此外,我真的很喜欢delete没有后卫的可能性,这对我来说是一个惊喜,它可以产生不同的(表现)结果.
UPDATE
我只是做了一个简单的基准测试,即排序对象,它们delete在移动赋值运算符和析构函数中调用.来源是:https://godbolt.org/g/7zGUvo
std::sort使用GCC 7.1测量的运行时间和-O2Xeon E2680v3上的标志:
链接代码中存在一个错误,它会比较指针,而不是指向值.更正结果如下:
if后卫: