So I know when you do x mod 2^n for unsigned operations, the compiler will simply convert that operation into x & (2^n - 1).
But when I look at the compiler implementation using signed numbers, e.g.
int signed_rem8(int x) { return x %8; }
I get something like this (https://godbolt.org/z/xY3Ef6WEc):
movl -4(%rbp), %eax
cltd
shrl $29, %edx
addl %edx, %eax
andl $7, %eax
subl %edx, %eax
What is the logic behind this?