Should I use “mul” or “imul” when multiplying a signed number to an unsigned number?

爷,独闯天下 提交于 2021-01-01 04:19:30

问题


I have found out that both mul and imul can be used to multiply a signed number to an unsigned number.

For example:

global _start

section .data
    byteVariable DB -5

section .text
_start:

mov al, 2
imul BYTE [byteVariable]

You can replace imul with mul, and the result would still be the same (-10).

Are mul and imul exactly the same when multiplying a signed number to an unsigned number, or is there a difference between them?


回答1:


The upper half is different, as mentioned in the comments. If you don't care about the upper half, you can use either mul or imul, in all of their forms (the one-operand forms produce the upper half, but in this scenario you would ignore it).

If you do care about the upper half, neither mul nor imul works by itself, since they just multiply unsigned*unsigned and signed*signed, but you can fix it fairly easily.

Consider that a signed byte has the bit-weights -128, 64, 32, 16, 8, 4, 2, 1 while an unsigned byte has the bit-weights +​128, 64, 32, 16, 8, 4, 2, 1. So you can represent the unsigned value of x in signed format (I know this is confusing but it's the best I can do) as x + 256 x_7 (where x_7 is bit 7 of x). The easiest way to see is probably to split it: x + 2 * 128 * x_7. What's happening here is compensating for the -128 weight, first removing it by adding the value of bit 7 128 times and then going all the way up to the +128 weight by doing it again, of course this can be done in one step.

Anyway, multiplying that by some signed number y and working it out gives 256 x_7 y + xy, where xy is the (double-width) result of imul and 256 x_7 y means "add y to the upper half if the sign of x is set", so a possible implementation is (not tested)

; al has some unsigned value
mov dl, al
sar dl, 7
and dl, [signedByte]
imul BYTE [signedByte]
add ah, dl

Naturally you could sign-extend one operand, zero-extend the other, and use a 16 bit multiplication (any, since the upper half is not relevant this way).




回答2:


Another behavior of flags. For MUL: OF=CF=1 when carry bit changes upper half; For IMUL: OF=CF=1 when carry bit changes sign bit in low part (or just sign bit in result for 2 or 3 operands form)




回答3:


x86 does have an instruction that multiplies signed bytes by unsigned bytes: SSSE3 pmaddubsw.

You can think of it as sign-extending one operand to 16 bits, zero-extending the other to 16 bits, then doing an NxN -> N-bit multiply. (For each SIMD element).

It also horizontally adds pairs of word products from adjacent bytes, but if you unpack the inputs with zeros (punpcklbw or pmovzxbw) then you can get each product separately.

Of course if you have SSE4.1 then you could just pmovsxbw one input and pmovzxbw the other input to feed a regular 16-bit pmullw, if you don't want pairs added.


But if you just want one scalar result, movsx / movzx to feed a regular non-widening imul reg, reg is your best bet.

As Harold points out, mul r/m and imul r/m widening multiplies treat both their inputs the same way so neither can work (unless the signed input is known to be non-negative, or the unsigned input is known to not have its high bit set, so you can treat them both the same after all.)

mul and imul also set FLAGS differently: CF=OF= whether or not the full result fits in the low half. (i.e. the full result is the zero-extension or sign-extension of the low half). For imul reg,r/m or imul reg, r/m, imm, the "low half" is the destination reg; the high half isn't written anywhere.



来源:https://stackoverflow.com/questions/45495711/should-i-use-mul-or-imul-when-multiplying-a-signed-number-to-an-unsigned-num

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!