- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在尝试寻找一种方法来执行间接左移/右移操作,而无需实际使用变量 shift op 或任何分支。
我正在研究的特定 PowerPC 处理器有一个怪癖,即按常量立即移动,例如
int ShiftByConstant( int x ) { return x << 3 ; }
是快速的、单操作的和超标量的,而按变量移动,比如
int ShiftByVar( int x, int y ) { return x << y ; }
我想做的是找出哪个非微编码整数 PPC ops sraw解码成然后单独发出。这对 sraw
的延迟没有帮助本身——它将用六个操作替换一个操作——但在这六个操作之间,我可以将一些工作双重分派(dispatch)给其他执行单元并获得净 yield 。
我似乎无法在任何地方找到 μops sraw 解码成的内容 — 有谁知道我如何用一系列常量移位和基本整数运算替换可变位移位? (for 循环或开关或任何带有分支的东西都不会工作,因为分支惩罚甚至比微码惩罚更大,即使对于正确预测的分支也是如此。)
这不需要在汇编中回答;我希望学习算法而不是特定的代码,因此用 C 或高级语言甚至伪代码的答案将非常有帮助。
编辑:我应该添加的一些说明:
PPC 有条件移动,所以我们可以假设存在无分支内函数
int isel(a, b, c) { return a >= 0 ? b : c; }
(如果你写出一个做同样事情的三元组,我会明白你的意思)
sraw
还要慢。 :-(最佳答案
给你...
我决定也尝试一下,因为 Mike Acton 声称这比在他的 CellPerformance 网站上使用 CELL/PS3 微编码转换更快,其中 he suggests to avoid the indirect shift .然而,在我所有的测试中,使用微编码版本不仅比间接移位的完整通用无分支替代更快,而且代码占用的内存更少(1 条指令)。
我将这些作为模板来做的唯一原因是为有符号(通常是算术)和无符号(逻辑)移位获得正确的输出。
template <typename T> FORCEINLINE T VariableShiftLeft(T nVal, int nShift)
{ // 31-bit shift capability (Rolls over at 32-bits)
const int bMask1=-(1&nShift);
const int bMask2=-(1&(nShift>>1));
const int bMask3=-(1&(nShift>>2));
const int bMask4=-(1&(nShift>>3));
const int bMask5=-(1&(nShift>>4));
nVal=(nVal&bMask1) + nVal; //nVal=((nVal<<1)&bMask1) | (nVal&(~bMask1));
nVal=((nVal<<(1<<1))&bMask2) | (nVal&(~bMask2));
nVal=((nVal<<(1<<2))&bMask3) | (nVal&(~bMask3));
nVal=((nVal<<(1<<3))&bMask4) | (nVal&(~bMask4));
nVal=((nVal<<(1<<4))&bMask5) | (nVal&(~bMask5));
return(nVal);
}
template <typename T> FORCEINLINE T VariableShiftRight(T nVal, int nShift)
{ // 31-bit shift capability (Rolls over at 32-bits)
const int bMask1=-(1&nShift);
const int bMask2=-(1&(nShift>>1));
const int bMask3=-(1&(nShift>>2));
const int bMask4=-(1&(nShift>>3));
const int bMask5=-(1&(nShift>>4));
nVal=((nVal>>1)&bMask1) | (nVal&(~bMask1));
nVal=((nVal>>(1<<1))&bMask2) | (nVal&(~bMask2));
nVal=((nVal>>(1<<2))&bMask3) | (nVal&(~bMask3));
nVal=((nVal>>(1<<3))&bMask4) | (nVal&(~bMask4));
nVal=((nVal>>(1<<4))&bMask5) | (nVal&(~bMask5));
return(nVal);
}
编辑: 关于 isel() 的注释我看到你的 isel() code on your website .
// if a >= 0, return x, else y
int isel( int a, int x, int y )
{
int mask = a >> 31; // arithmetic shift right, splat out the sign bit
// mask is 0xFFFFFFFF if (a < 0) and 0x00 otherwise.
return x + ((y - x) & mask);
};
FWIW,如果你重写你的 isel() 来做一个掩码和掩码补码,它在你的 PowerPC 目标上会更快,因为编译器足够聪明,可以生成一个 'andc' 操作码。它是相同数量的操作码,但操作码中结果到输入寄存器的依赖性少了一个。这两个掩码操作也可以在超标量处理器上并行发出。如果一切都正确排列,它可以快 2-3 个周期。对于 PowerPC 版本,您只需要将返回更改为此:
return (x & (~mask)) + (y & mask);
关于c - 仅使用常量移位模拟可变位移位?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/539836/
我想将这个无符号数:1479636484000 向右移动 7 位。这在 JavaScript 中可能吗? 两者 1479636484000 >> 7 和 1479636484000 >>> 7 返回错
鉴于以下代码: import matplotlib.pyplot as plt import numpy as np x = [1.0, 1.1, 2.0, 5.7] y = np.arange(le
我有一个低级键盘钩子(Hook),目前允许我从任何应用程序(包括游戏)中控制媒体播放器。 它通过查看捕获的特定击键来工作。 我想扩展它以查找键的组合。我可以对一些逻辑进行硬编码,但我觉得必须有一种更合
我需要一些帮助来理解这段C代码。我不知道这里的“L”和“\”是什么?请也说明一点:) #define l2n(l,c) (*((c)++)=(unsigned char)(((l)>>2
我正在查看一段代码: int result = 0 ; char byte = foo[j] for (i = 7 ; i>0 ; i--) { byte = (byte & ~0x1)>>1
我们有一个项目要求我们编写一个程序,允许用户输入一系列数字“将数字读入数组以进行进一步处理,用户通过输入负数表示他们已完成(负数不用于计算),在读取所有数字后执行以下操作,总结输入的#,计算输入的#,
锁定。有disputes about this question’s content正在解决中。它目前不接受新的答案或互动。 def menu(): choice = input("Pres
为什么如果 int x = -1 // binary: 11111111111111111111111111111111 x = x >>> 31; 我们有 000000000000000000000
我的问题其实应该很简单:我有一个玩家对象数组。(玩家[])我想要一个函数来旋转这个数组直到一个索引: public void rotateArray(Object[] array, int index
我有一个编码为 boost 动态位集的数字列表。我根据此列表中的任何数字可以采用的最大值动态选择此位集的大小。所以假设我有从 0 到 7 的数字,我只需要三位,我的字符串 0,2,7 将被编码为000
我能想到一些令人讨厌的低效方法来完成这项任务,但我想知道最好的方法是什么。 例如,我想复制一个字节中从第 3 位开始的 10 个字节,并像往常一样复制到一个指针。 有没有比一次复制一个移位字节更好的方
我正在尝试为该问题添加更多规则,并且该规则一直给我带来这种转变/减少冲突的能力,我不知道为什么会这样做,并且在过去的24小时内我一直在尝试解决问题 FuncDecl : RetTyp
This question already has answers here: Why does it make a difference if left and right shift are us
我在 Perl 中遇到这个问题已经有几天了,在搜索了无数的手册页、perldocs 和谷歌搜索了太多的搜索词之后,希望这里有人能帮助我。 我得到两个表示十六进制值的字符串,即“FFFF”,而不是 Pe
我有一个主 div,两个 div 水平并排放置在这个父 div 中。 .parent{ height: 360px; margin-top: 0px; bo
我想 float 我的元素列表并从第二个元素创建一个移动效果。 如何避免第二个 .item 之后的“清除”行为? .shift { float: right; width: 50%;
我正在使用 SSE3 优化我的代码。代码中有一点迫使我将 vector 中的所有元素移动一个元素 v[0] = 0 //v is some char* and N = v.size() for(i
.file "calcnew.c" .text .globl calcnew .type calcnew, @function calcnew:
我有一个点对象: class Point { final int x,y; ... } 因为这些点将在我的代码中到处使用/创建,所以我想开始使用 guavas 缓存。不幸的是
x = "Foo 890 bar *()" 如何将包括 "*()" 在内的小写字母“未移位”返回到 890?期望的结果: foo 890 bar 890 不需要的: x.lower() => "foo
我是一名优秀的程序员,十分优秀!