[llvm] [IR] Implementation and lowering of bitinsert and bitextract (PR #200605)

Alexis Engelke via llvm-commits llvm-commits at lists.llvm.org
Sun Aug 16 07:13:02 PDT 2026


================
@@ -0,0 +1,566 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=x86_64-unknown-linux-gnu < %s | FileCheck %s
+
+define half @test_bitextract_half_full(b16 %src) {
+; CHECK-LABEL: test_bitextract_half_full:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pinsrw $0, %edi, %xmm0
+; CHECK-NEXT:    retq
+  %result = bitextract half, b16 %src, i32 0
+  ret half %result
+}
+
+define half @test_bitextract_half_const(b32 %src) {
+; CHECK-LABEL: test_bitextract_half_const:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    shrl $8, %edi
+; CHECK-NEXT:    pinsrw $0, %edi, %xmm0
+; CHECK-NEXT:    retq
+  %result = bitextract half, b32 %src, i32 8
+  ret half %result
+}
+
+define half @test_bitextract_half_var(b32 %src, i32 %off) {
+; CHECK-LABEL: test_bitextract_half_var:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movl %esi, %ecx
+; CHECK-NEXT:    # kill: def $cl killed $cl killed $ecx
+; CHECK-NEXT:    shrl %cl, %edi
+; CHECK-NEXT:    pinsrw $0, %edi, %xmm0
+; CHECK-NEXT:    retq
+  %result = bitextract half, b32 %src, i32 %off
+  ret half %result
+}
+
+define float @test_bitextract_float_full(b32 %src) {
+; CHECK-LABEL: test_bitextract_float_full:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movd %edi, %xmm0
+; CHECK-NEXT:    retq
+  %result = bitextract float, b32 %src, i32 0
+  ret float %result
+}
+
+define float @test_bitextract_float_const(b64 %src) {
+; CHECK-LABEL: test_bitextract_float_const:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    shrq $32, %rdi
+; CHECK-NEXT:    movd %edi, %xmm0
+; CHECK-NEXT:    retq
+  %result = bitextract float, b64 %src, i32 32
+  ret float %result
+}
+
+define float @test_bitextract_float_var(b64 %src, i32 %off) {
+; CHECK-LABEL: test_bitextract_float_var:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movl %esi, %ecx
+; CHECK-NEXT:    # kill: def $cl killed $cl killed $ecx
+; CHECK-NEXT:    shrq %cl, %rdi
+; CHECK-NEXT:    movd %edi, %xmm0
+; CHECK-NEXT:    retq
+  %result = bitextract float, b64 %src, i32 %off
+  ret float %result
+}
+
+define float @test_bitextract_float_b87_var(b87 %src, i32 %off) {
+; CHECK-LABEL: test_bitextract_float_b87_var:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movl %edx, %ecx
+; CHECK-NEXT:    andl $8388607, %esi # imm = 0x7FFFFF
+; CHECK-NEXT:    shrdq %cl, %rsi, %rdi
+; CHECK-NEXT:    shrq %cl, %rsi
+; CHECK-NEXT:    testb $64, %cl
+; CHECK-NEXT:    cmoveq %rdi, %rsi
+; CHECK-NEXT:    movd %esi, %xmm0
+; CHECK-NEXT:    retq
+  %result = bitextract float, b87 %src, i32 %off
+  ret float %result
+}
+
+define float @test_bitextract_float_b87_crossword(b87 %src) {
+; CHECK-LABEL: test_bitextract_float_b87_crossword:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    andl $8388607, %esi # imm = 0x7FFFFF
+; CHECK-NEXT:    shldq $4, %rdi, %rsi
+; CHECK-NEXT:    movd %esi, %xmm0
+; CHECK-NEXT:    retq
+  %result = bitextract float, b87 %src, i32 60
+  ret float %result
+}
+
+define double @test_bitextract_double_full(b64 %src) {
+; CHECK-LABEL: test_bitextract_double_full:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movq %rdi, %xmm0
+; CHECK-NEXT:    retq
+  %result = bitextract double, b64 %src, i32 0
+  ret double %result
+}
+
+define double @test_bitextract_double_const(b128 %src) {
+; CHECK-LABEL: test_bitextract_double_const:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movq %rsi, %xmm0
+; CHECK-NEXT:    retq
+  %result = bitextract double, b128 %src, i32 64
+  ret double %result
+}
+
+define double @test_bitextract_double_var(b128 %src, i32 %off) {
+; CHECK-LABEL: test_bitextract_double_var:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movl %edx, %ecx
+; CHECK-NEXT:    shrdq %cl, %rsi, %rdi
+; CHECK-NEXT:    shrq %cl, %rsi
+; CHECK-NEXT:    testb $64, %cl
+; CHECK-NEXT:    cmoveq %rdi, %rsi
+; CHECK-NEXT:    movq %rsi, %xmm0
+; CHECK-NEXT:    retq
+  %result = bitextract double, b128 %src, i32 %off
+  ret double %result
+}
+
+define double @test_bitextract_double_b231_var(b231 %src, i32 %off) {
+; CHECK-LABEL: test_bitextract_double_b231_var:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movabsq $549755813887, %rax # imm = 0x7FFFFFFFFF
+; CHECK-NEXT:    andq %rcx, %rax
+; CHECK-NEXT:    xorps %xmm0, %xmm0
+; CHECK-NEXT:    movaps %xmm0, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movaps %xmm0, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movq %rdx, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movq %rsi, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movq %rdi, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movq %rax, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    movl %r8d, %eax
+; CHECK-NEXT:    shrb $6, %al
+; CHECK-NEXT:    movzbl %al, %eax
+; CHECK-NEXT:    movq -72(%rsp,%rax,8), %rdx
+; CHECK-NEXT:    movq -64(%rsp,%rax,8), %rax
+; CHECK-NEXT:    movl %r8d, %ecx
+; CHECK-NEXT:    shrdq %cl, %rax, %rdx
+; CHECK-NEXT:    movq %rdx, %xmm0
+; CHECK-NEXT:    retq
+  %result = bitextract double, b231 %src, i32 %off
+  ret double %result
+}
+
+define double @test_bitextract_double_b231_crossword(b231 %src) {
+; CHECK-LABEL: test_bitextract_double_b231_crossword:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movabsq $549755813887, %rax # imm = 0x7FFFFFFFFF
+; CHECK-NEXT:    andq %rcx, %rax
+; CHECK-NEXT:    shldq $2, %rdx, %rax
+; CHECK-NEXT:    movq %rax, %xmm0
+; CHECK-NEXT:    retq
+  %result = bitextract double, b231 %src, i32 190
+  ret double %result
+}
+
+define b16 @test_bitinsert_half_full(b16 %base, half %val) {
+; CHECK-LABEL: test_bitinsert_half_full:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pextrw $0, %xmm0, %eax
+; CHECK-NEXT:    # kill: def $ax killed $ax killed $eax
+; CHECK-NEXT:    retq
+  %result = bitinsert b16 %base, half %val, i32 0
+  ret b16 %result
+}
+
+define b32 @test_bitinsert_half_const(b32 %base, half %val) {
+; CHECK-LABEL: test_bitinsert_half_const:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pextrw $0, %xmm0, %eax
+; CHECK-NEXT:    rorl $8, %edi
+; CHECK-NEXT:    andl $-65536, %edi # imm = 0xFFFF0000
+; CHECK-NEXT:    movzwl %ax, %eax
+; CHECK-NEXT:    orl %edi, %eax
+; CHECK-NEXT:    roll $8, %eax
+; CHECK-NEXT:    retq
+  %result = bitinsert b32 %base, half %val, i32 8
+  ret b32 %result
+}
+
+define b32 @test_bitinsert_half_var(b32 %base, half %val, i32 %off) {
+; CHECK-LABEL: test_bitinsert_half_var:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movl %esi, %ecx
+; CHECK-NEXT:    pextrw $0, %xmm0, %eax
+; CHECK-NEXT:    rorl %cl, %edi
+; CHECK-NEXT:    andl $-65536, %edi # imm = 0xFFFF0000
+; CHECK-NEXT:    movzwl %ax, %eax
+; CHECK-NEXT:    orl %edi, %eax
+; CHECK-NEXT:    # kill: def $cl killed $cl killed $ecx
+; CHECK-NEXT:    roll %cl, %eax
+; CHECK-NEXT:    retq
+  %result = bitinsert b32 %base, half %val, i32 %off
+  ret b32 %result
+}
+
+define b32 @test_bitinsert_float_full(b32 %base, float %val) {
+; CHECK-LABEL: test_bitinsert_float_full:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movd %xmm0, %eax
+; CHECK-NEXT:    retq
+  %result = bitinsert b32 %base, float %val, i32 0
+  ret b32 %result
+}
+
+define b64 @test_bitinsert_float_const(b64 %base, float %val) {
+; CHECK-LABEL: test_bitinsert_float_const:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movd %xmm0, %eax
+; CHECK-NEXT:    shlq $32, %rdi
+; CHECK-NEXT:    orq %rdi, %rax
+; CHECK-NEXT:    rolq $32, %rax
+; CHECK-NEXT:    retq
+  %result = bitinsert b64 %base, float %val, i32 32
+  ret b64 %result
+}
+
+define b64 @test_bitinsert_float_var(b64 %base, float %val, i32 %off) {
+; CHECK-LABEL: test_bitinsert_float_var:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movl %esi, %ecx
+; CHECK-NEXT:    movd %xmm0, %eax
+; CHECK-NEXT:    rorq %cl, %rdi
+; CHECK-NEXT:    movabsq $-4294967296, %rdx # imm = 0xFFFFFFFF00000000
+; CHECK-NEXT:    andq %rdi, %rdx
+; CHECK-NEXT:    orq %rdx, %rax
+; CHECK-NEXT:    # kill: def $cl killed $cl killed $ecx
+; CHECK-NEXT:    rolq %cl, %rax
+; CHECK-NEXT:    retq
+  %result = bitinsert b64 %base, float %val, i32 %off
+  ret b64 %result
+}
+
+define b87 @test_bitinsert_float_b87_var(b87 %base, float %val, i32 %off) {
+; CHECK-LABEL: test_bitinsert_float_b87_var:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pushq %rbx
+; CHECK-NEXT:    .cfi_def_cfa_offset 16
+; CHECK-NEXT:    .cfi_offset %rbx, -16
+; CHECK-NEXT:    movd %xmm0, %r10d
+; CHECK-NEXT:    movl %esi, %eax
+; CHECK-NEXT:    andl $8388607, %eax # imm = 0x7FFFFF
+; CHECK-NEXT:    shldq $1, %rdi, %rsi
+; CHECK-NEXT:    movzbl %dl, %r8d
+; CHECK-NEXT:    imull $189, %r8d, %ecx
+; CHECK-NEXT:    shrl $14, %ecx
+; CHECK-NEXT:    imull $87, %ecx, %ecx
----------------
aengelke wrote:

Same question here -- the codegen is abysmally bad, why?

https://github.com/llvm/llvm-project/pull/200605


More information about the llvm-commits mailing list