llvm/llvm-project

[DAG][X86] Use shrdq to insert into a bitfield

Open

#112,488 建立於 2024年10月16日

在 GitHub 查看
 (15 留言) (0 反應) (1 負責人)C++ (10,782 fork)batch import
backend:X86good first issuemissed-optimization

倉庫指標

Star
 (26,378 star)
PR 合併指標
 (平均合併 1天 2小時) (30 天內合併 1,000 個 PR)

描述

Consider inserting a value into a "manually managed" bit field (that is, without using : 10 in a struct):

uint64_t updateTop10Bits(uint64_t A, uint64_t B) {
  uint64_t Mask = (1ULL << 54) - 1;
  return (A & Mask) | (B << 54);
}

This takes the lower 10 bits from B and inserts into the top 10 bits of A.

clang -O3 -march=skylake generates:

        movb    $54, %al
        bzhiq   %rax, %rdi, %rax
        shlq    $54, %rsi
        orq     %rsi, %rax
        retq

We could left-shift the destination to remove the 10 bits and then perform a double-precision right-shift like so:

        movq    %rdi, %rax       ; Copy A into RAX.
        shlq    $10, %rax        ; Shift RAX left by 10 bits.
        shrdq   $10, %rsi, %rax  ; Shift RAX right by 10 bits while taking 10 bits from B.
        retq

The LLVM IR for the C++ code snippet above is:

define dso_local noundef i64 @updateTop10Bits(unsigned long, unsigned long)(i64 noundef %A, i64 noundef %B) local_unnamed_addr {
entry:
  %and = and i64 %A, 18014398509481983
  %shl = shl i64 %B, 54
  %or = or disjoint i64 %shl, %and
  ret i64 %or
}

https://godbolt.org/z/fdcWqMnvW

貢獻者指南