简体   繁体   English

ALU 设计 - 左移是否会导致有符号数溢出?

[英]ALU Design - Should a left shift cause overflow for signed numbers?

My understanding is an overflow can happen when all of the following conditions are met:我的理解是当满足以下所有条件时可能会发生溢出:

  1. Performing addition or subtraction.执行加法或减法。
  2. Both numbers should have the same sign.两个数字应该有相同的符号。
  3. The result should have the opposite sign.结果应该有相反的符号。

Ex: for 4-bit numbers 4 10 + 5 10 = 0100 2 + 0101 2 = 1001 2 = (-7) 10例如:对于 4 位数字 4 10 + 5 10 = 0100 2 + 0101 2 = 1001 2 = (-7) 10

But what about a left shift operator on a signed number?但是有符号数字上的左移运算符呢? Should that be considered an overflow as well?这也应该被视为溢出吗?

Ex: 5 10 << 1 = 0101 2 << 1 = 1010 2 = (-6) 10例如:5 10 << 1 = 0101 2 << 1 = 1010 2 = (-6) 10

Or does it make sense to ignore the overflow for shifting left?或者忽略左移的溢出有意义吗?

  1 #include <stdio.h>
  2 
  3 int a = 0x01;
  4 
  5 int main(int argc,char *argv[])
  6 {
  7     for(int i = 0 ; i < 32 ; i++){
  8         printf("%p : %d \n", a, a);
  9         a<<=1;
 10     }
 11     return 0;
 12 }                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             

Of course.当然。 Left shift operator also occur overflow左移运算符也会发生溢出
below is result.下面是结果。

0x1 : 1 
0x2 : 2 
0x4 : 4 
0x8 : 8 
0x10 : 16 
0x20 : 32 
0x40 : 64 
0x80 : 128 
0x100 : 256 
0x200 : 512 
0x400 : 1024 
0x800 : 2048 
0x1000 : 4096 
0x2000 : 8192 
0x4000 : 16384 
0x8000 : 32768 
0x10000 : 65536 
0x20000 : 131072 
0x40000 : 262144 
0x80000 : 524288 
0x100000 : 1048576 
0x200000 : 2097152 
0x400000 : 4194304 
0x800000 : 8388608 
0x1000000 : 16777216 
0x2000000 : 33554432 
0x4000000 : 67108864 
0x8000000 : 134217728 
0x10000000 : 268435456 
0x20000000 : 536870912 
0x40000000 : 1073741824 
0x80000000 : -2147483648 


It makes sense to indicate when left-shift has overflow, at least for 1-bit shifts.指示左移何时溢出是有意义的,至少对于 1 位移位。 You might as well produce some output for n-bit shifts, too.您也可以为 n 位移位生成一些输出。 (Although ARM apparently chooses to always produce overflow=0, so that's a valid choice. Most software written in high-level languages never looks at signed-overflow flags except as part of a signed less or greater compare condition.) (虽然 ARM 显然选择总是产生溢出 = 0,所以这是一个有效的选择。大多数用高级语言编写的软件从不查看有符号溢出标志,除非作为有符号的较小或较大比较条件的一部分。)

For shift count != 1, or variable (which are logically equivalent to repeated x *= 2 ), you can overflow along the way and then get back to the same sign as the input.对于移位计数 != 1 或变量(逻辑上等同于重复的x *= 2 ),您可以沿途溢出,然后返回与输入相同的符号。 You might as well still produce an overflow signal according to input_sign ^ output_sign , because you can do that cheaply even with a barrel shifter ALU.您最好仍然根据input_sign ^ output_sign产生溢出信号,因为即使使用桶形移位器 ALU 也可以廉价地做到这一点。 Maybe some users will be interested in that output even though overflow=0 wouldn't mean no overflow.也许有些用户会对该输出感兴趣,即使 overflow=0 并不意味着没有溢出。

(Detecting if any of the bits shifted out were different from the final high bit is probably more expensive for a barrel shifter, although probably still cheap to accumulate for an iterative shifter. But if you're designing an ISA for an implementation that currently uses an iterative shifter, keep in mind you're imposing extra cost on a possible future implementation that wants an O(1) barrel shifter if it still has to match the behaviour of your overflow signal.) (检测移出的任何位是否与最终高位不同对于桶形移位器来说可能更昂贵,尽管对于迭代移位器来说累积起来可能仍然便宜。但是如果您正在为当前使用的实现设计 ISA一个迭代移位器,请记住,如果它仍然必须与溢出信号的行为相匹配,那么您正在对未来可能需要 O(1) 桶形移位器的可能实现施加额外成本。)


You don't need separate shift instructions for signed vs. unsigned left shift.对于有符号和无符号左移,您不需要单独的移位指令。 If your ISA has flags / condition-code output from the ALU accessible to later instructions, then yes you can have the left-shift instruction affect the signed-overflow flag (in some way).如果您的 ISA 有来自 ALU 的标志/条件代码输出,以后的指令可以访问,那么是的,您可以让左移指令影响有符号溢出标志(以某种方式)。 Code that's shifting unsigned numbers can ignore that flag output.移动无符号数字的代码可以忽略该标志输出。

All of this is of course assuming you use 2's complement signed integers, not for example sign/magnitude.当然,所有这些都是假设您使用 2 的补码有符号整数,而不是例如符号/大小。 Then you might need separate instructions, since sign/mag shifts would leave the sign bit in place and just shift the low n-1 bits.然后您可能需要单独的指令,因为符号/磁力移位会将符号位留在原位并只移动低 n-1 位。

The only reason you might not want to signal overflow is if your CPU traps by default in that case (like MIPS add ), meaning that you would need separate instructions for non-trapping left shift (like MIPS addu for addition; MIPS only has logical left-shift).您可能不想发出溢出信号的唯一原因是,如果您的 CPU 在这种情况下默认捕获(例如 MIPS add ),这意味着您需要单独的指令进行非捕获左移(例如 MIPS addu用于加法;MIPS 只有逻辑左移)。 Note that MIPS doesn't have a FLAGS register or any equivalent;请注意,MIPS 没有 FLAGS 寄存器或任何等效项; if you want the carry output of an add, you need addu / sltu to compare-into-register producing a 0 or 1 result for sum = a+b;如果你想一个附加的进位输出,则需要addu / sltu比较-进入-寄存器产生0或1的结果为sum = a+b; carry = sum < a;

(Semi-related: GNU Cdefines the behaviour of left shifts that have signed overflow, ISO C doesn't . Of course, there's no reason to build a CPU that defines as little about arithmetic as ISO C does! That would be horrible.) (半相关:GNU C定义了有符号溢出的左移行为ISO C 没有。当然,没有理由构建一个像 ISO C 那样定义的算术很少的 CPU!那太可怕了。 )


Existing ISAs现有的 ISA

ARM and AArch64 apparently don't ever set the oVerflow flag for left shifts. ARM 和 AArch64显然从未为左移设置 oVerflow 标志。

x86 does set OF according to what happens when left shifting: x86确实根据左移时发生的情况设置 OF:

https://www.felixcloutier.com/x86/sal:sar:shl:shr#flags-affected https://www.felixcloutier.com/x86/sal:sar:shl:shr#flags-affected

The CF flag contains the value of the last bit shifted out of the destination operand; CF 标志包含移出目标操作数的最后一位的值; it is undefined for SHL and SHR instructions where the count is greater than or equal to the size (in bits) of the destination operand.对于计数大于或等于目标操作数的大小(以位为单位)的 SHL 和 SHR 指令,它是未定义的。 The OF flag is affected only for 1-bit shifts (see “Description” above); OF 标志仅在 1 位移位时受到影响(参见上面的“说明”); otherwise, it is undefined.否则,它是未定义的。 The SF, ZF, and PF flags are set according to the result.根据结果​​设置 SF、ZF 和 PF 标志。 If the count is 0, the flags are not affected.如果计数为 0,则标志不受影响。 For a non-zero count, the AF flag is undefined.对于非零计数,AF 标志未定义。

But x86 is weird.但是 x86 很奇怪。 Modern x86 CPUs always write OF, even for shifts with larger counts, because it would be inconvenient to preserve the old value.现代 x86 CPU 总是写入 OF,即使对于计数较大的班次也是如此,因为保留旧值会很不方便。 (Then the old FLAGS would be an input / dependency for out-of-order exec.) (那么旧的 FLAGS 将是乱序 exec 的输入/依赖项。)

I haven't looked at what value they choose to write, perhaps just XOR of the original sign and the new sign.我没有看他们选择写什么值,也许只是原始符号和新符号的异或。 (So they'd miss overflows that happened along the way as bits got shifted out.) (因此,当位移出时,他们会错过沿途发生的溢出。)

x86 has separate mnemonics for shl (logical left) and sal (arithmetic left), but they both assemble to the same opcode. x86 对shl (逻辑左)和sal (算术左)有不同的助记符,但它们都组装成相同的操作码。 Ie they're source-level synonyms.即它们是源级同义词。 x86 machine code only has one kind of left shift. x86 机器码只有一种左移。 (Or two if you count rotates, and of course there are different opcodes for 8-bit operand-size or immediate vs. variable vs. implicit-1 count...) (或者两个,如果你计算旋转,当然 8 位操作数大小或立即数与变量与隐式 1 计数有不同的操作码......)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM