小编Pet*_*des的帖子

x86的MOV真的可以"免费"吗?为什么我不能重现这个呢?

我一直看到人们声称MOV指令可以在x86中免费,因为寄存器重命名.

对于我的生活,我无法在一个测试用例中验证这一点.每个测试用例我尝试揭穿它.

例如,这是我用Visual C++编译的代码:

#include <limits.h>
#include <stdio.h>
#include <time.h>

int main(void)
{
    unsigned int k, l, j;
    clock_t tstart = clock();
    for (k = 0, j = 0, l = 0; j < UINT_MAX; ++j)
    {
        ++k;
        k = j;     // <-- comment out this line to remove the MOV instruction
        l += j;
    }
    fprintf(stderr, "%d ms\n", (int)((clock() - tstart) * 1000 / CLOCKS_PER_SEC));
    fflush(stderr);
    return (int)(k + j + l);
}
Run Code Online (Sandbox Code Playgroud)

这为循环生成以下汇编代码(随意生成这个你想要的;你显然不需要Visual C++):

LOOP:
    add edi,esi
    mov …
Run Code Online (Sandbox Code Playgroud)

c x86 assembly cpu-registers micro-optimization

23
推荐指数
2
解决办法
2113
查看次数

为什么按位运算比旧微处理器上的加/减操作稍快?

我今天看到了这段摘录:

在大多数较旧的微处理器上,按位运算比加法和减法运算稍快,并且通常比乘法和除法运算快得多.在现代体系结构中,情况并非如此:按位运算通常与添加速度相同(尽管仍然比乘法更快).

我很好奇为什么按位操作比旧微处理器上的加/减操作稍快一些.

我能想到的只会导致延迟的是,实现加/减的电路取决于几级逻辑门(并行加法器和诸如此类),而按位运算则具有更简单的电路实现.这是什么原因?

我知道算术和按位运算都在现代处理器的一个时钟内执行,但纯粹谈到电路的传播时间,理论上现在处理器中的延迟仍然存在吗?

最后,我有一个关于按位移位操作执行的概念C问题:

unsigned x = 1;
x <<= 5;

unsigned y = 0;
y += 32;
Run Code Online (Sandbox Code Playgroud)

双方xy应持有的价值32,但它采取5个独立左移获得x该值(中位运算的变化通过管道实现)?为了澄清,我纯粹是在询问电路行为而不是时钟周期数.

c bit-manipulation cpu-architecture bitwise-operators digital-logic

22
推荐指数
1
解决办法
1万
查看次数

由运行时常量值重复整数除

在我的程序中的某个时刻,我计算整数除数d.从那时起d,这将是不变的.

稍后在代码中我将除以它d几次 - 执行整数除法,因为值d不是编译时已知常量.

鉴于与其他类型的整数运算相比,整数除法是一个相对较慢的过程,我想优化它.我可以存储一些替代格式d,以便分割过程执行得更快吗?也许是某种形式的倒数?

我不需要d其他任何东西的价值.

d是任何64位整数,但通常很适合32位.

c++ optimization assembly x86-64

22
推荐指数
2
解决办法
1316
查看次数

当将变量分配给对其自身的引用时,在修改然后由函数调用返回之间,结果应该是什么?

#include <iostream>

int& addOne(int& x)
{
    x += 1;
    return x;
}

int main()
{
    int x {5};
    addOne(x) = x;
    std::cout << x << ' ' << addOne(x);
}
Run Code Online (Sandbox Code Playgroud)

我目前正在学习左值和右值,并进行了一些实验,并做出了这似乎得到了相互矛盾的结果。 https://godbolt.org/z/KqsGz3Toe产生的输出为“5 6”,Clion 和 Visual Studio 也是如此,但是https://www.onlinegdb.com/49mUC7x8U产生的结果为“6 7”

我认为,因为addOne作为引用调用,所以尽管被称为左值,x它仍会显式地将 的值更改为 6。x正确的结果应该是什么?

c++ sequence-points

22
推荐指数
1
解决办法
2064
查看次数

移位运算符的结果类型是什么?

考虑以下清单:

#include <type_traits>
#include <cstdint>

static_assert(std::is_same_v<decltype(31), int32_t>);
static_assert(std::is_same_v<decltype(31u), uint32_t>);

static_assert(std::is_same_v<decltype((signed char)1 << 1), int32_t>);
static_assert(std::is_same_v<decltype((signed char)1 << 1u), int32_t>);
static_assert(std::is_same_v<decltype((unsigned char)1 << 1), int32_t>);
// Signed result for unsigned char
static_assert(std::is_same_v<decltype((unsigned char)1 << 1u), int32_t>);
// But unsigned for uint32_t
static_assert(std::is_same_v<decltype(1u << 1u), uint32_t>);
Run Code Online (Sandbox Code Playgroud)

它可以与 GCC 和 Clang 很好地编译。我很困惑operator<<(uint8_t, uint32_t)。为什么要签署结果?

c++ types bit-shift integer-promotion

22
推荐指数
2
解决办法
2117
查看次数

21
推荐指数
3
解决办法
2万
查看次数

字可寻址和字节可寻址之间的区别

有人能解释一下有什么不同WordByte可寻址的吗?它与内存大小等有什么关系?

memory operating-system cpu-architecture

21
推荐指数
2
解决办法
5万
查看次数

打印__m128i变量

我正在尝试学习使用内在函数进行编码,下面是一个添加代码的代码

compiler used: icc

#include<stdio.h>
#include<emmintrin.h>
int main()
{
        __m128i a = _mm_set_epi32(1,2,3,4);
        __m128i b = _mm_set_epi32(1,2,3,4);
        __m128i c;
        c = _mm_add_epi32(a,b);
        printf("%d\n",c[2]);
        return 0;
}
Run Code Online (Sandbox Code Playgroud)

我得到以下错误:

test.c(9): error: expression must have pointer-to-object type
        printf("%d\n",c[2]);
Run Code Online (Sandbox Code Playgroud)

如何在c类型变量中打印值__m128i

c assembly sse simd intrinsics

21
推荐指数
3
解决办法
2万
查看次数

如何控制C数学是否使用SSE2?

我在fp:strict模式下使用MSVC进入了C库的超越数学函数的汇编.他们似乎都遵循相同的模式,这就是发生的事情sin.

首先,从名为"disp_pentium4.inc"的文件中有一个调度例程.它检查变量___use_sse2_mathfcns是否已设置; 如果是这样,电话__sin_pentium4,否则打电话__sin_default.

__sin_pentium4 (在"sin_pentium4.asm"中)首先将参数从x87 fpu传送到xmm0寄存器,使用SSE2指令执行计算,然后将结果加载回fpu.

__sin_default(在"sin.asm"中)将变量保存在x87堆栈上并简单地调用fsin.

因此,在这两种情况下,操作数推x87堆栈上和它返回为好,使之透明的来电,但如果___use_sse2_mathfcns被定义,在SSE2而不是的x87实际执行的操作.

这种行为是对我来说很有趣,因为的x87超越函数是臭名昭著的具有取决于实施的行为稍有不同,而SSE2的给定代码块要经常给重现的结果.

有没有办法确定在编译或运行时是否会使用SSE2代码路径?我不是很精通编写程序集,所以如果这涉及编写任何程序集,那么代码示例将不胜感激.

c++ floating-point sse deterministic visual-c++

21
推荐指数
1
解决办法
1784
查看次数

x86-64 Linux中不再允许32位绝对地址?

64位Linux默认使用小内存模型,它将所有代码和静态数据置于2GB地址限制之下.这可确保您可以使用32位绝对地址.较旧版本的gcc使用静态数组的32位绝对地址,以便为相对地址计算保存额外的指令.但是,这不再有效.如果我尝试在汇编中创建一个32位的绝对地址,我会收到链接器错误:"在创建共享对象时,不能使用".data"重定位R_X86_64_32S;使用-fPIC重新编译".当然,此错误消息具有误导性,因为我没有创建共享对象,-fPIC也没有帮助.到目前为止我发现的是:gcc版本4.8.5对静态数组使用32位绝对地址,gcc版本6.3.0不使用.版本5可能也没有.binutils 2.24中的链接器允许32位绝对地址,而2.28则不允许.

这种变化的后果是必须重新编译旧库并破坏传统汇编代码.

现在我想问一下:这个改变是什么时候做的?它在某处记录了吗?是否有一个链接器选项,使其接受32位绝对地址?

linux gcc x86-64 linker-errors relocation

21
推荐指数
1
解决办法
5787
查看次数