I'm digging into left and right shift operations in ASM.

From IA-32 Intel Architecture Software Developer’s Manual 3

All IA-32 processors (starting with the Intel 286 processor) do mask the shift count to 5 bits, resulting in a maximum count of 31. This masking is done in all operating modes (including the virtual-8086 mode) to reduce the maximum execution time of the instructions.

I'm trying to understand the reasoning behind this logic. Maybe it works as it works because on a hardware level it is hard to implement shift for all 32 (or 64) bits in a register using 1 cycle?

Any detailed explanation would help a lot!

  • \$\begingroup\$ Why would you want to shift all 32 bits? \$\endgroup\$
    – Andy aka
    May 12 '20 at 7:37
  • \$\begingroup\$ @Andyaka the question is not "why I want to do so". The question is "why does it work this way?". It is just seems weird, since the SSE shift instructions (PSLL* etc.) do not mask the shift count. \$\endgroup\$
    – No Name QA
    May 12 '20 at 7:44
  • \$\begingroup\$ Why would anyone want to shift all 32 bits then? \$\endgroup\$
    – Andy aka
    May 12 '20 at 7:57
  • 1
    \$\begingroup\$ @Andyaka because it leads us to an inconsistency in shifting behavior. Please, if you know the answer tell me. If not then stop trolling. \$\endgroup\$
    – No Name QA
    May 12 '20 at 11:16
  • \$\begingroup\$ Part of the reason is, C has banned shifting beyond word length so there is no need for other behaviors. Also shifting beyond word length would probably return 0 and can easily be handled as a conditional. \$\endgroup\$ May 12 '20 at 14:27

As said in the 286 programming reference, they mask the count to limit shift and rotate instruction execution time. These did not have a barrel shifter. Basically the CPU would sit in a loop that shifts data and decrements CL until CL is zero. Earlier CPUs such as 8086 could accept 255 in CL so it would take just needlessly long to execute. And limiting to 5 bits is enough, as that allows shifting of 16-bit registers via carry.

  • \$\begingroup\$ Thank you! In your last sentence that allows shifting of 16-bit registers via carry you specify 16-bit registers. So in an old good times we could do x << 16 = 0, right? If so, why did they implement x<<32 = x? \$\endgroup\$
    – No Name QA
    May 12 '20 at 9:29
  • \$\begingroup\$ Because you have 16 bit registers, you must be able to shift 16 bit positions at minimum to be compatible, for example shifting any bit to carry bit. So you need 5 bits to indicate how many positions you want to shift, and this limits the positions to shift between 0 and 31 positions. \$\endgroup\$
    – Justme
    May 12 '20 at 11:59
  • \$\begingroup\$ Thank you for clarification. I'm sorry, but I'm not a native english speaker and it is very hard for me to translate your first sentence Because you have 16 bit registers, you must be able to shift 16 bit positions at minimum to be compatible, for example shifting any bit to carry bit. Could you please rewrite it in a more simpler or detailed manner? \$\endgroup\$
    – No Name QA
    May 12 '20 at 16:42
  • \$\begingroup\$ When the limit to mask shifting was made in 80186/80188 and 80286, it did break compatibility with old code 8086/8088 code, but in real world code, maximum shift or rotate value ever needed was 16, or 17 tops, and for that, 5 bits is needed which allows shifting or rotating up to count of 31. No real world code would ever need to rotate or shift more than that 17 bits, and if some 8086/8088 code really used shifts or rotates with more than 31 counts, the code needed to be rewritten to run on any later CPU. \$\endgroup\$
    – Justme
    May 12 '20 at 19:29
  • \$\begingroup\$ thank you for your amazing explanation! \$\endgroup\$
    – No Name QA
    May 13 '20 at 8:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.