[llvm-dev] [X86] How do I set just the low byte of an x86_64 register?

Mat Hostetter via llvm-dev llvm-dev at lists.llvm.org
Thu Feb 11 05:29:41 PST 2021


I work on a compiler that uses LLVM for its back end. I'm interested in setting just the low byte of a register, leaving the other bits alone, for some GC tag bit shenanigans, e.g.:

long replace_low_byte_with_37(long* a) {
  return (*a & ~0xFFL) | 37;
}

x86_64 has a movb instruction that does exactly this, but I can't get clang (or any other compiler), to use movb for this purpose, even at -Os.

Here is the -Os -march=sandybridge compiler output for gcc-10.2, icc-21.1.9, and clang-11.0.1 (all different!), as well as how a simple movb assembles:

0000000000000000 <gcc>:
   0:   48 8b 07                mov    (%rdi),%rax
   3:   30 c0                   xor    %al,%al
   5:   48 83 c8 25             or     $0x25,%rax
   9:   c3                      retq
000000000000000a <icc>:
   a:   48 8b 07                mov    (%rdi),%rax
   d:   48 25 00 ff ff ff       and    $0xffffffffffffff00,%rax
  13:   48 83 c0 25             add    $0x25,%rax
  17:   c3                      retq
0000000000000018 <clang>:
  18:   48 c7 c0 00 ff ff ff    mov    $0xffffffffffffff00,%rax
  1f:   48 23 07                and    (%rdi),%rax
  22:   48 83 c8 25             or     $0x25,%rax
  26:   c3                      retq
0000000000000027 <simple_movb_by_hand>:
  27:   48 8b 07                mov    (%rdi),%rax
  2a:   b0 25                   mov    $0x25,%al
  2c:   c3                      retq

As you can see, movb would be smallest (and llvm's is the biggest). Size is important for my use case.

So why don't these compilers generate movb? Perhaps the concern is partial register stalls and how %rax and %al interact with the register renamer. As I understand the background<https://stackoverflow.com/questions/45660139/how-exactly-do-partial-registers-on-haswell-skylake-perform-writing-al-seems-to> from Peter Cordes referenced by #34707<https://bugs.llvm.org/show_bug.cgi?id=34707>, the punchline is that since Sandy Bridge, and especially Skylake, the partial register stall is no big deal for an actual RMW operation like this.

But even on CPUs where there is a stall that's worse than the added instructions from not using movb, -Os should still prefer movb.

I'm not advocating using this for %ah (etc.), which is famously incorrect<http://gallium.inria.fr/blog/intel-skylake-bug/> in some Skylake and Kaby Lake CPUs without a microcode patch.

Is there a way to get LLVM to generate movb to set just the low byte?

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20210211/71bdd072/attachment.html>


More information about the llvm-dev mailing list