[Valgrind-developers] [PATCH 1/2] x86: optimize XCHG to MOV for same-register forms

Maciej W. Rozycki macro@orcam.me.uk
Tue Aug 18 00:55:24 GMT 2026


On Mon, 27 Jul 2026, Jan Beulich wrote:

> >  Sure, it is a peculiarity of the x86 instruction set known to me since 
> > forever, and it has always been the case that x86 assemblers choose the 
> > shortest encoding for the requested operation (there's some redundancy for 
> > address expressions with the addition of the SIB encodings too), although 
> > for corner cases there's no way I know of to express the requirement to 
> > use a particular machine instruction, e.g.
> > 
> > 	rcll	$1, %eax
> > 
> > either modifies or preserves OF depending on the opcode used,
> 
> Are you sure about this? Both an old i486 paper manual and the current SDM
> refer to COUNT (nowadays COUNT & COUNTMASK) being 1. There's no tying to a
> particular encoding afaics.

 I used to, but you made me less convinced.  Indeed the wording is as it 
is:

"The OF flag is defined only for the 1-bit rotates; it is undefined in all 
other cases (except that a zero-bit rotate does nothing, that is affects 
no flags)."

which I find ambiguous, however the "Operation" specification seems clear 
and while Intel documentation does not always exactly match reality, I 
highly doubt it is the case here.

 I guess one of these is true, in the dropping order of likelihood:

1. I misremembered.

2. My non-Intel source got it wrong back in 1990s.

3. Something's changed at one point, possibly at the introduction of the 
   barrel shifter to the architecture.

> > and one may 
> > need either semantics depending on the circumstances, but no assembler I 
> > know of gives the programmer choice here.
> 
> I think I did fix this at some point, by making
> 
> 	rcl	$one, %eax
> 	.equ one, 1
> 
> work. Or maybe I'm misremembering and it has always worked.

 Indeed it does work, thanks.  I guess x86 GAS doesn't do relaxation here.  
Still a hack anyway, in a proper world you'd have separate RCLI and RCL1 
instruction mnemonics or suchlike for the two cases.

 So I've allocated some time and made an experiment with the oldest piece 
of x86 hardware I have, which is not impressively old TBH as it even still 
ran Linux as of 7.0.0, a late 486 DX/2 stepping 5 which even has CPUID and 
VME extensions (no 4MiB pages though; these landed with stepping 6 only).  
So it's likely not representative really for the matter in question.

 Anyway, I've stepped through the inline asm of the piece of code below:

#include <stdint.h>

int
main (void)
{
  register uint8_t a asm ("al") = 1;
  register uint8_t c asm ("cl") = 1;
  uint8_t x = 0xa5;
  uint8_t y = 0xd2;

  asm volatile (
	"addb	$0, %[a]\n\t"
	"rorb	$1, %[x]\n\t"
	"addb	$0, %[a]\n\t"
	"rorb	$1, %[y]\n\t"
	"addb	$0, %[a]\n\t"
	"rorb	$7, %[x]\n\t"
	"addb	$0, %[a]\n\t"
	"rorb	$7, %[y]\n\t"
	"addb	$0, %[a]\n\t"
	"rorb	%[c], %[x]\n\t"
	"addb	$0, %[a]\n\t"
	"rorb	%[c], %[y]\n\t"
	"movb	$7, %[c]\n\t"
	"addb	$0, %[a]\n\t"
	"rorb	%[c], %[x]\n\t"
	"addb	$0, %[a]\n\t"
	"rorb	%[c], %[y]\n\t"
	"addb	$0, %[a]\n\t"
	"rorb	$one, %[x]\n\t"
	"addb	$0, %[a]\n\t"
	"rorb	$one, %[y]\n\t"
	"addb	$0, %[a]\n\t"
	".eqv	one, 1\n"
	: [x] "+qQ" (x), [y] "+qQ" (y), [c] "+q" (c)
	: [a] "q" (a)
	: "flags");

  return 0;
}

under GDB and each and every ROR instruction did set OF according to the 
result of the operation, even for the cases undefined in the architecture.  
I think one would have to go back perhaps to the original 80186 or 80286 
really to see any difference here.

 I may yet try to chase my old hardcopy documentation, but I don't have it 
handy, so it may not happen soon.

 FWIW,

  Maciej


More information about the Binutils mailing list