VOGONS


First post, by superfury

User metadata
Rank l33t++
Rank
l33t++

Thinking about it, it sounds fine. But when it reaches -1 and shifts that(counter is still left to shift), it gets stuck at -1 instead of becoming 0? -1 SAR 1 = -1 instead of SAR -1,1=0? It's shifted, clearing the MSb(becoming +127 when used on a 8-bit value). Then the MSb is set because the value before shifting had it set, thus becoming -1 again?

So, an example on gcc 4.4 on stackoverflow:

00000000 <arithmetic0>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 8b 45 08 mov 0x8(%ebp),%eax
6: 5d pop %ebp
7: 89 c2 mov %eax,%edx
9: c1 ea 1f shr $0x1f,%edx
c: 8d 04 02 lea (%edx,%eax,1),%eax
f: d1 f8 sar %eax
11: c3

Thus, executing it yields:

00000000 <arithmetic0>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 8b 45 08 mov 0x8(%ebp),%eax ;eax=ffffffff
6: 5d pop %ebp
7: 89 c2 mov %eax,%edx ;eax=edx=ffffffff
9: c1 ea 1f shr $0x1f,%edx ;edx=7fffffff, cf set
c: 8d 04 02 lea (%edx,%eax,1),%eax ;eax=7ffffffe
f: d1 f8 sar %eax ;eax=3fffffff? should be 0?
11: c3

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 1 of 4, by cyclone3d

User metadata
Rank l33t++
Rank
l33t++

What happens if you use the same code in Visual Studio?

If you are right, I would say that there is a bug in the GCC compiler.. and it has probably been there for a super long time.

Back in the day, I had issues with some C/C++ code throwing some weird errors when compiled with GCC but it worked fine when compiled through Visual Studio.

I never looked into what was causing the issue with GCC and just kept using Visual Studio instead.

Yamaha modified setupds and drivers
Yamaha XG repository
YMF7x4 Guide
Aopen AW744L II SB-LINK

Reply 3 of 4, by peterferrie

User metadata
Rank Oldbie
Rank
Oldbie

SAR of -1 does not clear the MSB. It copies the sign bit into the next bit, and retains the sign bit.
Also, your comments don't match your code.
SHR EDX, 1F = 1, not 7FFFFFFFF.
and
LEA EAX, [EDX+EAX-1] isn't encoded as 8D 04 02, it's 8D 44 02 FF.

Reply 4 of 4, by superfury

User metadata
Rank l33t++
Rank
l33t++

Looking at it again, you're right(1f, so bit 31=result, not bit shifted right by 1, miscounted there(did that one off the top of my head, thus miscounted 32 instead of 31)), cf=1. Then EDX(1)+EAX(ffffffff)+1=1. Then SAR 1 results in 0(and CF=1), thus correct result?

So it's correct, but it requires that extra logic, a simple sar isn't enough(as can be seen(sar -1=>-1 carry 1).

@realnc: That code isn't generated using a signed shift. That code was generated by a simple

int arithmetic0(x) {return x/2;}

It just looked strange, but it actually isn't.

And it does require extra logic with sar for the extra -1/2=0 result(everything before said opcode, so the val=(val+(val shr 1f)+1)) for the correct divide result.

Edit: It might still go wrong that way if done with bigger powers of 2(SAL still shifts more, thus a repeating cause for troubles).
Edit: Looks like a different algorithm with divide by 4 indeed:

00000050 <arithmetic4>:
50: 55 push %ebp
51: 89 e5 mov %esp,%ebp
53: 8b 55 08 mov 0x8(%ebp),%edx
56: 5d pop %ebp
; divide by four:
57: 89 d0 mov %edx,%eax
59: c1 f8 1f sar $0x1f,%eax
5c: c1 e8 1e shr $0x1e,%eax
5f: 01 d0 add %edx,%eax
61: c1 f8 02 sar $0x2,%eax
; result ready
64: c3 ret

Looks like a different algorithm there ((((x sar 1f) shr 1e)+x) sar 2).

So... sar 1f results in -1(negative numbers) or 0(positive numbers). Then, shr 1e results in 3(for negative) or 0(for positive). So it's shifting x by 2 bits for positive or x+3 by 2 bits for negative?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io