我被告知并且从英特尔的手册中读到可以将指令写入内存,但是指令预取队列已经获取了陈旧的指令并将执行那些旧的指令.我没有成功观察到这种行为.我的方法如下.
英特尔软件开发手册从第11.6节开始说明
对当前在处理器中高速缓存的代码段中的存储器位置的写入导致相关联的高速缓存行(或多个行)无效.此检查基于指令的物理地址.此外,P6系列和奔腾处理器检查对代码段的写入是否可以修改已经预取执行的指令.如果写入影响预取指令,则预取队列无效.后一种检查基于指令的线性地址.
所以,看起来如果我希望执行陈旧的指令,我需要有两个不同的线性地址引用相同的物理页面.所以,我将内存映射到两个不同的地址.
int fd = open("code_area", O_RDWR | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO);
assert(fd>=0);
write(fd, zeros, 0x1000);
uint8_t *a1 = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_FILE | MAP_SHARED, fd, 0);
uint8_t *a2 = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_FILE | MAP_SHARED, fd, 0);
assert(a1 != a2);
Run Code Online (Sandbox Code Playgroud)
我有一个汇编函数,它接受一个参数,一个指向我想要更改的指令的指针.
fun:
push %rbp
mov %rsp, %rbp
xorq %rax, %rax # Return value 0
# A far jump simulated with a far return
# Push the …Run Code Online (Sandbox Code Playgroud) 我试图找到一种方法来执行间接左移/右移操作而不实际使用变量移位操作或任何分支.
我正在研究的特定PowerPC处理器有一个怪癖,即按常数立即移位,就像
int ShiftByConstant( int x ) { return x << 3 ; }
Run Code Online (Sandbox Code Playgroud)
是快速的,单操作的,超标量的,而变量的变换,如
int ShiftByVar( int x, int y ) { return x << y ; }
Run Code Online (Sandbox Code Playgroud)
是一个微编码操作,需要7-11个周期才能执行,而管道的其余部分都停止运行.
我想要做的是弄清楚哪个非微码整数PPC操作sraw解码然后单独发出它们.这对sraw自身的延迟没有帮助- 它将用六个替换一个操作 - 但在这六个操作之间我可以将一些工作双重调度到其他执行单元并获得净增益.
我似乎无法找到μopssraw解码到的任何地方 - 有谁知道如何用一系列常量移位和基本整数运算替换变量位移?(for循环或开关或其中带有分支的任何东西都不会起作用,因为分支惩罚甚至比微码惩罚更大,即使对于正确预测的分支也是如此.)
这无需在装配中回答; 我希望学习算法而不是特定的代码,所以用C语言或高级语言甚至伪代码的答案都会非常有用.
编辑:我应该补充一些说明:
PPC具有条件移动,因此我们可以假设存在无分支内部函数
int isel(a, b, c) { return a >= 0 ? b : c; }
Run Code Online (Sandbox Code Playgroud)
(如果你写出一个做同样事情的三元组,我会明白你的意思)
sraw.:-(如果可用(在运行时测试),实现使用特定 CPU 指令的同一功能的多个版本的最佳方法是什么,或者如果没有,则回退到较慢的实现?
例如,x86 BMI2 提供了非常有用的PDEP指令。我将如何编写 C 代码,以便它在启动时测试正在执行的 CPU 的 BMI2 可用性,并使用两种实现之一——一种使用_pdep_u64调用(可用-mbmi2),另一种使用 C 进行“手动”位操作代码。是否有对此类情况的内置支持?在提供对较新的内在函数的访问的同时,如何让 GCC 为较旧的 arch 编译?我怀疑如果通过全局函数指针而不是每次都使用 if/else 调用函数,执行速度会更快吗?