; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=i686-unknown-unknown | FileCheck %s --check-prefix=X32 ; RUN: llc < %s -mtriple=x86_64-unknown-unknown | FileCheck %s --check-prefix=X64 ;==============================================================================; ; the shift amount is negated (shiftbitwidth - shiftamt) ;==============================================================================; ; shift left ;------------------------------------------------------------------------------; define i32 @reg32_shl_by_negated(i32 %val, i32 %shamt) nounwind { ; X32-LABEL: reg32_shl_by_negated: ; X32: # %bb.0: ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: xorl %ecx, %ecx ; X32-NEXT: subb {{[0-9]+}}(%esp), %cl ; X32-NEXT: # kill: def $cl killed $cl killed $ecx ; X32-NEXT: shll %cl, %eax ; X32-NEXT: retl ; ; X64-LABEL: reg32_shl_by_negated: ; X64: # %bb.0: ; X64-NEXT: movl %esi, %ecx ; X64-NEXT: movl %edi, %eax ; X64-NEXT: negb %cl ; X64-NEXT: # kill: def $cl killed $cl killed $ecx ; X64-NEXT: shll %cl, %eax ; X64-NEXT: retq %negshamt = sub i32 32, %shamt %shifted = shl i32 %val, %negshamt ret i32 %shifted } define i32 @load32_shl_by_negated(ptr %valptr, i32 %shamt) nounwind { ; X32-LABEL: load32_shl_by_negated: ; X32: # %bb.0: ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movl (%eax), %eax ; X32-NEXT: xorl %ecx, %ecx ; X32-NEXT: subb {{[0-9]+}}(%esp), %cl ; X32-NEXT: # kill: def $cl killed $cl killed $ecx ; X32-NEXT: shll %cl, %eax ; X32-NEXT: retl ; ; X64-LABEL: load32_shl_by_negated: ; X64: # %bb.0: ; X64-NEXT: movl %esi, %ecx ; X64-NEXT: movl (%rdi), %eax ; X64-NEXT: negb %cl ; X64-NEXT: # kill: def $cl killed $cl killed $ecx ; X64-NEXT: shll %cl, %eax ; X64-NEXT: retq %val = load i32, ptr %valptr %negshamt = sub i32 32, %shamt %shifted = shl i32 %val, %negshamt ret i32 %shifted } define void @store32_shl_by_negated(i32 %val, ptr %dstptr, i32 %shamt) nounwind { ; X32-LABEL: store32_shl_by_negated: ; X32: # %bb.0: ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movl {{[0-9]+}}(%esp), %edx ; X32-NEXT: xorl %ecx, %ecx ; X32-NEXT: subb {{[0-9]+}}(%esp), %cl ; X32-NEXT: # kill: def $cl killed $cl killed $ecx ; X32-NEXT: shll %cl, %edx ; X32-NEXT: movl %edx, (%eax) ; X32-NEXT: retl ; ; X64-LABEL: store32_shl_by_negated: ; X64: # %bb.0: ; X64-NEXT: movl %edx, %ecx ; X64-NEXT: negb %cl ; X64-NEXT: # kill: def $cl killed $cl killed $ecx ; X64-NEXT: shll %cl, %edi ; X64-NEXT: movl %edi, (%rsi) ; X64-NEXT: retq %negshamt = sub i32 32, %shamt %shifted = shl i32 %val, %negshamt store i32 %shifted, ptr %dstptr ret void } define void @modify32_shl_by_negated(ptr %valptr, i32 %shamt) nounwind { ; X32-LABEL: modify32_shl_by_negated: ; X32: # %bb.0: ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movb $32, %cl ; X32-NEXT: subb {{[0-9]+}}(%esp), %cl ; X32-NEXT: shll %cl, (%eax) ; X32-NEXT: retl ; ; X64-LABEL: modify32_shl_by_negated: ; X64: # %bb.0: ; X64-NEXT: movb $32, %cl ; X64-NEXT: subb %sil, %cl ; X64-NEXT: shll %cl, (%rdi) ; X64-NEXT: retq %val = load i32, ptr %valptr %negshamt = sub i32 32, %shamt %shifted = shl i32 %val, %negshamt store i32 %shifted, ptr %valptr ret void } define i64 @reg64_shl_by_negated(i64 %val, i64 %shamt) nounwind { ; X32-LABEL: reg64_shl_by_negated: ; X32: # %bb.0: ; X32-NEXT: pushl %esi ; X32-NEXT: movl {{[0-9]+}}(%esp), %esi ; X32-NEXT: movl {{[0-9]+}}(%esp), %edx ; X32-NEXT: movb $64, %cl ; X32-NEXT: subb {{[0-9]+}}(%esp), %cl ; X32-NEXT: movl %esi, %eax ; X32-NEXT: shll %cl, %eax ; X32-NEXT: shldl %cl, %esi, %edx ; X32-NEXT: testb $32, %cl ; X32-NEXT: je .LBB4_2 ; X32-NEXT: # %bb.1: ; X32-NEXT: movl %eax, %edx ; X32-NEXT: xorl %eax, %eax ; X32-NEXT: .LBB4_2: ; X32-NEXT: popl %esi ; X32-NEXT: retl ; ; X64-LABEL: reg64_shl_by_negated: ; X64: # %bb.0: ; X64-NEXT: movq %rsi, %rcx ; X64-NEXT: movq %rdi, %rax ; X64-NEXT: negb %cl ; X64-NEXT: # kill: def $cl killed $cl killed $rcx ; X64-NEXT: shlq %cl, %rax ; X64-NEXT: retq %negshamt = sub i64 64, %shamt %shifted = shl i64 %val, %negshamt ret i64 %shifted } define i64 @load64_shl_by_negated(ptr %valptr, i64 %shamt) nounwind { ; X32-LABEL: load64_shl_by_negated: ; X32: # %bb.0: ; X32-NEXT: pushl %esi ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movl (%eax), %esi ; X32-NEXT: movl 4(%eax), %edx ; X32-NEXT: movb $64, %cl ; X32-NEXT: subb {{[0-9]+}}(%esp), %cl ; X32-NEXT: movl %esi, %eax ; X32-NEXT: shll %cl, %eax ; X32-NEXT: shldl %cl, %esi, %edx ; X32-NEXT: testb $32, %cl ; X32-NEXT: je .LBB5_2 ; X32-NEXT: # %bb.1: ; X32-NEXT: movl %eax, %edx ; X32-NEXT: xorl %eax, %eax ; X32-NEXT: .LBB5_2: ; X32-NEXT: popl %esi ; X32-NEXT: retl ; ; X64-LABEL: load64_shl_by_negated: ; X64: # %bb.0: ; X64-NEXT: movq %rsi, %rcx ; X64-NEXT: movq (%rdi), %rax ; X64-NEXT: negb %cl ; X64-NEXT: # kill: def $cl killed $cl killed $rcx ; X64-NEXT: shlq %cl, %rax ; X64-NEXT: retq %val = load i64, ptr %valptr %negshamt = sub i64 64, %shamt %shifted = shl i64 %val, %negshamt ret i64 %shifted } define void @store64_shl_by_negated(i64 %val, ptr %dstptr, i64 %shamt) nounwind { ; X32-LABEL: store64_shl_by_negated: ; X32: # %bb.0: ; X32-NEXT: pushl %edi ; X32-NEXT: pushl %esi ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movl {{[0-9]+}}(%esp), %edi ; X32-NEXT: movl {{[0-9]+}}(%esp), %edx ; X32-NEXT: movb $64, %cl ; X32-NEXT: subb {{[0-9]+}}(%esp), %cl ; X32-NEXT: movl %edi, %esi ; X32-NEXT: shll %cl, %esi ; X32-NEXT: shldl %cl, %edi, %edx ; X32-NEXT: testb $32, %cl ; X32-NEXT: je .LBB6_2 ; X32-NEXT: # %bb.1: ; X32-NEXT: movl %esi, %edx ; X32-NEXT: xorl %esi, %esi ; X32-NEXT: .LBB6_2: ; X32-NEXT: movl %edx, 4(%eax) ; X32-NEXT: movl %esi, (%eax) ; X32-NEXT: popl %esi ; X32-NEXT: popl %edi ; X32-NEXT: retl ; ; X64-LABEL: store64_shl_by_negated: ; X64: # %bb.0: ; X64-NEXT: movq %rdx, %rcx ; X64-NEXT: negb %cl ; X64-NEXT: # kill: def $cl killed $cl killed $rcx ; X64-NEXT: shlq %cl, %rdi ; X64-NEXT: movq %rdi, (%rsi) ; X64-NEXT: retq %negshamt = sub i64 64, %shamt %shifted = shl i64 %val, %negshamt store i64 %shifted, ptr %dstptr ret void } define void @modify64_shl_by_negated(ptr %valptr, i64 %shamt) nounwind { ; X32-LABEL: modify64_shl_by_negated: ; X32: # %bb.0: ; X32-NEXT: pushl %edi ; X32-NEXT: pushl %esi ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movl (%eax), %edi ; X32-NEXT: movl 4(%eax), %edx ; X32-NEXT: movb $64, %cl ; X32-NEXT: subb {{[0-9]+}}(%esp), %cl ; X32-NEXT: movl %edi, %esi ; X32-NEXT: shll %cl, %esi ; X32-NEXT: shldl %cl, %edi, %edx ; X32-NEXT: testb $32, %cl ; X32-NEXT: je .LBB7_2 ; X32-NEXT: # %bb.1: ; X32-NEXT: movl %esi, %edx ; X32-NEXT: xorl %esi, %esi ; X32-NEXT: .LBB7_2: ; X32-NEXT: movl %esi, (%eax) ; X32-NEXT: movl %edx, 4(%eax) ; X32-NEXT: popl %esi ; X32-NEXT: popl %edi ; X32-NEXT: retl ; ; X64-LABEL: modify64_shl_by_negated: ; X64: # %bb.0: ; X64-NEXT: movb $64, %cl ; X64-NEXT: subb %sil, %cl ; X64-NEXT: shlq %cl, (%rdi) ; X64-NEXT: retq %val = load i64, ptr %valptr %negshamt = sub i64 64, %shamt %shifted = shl i64 %val, %negshamt store i64 %shifted, ptr %valptr ret void } ; logical shift right ;------------------------------------------------------------------------------; define i32 @reg32_lshr_by_negated(i32 %val, i32 %shamt) nounwind { ; X32-LABEL: reg32_lshr_by_negated: ; X32: # %bb.0: ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: xorl %ecx, %ecx ; X32-NEXT: subb {{[0-9]+}}(%esp), %cl ; X32-NEXT: # kill: def $cl killed $cl killed $ecx ; X32-NEXT: shrl %cl, %eax ; X32-NEXT: retl ; ; X64-LABEL: reg32_lshr_by_negated: ; X64: # %bb.0: ; X64-NEXT: movl %esi, %ecx ; X64-NEXT: movl %edi, %eax ; X64-NEXT: negb %cl ; X64-NEXT: # kill: def $cl killed $cl killed $ecx ; X64-NEXT: shrl %cl, %eax ; X64-NEXT: retq %negshamt = sub i32 32, %shamt %shifted = lshr i32 %val, %negshamt ret i32 %shifted } define i32 @load32_lshr_by_negated(ptr %valptr, i32 %shamt) nounwind { ; X32-LABEL: load32_lshr_by_negated: ; X32: # %bb.0: ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movl (%eax), %eax ; X32-NEXT: xorl %ecx, %ecx ; X32-NEXT: subb {{[0-9]+}}(%esp), %cl ; X32-NEXT: # kill: def $cl killed $cl killed $ecx ; X32-NEXT: shrl %cl, %eax ; X32-NEXT: retl ; ; X64-LABEL: load32_lshr_by_negated: ; X64: # %bb.0: ; X64-NEXT: movl %esi, %ecx ; X64-NEXT: movl (%rdi), %eax ; X64-NEXT: negb %cl ; X64-NEXT: # kill: def $cl killed $cl killed $ecx ; X64-NEXT: shrl %cl, %eax ; X64-NEXT: retq %val = load i32, ptr %valptr %negshamt = sub i32 32, %shamt %shifted = lshr i32 %val, %negshamt ret i32 %shifted } define void @store32_lshr_by_negated(i32 %val, ptr %dstptr, i32 %shamt) nounwind { ; X32-LABEL: store32_lshr_by_negated: ; X32: # %bb.0: ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movl {{[0-9]+}}(%esp), %edx ; X32-NEXT: xorl %ecx, %ecx ; X32-NEXT: subb {{[0-9]+}}(%esp), %cl ; X32-NEXT: # kill: def $cl killed $cl killed $ecx ; X32-NEXT: shrl %cl, %edx ; X32-NEXT: movl %edx, (%eax) ; X32-NEXT: retl ; ; X64-LABEL: store32_lshr_by_negated: ; X64: # %bb.0: ; X64-NEXT: movl %edx, %ecx ; X64-NEXT: negb %cl ; X64-NEXT: # kill: def $cl killed $cl killed $ecx ; X64-NEXT: shrl %cl, %edi ; X64-NEXT: movl %edi, (%rsi) ; X64-NEXT: retq %negshamt = sub i32 32, %shamt %shifted = lshr i32 %val, %negshamt store i32 %shifted, ptr %dstptr ret void } define void @modify32_lshr_by_negated(ptr %valptr, i32 %shamt) nounwind { ; X32-LABEL: modify32_lshr_by_negated: ; X32: # %bb.0: ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movb $32, %cl ; X32-NEXT: subb {{[0-9]+}}(%esp), %cl ; X32-NEXT: shrl %cl, (%eax) ; X32-NEXT: retl ; ; X64-LABEL: modify32_lshr_by_negated: ; X64: # %bb.0: ; X64-NEXT: movb $32, %cl ; X64-NEXT: subb %sil, %cl ; X64-NEXT: shrl %cl, (%rdi) ; X64-NEXT: retq %val = load i32, ptr %valptr %negshamt = sub i32 32, %shamt %shifted = lshr i32 %val, %negshamt store i32 %shifted, ptr %valptr ret void } define i64 @reg64_lshr_by_negated(i64 %val, i64 %shamt) nounwind { ; X32-LABEL: reg64_lshr_by_negated: ; X32: # %bb.0: ; X32-NEXT: pushl %esi ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movl {{[0-9]+}}(%esp), %esi ; X32-NEXT: movb $64, %cl ; X32-NEXT: subb {{[0-9]+}}(%esp), %cl ; X32-NEXT: movl %esi, %edx ; X32-NEXT: shrl %cl, %edx ; X32-NEXT: shrdl %cl, %esi, %eax ; X32-NEXT: testb $32, %cl ; X32-NEXT: je .LBB12_2 ; X32-NEXT: # %bb.1: ; X32-NEXT: movl %edx, %eax ; X32-NEXT: xorl %edx, %edx ; X32-NEXT: .LBB12_2: ; X32-NEXT: popl %esi ; X32-NEXT: retl ; ; X64-LABEL: reg64_lshr_by_negated: ; X64: # %bb.0: ; X64-NEXT: movq %rsi, %rcx ; X64-NEXT: movq %rdi, %rax ; X64-NEXT: negb %cl ; X64-NEXT: # kill: def $cl killed $cl killed $rcx ; X64-NEXT: shrq %cl, %rax ; X64-NEXT: retq %negshamt = sub i64 64, %shamt %shifted = lshr i64 %val, %negshamt ret i64 %shifted } define i64 @load64_lshr_by_negated(ptr %valptr, i64 %shamt) nounwind { ; X32-LABEL: load64_lshr_by_negated: ; X32: # %bb.0: ; X32-NEXT: pushl %esi ; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx ; X32-NEXT: movl (%ecx), %eax ; X32-NEXT: movl 4(%ecx), %esi ; X32-NEXT: movb $64, %cl ; X32-NEXT: subb {{[0-9]+}}(%esp), %cl ; X32-NEXT: movl %esi, %edx ; X32-NEXT: shrl %cl, %edx ; X32-NEXT: shrdl %cl, %esi, %eax ; X32-NEXT: testb $32, %cl ; X32-NEXT: je .LBB13_2 ; X32-NEXT: # %bb.1: ; X32-NEXT: movl %edx, %eax ; X32-NEXT: xorl %edx, %edx ; X32-NEXT: .LBB13_2: ; X32-NEXT: popl %esi ; X32-NEXT: retl ; ; X64-LABEL: load64_lshr_by_negated: ; X64: # %bb.0: ; X64-NEXT: movq %rsi, %rcx ; X64-NEXT: movq (%rdi), %rax ; X64-NEXT: negb %cl ; X64-NEXT: # kill: def $cl killed $cl killed $rcx ; X64-NEXT: shrq %cl, %rax ; X64-NEXT: retq %val = load i64, ptr %valptr %negshamt = sub i64 64, %shamt %shifted = lshr i64 %val, %negshamt ret i64 %shifted } define void @store64_lshr_by_negated(i64 %val, ptr %dstptr, i64 %shamt) nounwind { ; X32-LABEL: store64_lshr_by_negated: ; X32: # %bb.0: ; X32-NEXT: pushl %edi ; X32-NEXT: pushl %esi ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movl {{[0-9]+}}(%esp), %edx ; X32-NEXT: movl {{[0-9]+}}(%esp), %edi ; X32-NEXT: movb $64, %cl ; X32-NEXT: subb {{[0-9]+}}(%esp), %cl ; X32-NEXT: movl %edi, %esi ; X32-NEXT: shrl %cl, %esi ; X32-NEXT: shrdl %cl, %edi, %edx ; X32-NEXT: testb $32, %cl ; X32-NEXT: je .LBB14_2 ; X32-NEXT: # %bb.1: ; X32-NEXT: movl %esi, %edx ; X32-NEXT: xorl %esi, %esi ; X32-NEXT: .LBB14_2: ; X32-NEXT: movl %esi, 4(%eax) ; X32-NEXT: movl %edx, (%eax) ; X32-NEXT: popl %esi ; X32-NEXT: popl %edi ; X32-NEXT: retl ; ; X64-LABEL: store64_lshr_by_negated: ; X64: # %bb.0: ; X64-NEXT: movq %rdx, %rcx ; X64-NEXT: negb %cl ; X64-NEXT: # kill: def $cl killed $cl killed $rcx ; X64-NEXT: shrq %cl, %rdi ; X64-NEXT: movq %rdi, (%rsi) ; X64-NEXT: retq %negshamt = sub i64 64, %shamt %shifted = lshr i64 %val, %negshamt store i64 %shifted, ptr %dstptr ret void } define void @modify64_lshr_by_negated(ptr %valptr, i64 %shamt) nounwind { ; X32-LABEL: modify64_lshr_by_negated: ; X32: # %bb.0: ; X32-NEXT: pushl %edi ; X32-NEXT: pushl %esi ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movl (%eax), %edx ; X32-NEXT: movl 4(%eax), %edi ; X32-NEXT: movb $64, %cl ; X32-NEXT: subb {{[0-9]+}}(%esp), %cl ; X32-NEXT: movl %edi, %esi ; X32-NEXT: shrl %cl, %esi ; X32-NEXT: shrdl %cl, %edi, %edx ; X32-NEXT: testb $32, %cl ; X32-NEXT: je .LBB15_2 ; X32-NEXT: # %bb.1: ; X32-NEXT: movl %esi, %edx ; X32-NEXT: xorl %esi, %esi ; X32-NEXT: .LBB15_2: ; X32-NEXT: movl %edx, (%eax) ; X32-NEXT: movl %esi, 4(%eax) ; X32-NEXT: popl %esi ; X32-NEXT: popl %edi ; X32-NEXT: retl ; ; X64-LABEL: modify64_lshr_by_negated: ; X64: # %bb.0: ; X64-NEXT: movb $64, %cl ; X64-NEXT: subb %sil, %cl ; X64-NEXT: shrq %cl, (%rdi) ; X64-NEXT: retq %val = load i64, ptr %valptr %negshamt = sub i64 64, %shamt %shifted = lshr i64 %val, %negshamt store i64 %shifted, ptr %valptr ret void } ; arithmetic shift right ;------------------------------------------------------------------------------; define i32 @reg32_ashr_by_negated(i32 %val, i32 %shamt) nounwind { ; X32-LABEL: reg32_ashr_by_negated: ; X32: # %bb.0: ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: xorl %ecx, %ecx ; X32-NEXT: subb {{[0-9]+}}(%esp), %cl ; X32-NEXT: # kill: def $cl killed $cl killed $ecx ; X32-NEXT: sarl %cl, %eax ; X32-NEXT: retl ; ; X64-LABEL: reg32_ashr_by_negated: ; X64: # %bb.0: ; X64-NEXT: movl %esi, %ecx ; X64-NEXT: movl %edi, %eax ; X64-NEXT: negb %cl ; X64-NEXT: # kill: def $cl killed $cl killed $ecx ; X64-NEXT: sarl %cl, %eax ; X64-NEXT: retq %negshamt = sub i32 32, %shamt %shifted = ashr i32 %val, %negshamt ret i32 %shifted } define i32 @load32_ashr_by_negated(ptr %valptr, i32 %shamt) nounwind { ; X32-LABEL: load32_ashr_by_negated: ; X32: # %bb.0: ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movl (%eax), %eax ; X32-NEXT: xorl %ecx, %ecx ; X32-NEXT: subb {{[0-9]+}}(%esp), %cl ; X32-NEXT: # kill: def $cl killed $cl killed $ecx ; X32-NEXT: sarl %cl, %eax ; X32-NEXT: retl ; ; X64-LABEL: load32_ashr_by_negated: ; X64: # %bb.0: ; X64-NEXT: movl %esi, %ecx ; X64-NEXT: movl (%rdi), %eax ; X64-NEXT: negb %cl ; X64-NEXT: # kill: def $cl killed $cl killed $ecx ; X64-NEXT: sarl %cl, %eax ; X64-NEXT: retq %val = load i32, ptr %valptr %negshamt = sub i32 32, %shamt %shifted = ashr i32 %val, %negshamt ret i32 %shifted } define void @store32_ashr_by_negated(i32 %val, ptr %dstptr, i32 %shamt) nounwind { ; X32-LABEL: store32_ashr_by_negated: ; X32: # %bb.0: ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movl {{[0-9]+}}(%esp), %edx ; X32-NEXT: xorl %ecx, %ecx ; X32-NEXT: subb {{[0-9]+}}(%esp), %cl ; X32-NEXT: # kill: def $cl killed $cl killed $ecx ; X32-NEXT: sarl %cl, %edx ; X32-NEXT: movl %edx, (%eax) ; X32-NEXT: retl ; ; X64-LABEL: store32_ashr_by_negated: ; X64: # %bb.0: ; X64-NEXT: movl %edx, %ecx ; X64-NEXT: negb %cl ; X64-NEXT: # kill: def $cl killed $cl killed $ecx ; X64-NEXT: sarl %cl, %edi ; X64-NEXT: movl %edi, (%rsi) ; X64-NEXT: retq %negshamt = sub i32 32, %shamt %shifted = ashr i32 %val, %negshamt store i32 %shifted, ptr %dstptr ret void } define void @modify32_ashr_by_negated(ptr %valptr, i32 %shamt) nounwind { ; X32-LABEL: modify32_ashr_by_negated: ; X32: # %bb.0: ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movb $32, %cl ; X32-NEXT: subb {{[0-9]+}}(%esp), %cl ; X32-NEXT: sarl %cl, (%eax) ; X32-NEXT: retl ; ; X64-LABEL: modify32_ashr_by_negated: ; X64: # %bb.0: ; X64-NEXT: movb $32, %cl ; X64-NEXT: subb %sil, %cl ; X64-NEXT: sarl %cl, (%rdi) ; X64-NEXT: retq %val = load i32, ptr %valptr %negshamt = sub i32 32, %shamt %shifted = ashr i32 %val, %negshamt store i32 %shifted, ptr %valptr ret void } define i64 @reg64_ashr_by_negated(i64 %val, i64 %shamt) nounwind { ; X32-LABEL: reg64_ashr_by_negated: ; X32: # %bb.0: ; X32-NEXT: pushl %esi ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movl {{[0-9]+}}(%esp), %esi ; X32-NEXT: movb $64, %cl ; X32-NEXT: subb {{[0-9]+}}(%esp), %cl ; X32-NEXT: movl %esi, %edx ; X32-NEXT: sarl %cl, %edx ; X32-NEXT: shrdl %cl, %esi, %eax ; X32-NEXT: testb $32, %cl ; X32-NEXT: je .LBB20_2 ; X32-NEXT: # %bb.1: ; X32-NEXT: sarl $31, %esi ; X32-NEXT: movl %edx, %eax ; X32-NEXT: movl %esi, %edx ; X32-NEXT: .LBB20_2: ; X32-NEXT: popl %esi ; X32-NEXT: retl ; ; X64-LABEL: reg64_ashr_by_negated: ; X64: # %bb.0: ; X64-NEXT: movq %rsi, %rcx ; X64-NEXT: movq %rdi, %rax ; X64-NEXT: negb %cl ; X64-NEXT: # kill: def $cl killed $cl killed $rcx ; X64-NEXT: sarq %cl, %rax ; X64-NEXT: retq %negshamt = sub i64 64, %shamt %shifted = ashr i64 %val, %negshamt ret i64 %shifted } define i64 @load64_ashr_by_negated(ptr %valptr, i64 %shamt) nounwind { ; X32-LABEL: load64_ashr_by_negated: ; X32: # %bb.0: ; X32-NEXT: pushl %esi ; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx ; X32-NEXT: movl (%ecx), %eax ; X32-NEXT: movl 4(%ecx), %esi ; X32-NEXT: movb $64, %cl ; X32-NEXT: subb {{[0-9]+}}(%esp), %cl ; X32-NEXT: movl %esi, %edx ; X32-NEXT: sarl %cl, %edx ; X32-NEXT: shrdl %cl, %esi, %eax ; X32-NEXT: testb $32, %cl ; X32-NEXT: je .LBB21_2 ; X32-NEXT: # %bb.1: ; X32-NEXT: sarl $31, %esi ; X32-NEXT: movl %edx, %eax ; X32-NEXT: movl %esi, %edx ; X32-NEXT: .LBB21_2: ; X32-NEXT: popl %esi ; X32-NEXT: retl ; ; X64-LABEL: load64_ashr_by_negated: ; X64: # %bb.0: ; X64-NEXT: movq %rsi, %rcx ; X64-NEXT: movq (%rdi), %rax ; X64-NEXT: negb %cl ; X64-NEXT: # kill: def $cl killed $cl killed $rcx ; X64-NEXT: sarq %cl, %rax ; X64-NEXT: retq %val = load i64, ptr %valptr %negshamt = sub i64 64, %shamt %shifted = ashr i64 %val, %negshamt ret i64 %shifted } define void @store64_ashr_by_negated(i64 %val, ptr %dstptr, i64 %shamt) nounwind { ; X32-LABEL: store64_ashr_by_negated: ; X32: # %bb.0: ; X32-NEXT: pushl %edi ; X32-NEXT: pushl %esi ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movl {{[0-9]+}}(%esp), %edx ; X32-NEXT: movl {{[0-9]+}}(%esp), %edi ; X32-NEXT: movb $64, %cl ; X32-NEXT: subb {{[0-9]+}}(%esp), %cl ; X32-NEXT: movl %edi, %esi ; X32-NEXT: sarl %cl, %esi ; X32-NEXT: shrdl %cl, %edi, %edx ; X32-NEXT: testb $32, %cl ; X32-NEXT: je .LBB22_2 ; X32-NEXT: # %bb.1: ; X32-NEXT: sarl $31, %edi ; X32-NEXT: movl %esi, %edx ; X32-NEXT: movl %edi, %esi ; X32-NEXT: .LBB22_2: ; X32-NEXT: movl %esi, 4(%eax) ; X32-NEXT: movl %edx, (%eax) ; X32-NEXT: popl %esi ; X32-NEXT: popl %edi ; X32-NEXT: retl ; ; X64-LABEL: store64_ashr_by_negated: ; X64: # %bb.0: ; X64-NEXT: movq %rdx, %rcx ; X64-NEXT: negb %cl ; X64-NEXT: # kill: def $cl killed $cl killed $rcx ; X64-NEXT: sarq %cl, %rdi ; X64-NEXT: movq %rdi, (%rsi) ; X64-NEXT: retq %negshamt = sub i64 64, %shamt %shifted = ashr i64 %val, %negshamt store i64 %shifted, ptr %dstptr ret void } define void @modify64_ashr_by_negated(ptr %valptr, i64 %shamt) nounwind { ; X32-LABEL: modify64_ashr_by_negated: ; X32: # %bb.0: ; X32-NEXT: pushl %edi ; X32-NEXT: pushl %esi ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movl (%eax), %edx ; X32-NEXT: movl 4(%eax), %edi ; X32-NEXT: movb $64, %cl ; X32-NEXT: subb {{[0-9]+}}(%esp), %cl ; X32-NEXT: movl %edi, %esi ; X32-NEXT: sarl %cl, %esi ; X32-NEXT: shrdl %cl, %edi, %edx ; X32-NEXT: testb $32, %cl ; X32-NEXT: je .LBB23_2 ; X32-NEXT: # %bb.1: ; X32-NEXT: sarl $31, %edi ; X32-NEXT: movl %esi, %edx ; X32-NEXT: movl %edi, %esi ; X32-NEXT: .LBB23_2: ; X32-NEXT: movl %edx, (%eax) ; X32-NEXT: movl %esi, 4(%eax) ; X32-NEXT: popl %esi ; X32-NEXT: popl %edi ; X32-NEXT: retl ; ; X64-LABEL: modify64_ashr_by_negated: ; X64: # %bb.0: ; X64-NEXT: movb $64, %cl ; X64-NEXT: subb %sil, %cl ; X64-NEXT: sarq %cl, (%rdi) ; X64-NEXT: retq %val = load i64, ptr %valptr %negshamt = sub i64 64, %shamt %shifted = ashr i64 %val, %negshamt store i64 %shifted, ptr %valptr ret void } ;||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||; ; next let's only test simple reg pattern, and only lshr. ;||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||; ;==============================================================================; ; subtraction from negated shift amount define i32 @reg32_lshr_by_sub_from_negated(i32 %val, i32 %a, i32 %b) nounwind { ; X32-LABEL: reg32_lshr_by_sub_from_negated: ; X32: # %bb.0: ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx ; X32-NEXT: addl {{[0-9]+}}(%esp), %ecx ; X32-NEXT: negb %cl ; X32-NEXT: # kill: def $cl killed $cl killed $ecx ; X32-NEXT: shrl %cl, %eax ; X32-NEXT: retl ; ; X64-LABEL: reg32_lshr_by_sub_from_negated: ; X64: # %bb.0: ; X64-NEXT: # kill: def $edx killed $edx def $rdx ; X64-NEXT: # kill: def $esi killed $esi def $rsi ; X64-NEXT: movl %edi, %eax ; X64-NEXT: leal (%rsi,%rdx), %ecx ; X64-NEXT: negb %cl ; X64-NEXT: # kill: def $cl killed $cl killed $ecx ; X64-NEXT: shrl %cl, %eax ; X64-NEXT: retq %nega = sub i32 32, %a %negasubb = sub i32 %nega, %b %shifted = lshr i32 %val, %negasubb ret i32 %shifted } define i64 @reg64_lshr_by_sub_from_negated(i64 %val, i64 %a, i64 %b) nounwind { ; X32-LABEL: reg64_lshr_by_sub_from_negated: ; X32: # %bb.0: ; X32-NEXT: pushl %esi ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movl {{[0-9]+}}(%esp), %esi ; X32-NEXT: movl {{[0-9]+}}(%esp), %edx ; X32-NEXT: addl {{[0-9]+}}(%esp), %edx ; X32-NEXT: movb $64, %cl ; X32-NEXT: subb %dl, %cl ; X32-NEXT: movl %esi, %edx ; X32-NEXT: shrl %cl, %edx ; X32-NEXT: shrdl %cl, %esi, %eax ; X32-NEXT: testb $32, %cl ; X32-NEXT: je .LBB25_2 ; X32-NEXT: # %bb.1: ; X32-NEXT: movl %edx, %eax ; X32-NEXT: xorl %edx, %edx ; X32-NEXT: .LBB25_2: ; X32-NEXT: popl %esi ; X32-NEXT: retl ; ; X64-LABEL: reg64_lshr_by_sub_from_negated: ; X64: # %bb.0: ; X64-NEXT: movq %rdi, %rax ; X64-NEXT: leal (%rdx,%rsi), %ecx ; X64-NEXT: negb %cl ; X64-NEXT: # kill: def $cl killed $cl killed $ecx ; X64-NEXT: shrq %cl, %rax ; X64-NEXT: retq %nega = sub i64 64, %a %negasubb = sub i64 %nega, %b %shifted = lshr i64 %val, %negasubb ret i64 %shifted } ;==============================================================================; ; subtraction of negated shift amount define i32 @reg32_lshr_by_sub_of_negated(i32 %val, i32 %a, i32 %b) nounwind { ; X32-LABEL: reg32_lshr_by_sub_of_negated: ; X32: # %bb.0: ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx ; X32-NEXT: addl {{[0-9]+}}(%esp), %ecx ; X32-NEXT: # kill: def $cl killed $cl killed $ecx ; X32-NEXT: shrl %cl, %eax ; X32-NEXT: retl ; ; X64-LABEL: reg32_lshr_by_sub_of_negated: ; X64: # %bb.0: ; X64-NEXT: # kill: def $edx killed $edx def $rdx ; X64-NEXT: # kill: def $esi killed $esi def $rsi ; X64-NEXT: movl %edi, %eax ; X64-NEXT: leal (%rsi,%rdx), %ecx ; X64-NEXT: # kill: def $cl killed $cl killed $ecx ; X64-NEXT: shrl %cl, %eax ; X64-NEXT: retq %nega = sub i32 32, %a %negasubb = sub i32 %b, %nega %shifted = lshr i32 %val, %negasubb ret i32 %shifted } define i64 @reg64_lshr_by_sub_of_negated(i64 %val, i64 %a, i64 %b) nounwind { ; X32-LABEL: reg64_lshr_by_sub_of_negated: ; X32: # %bb.0: ; X32-NEXT: pushl %esi ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movl {{[0-9]+}}(%esp), %esi ; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx ; X32-NEXT: addl {{[0-9]+}}(%esp), %ecx ; X32-NEXT: addb $-64, %cl ; X32-NEXT: movl %esi, %edx ; X32-NEXT: shrl %cl, %edx ; X32-NEXT: shrdl %cl, %esi, %eax ; X32-NEXT: testb $32, %cl ; X32-NEXT: je .LBB27_2 ; X32-NEXT: # %bb.1: ; X32-NEXT: movl %edx, %eax ; X32-NEXT: xorl %edx, %edx ; X32-NEXT: .LBB27_2: ; X32-NEXT: popl %esi ; X32-NEXT: retl ; ; X64-LABEL: reg64_lshr_by_sub_of_negated: ; X64: # %bb.0: ; X64-NEXT: movq %rdi, %rax ; X64-NEXT: leal (%rdx,%rsi), %ecx ; X64-NEXT: # kill: def $cl killed $cl killed $ecx ; X64-NEXT: shrq %cl, %rax ; X64-NEXT: retq %nega = sub i64 64, %a %negasubb = sub i64 %b, %nega %shifted = lshr i64 %val, %negasubb ret i64 %shifted } ;==============================================================================; ; add to negated shift amount ; define i32 @reg32_lshr_by_add_to_negated(i32 %val, i32 %a, i32 %b) nounwind { ; X32-LABEL: reg32_lshr_by_add_to_negated: ; X32: # %bb.0: ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx ; X32-NEXT: subl {{[0-9]+}}(%esp), %ecx ; X32-NEXT: # kill: def $cl killed $cl killed $ecx ; X32-NEXT: shrl %cl, %eax ; X32-NEXT: retl ; ; X64-LABEL: reg32_lshr_by_add_to_negated: ; X64: # %bb.0: ; X64-NEXT: movl %edx, %ecx ; X64-NEXT: movl %edi, %eax ; X64-NEXT: subl %esi, %ecx ; X64-NEXT: # kill: def $cl killed $cl killed $ecx ; X64-NEXT: shrl %cl, %eax ; X64-NEXT: retq %nega = sub i32 32, %a %negasubb = add i32 %nega, %b %shifted = lshr i32 %val, %negasubb ret i32 %shifted } define i64 @reg64_lshr_by_add_to_negated(i64 %val, i64 %a, i64 %b) nounwind { ; X32-LABEL: reg64_lshr_by_add_to_negated: ; X32: # %bb.0: ; X32-NEXT: pushl %esi ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movl {{[0-9]+}}(%esp), %esi ; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx ; X32-NEXT: subl {{[0-9]+}}(%esp), %ecx ; X32-NEXT: addb $64, %cl ; X32-NEXT: movl %esi, %edx ; X32-NEXT: shrl %cl, %edx ; X32-NEXT: shrdl %cl, %esi, %eax ; X32-NEXT: testb $32, %cl ; X32-NEXT: je .LBB29_2 ; X32-NEXT: # %bb.1: ; X32-NEXT: movl %edx, %eax ; X32-NEXT: xorl %edx, %edx ; X32-NEXT: .LBB29_2: ; X32-NEXT: popl %esi ; X32-NEXT: retl ; ; X64-LABEL: reg64_lshr_by_add_to_negated: ; X64: # %bb.0: ; X64-NEXT: movq %rdx, %rcx ; X64-NEXT: movq %rdi, %rax ; X64-NEXT: subl %esi, %ecx ; X64-NEXT: # kill: def $cl killed $cl killed $rcx ; X64-NEXT: shrq %cl, %rax ; X64-NEXT: retq %nega = sub i64 64, %a %negasubb = add i64 %nega, %b %shifted = lshr i64 %val, %negasubb ret i64 %shifted } ;==============================================================================; ; subtraction of negated shift amounts define i32 @reg32_lshr_by_sub_of_negated_amts(i32 %val, i32 %a, i32 %b) nounwind { ; X32-LABEL: reg32_lshr_by_sub_of_negated_amts: ; X32: # %bb.0: ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx ; X32-NEXT: subl {{[0-9]+}}(%esp), %ecx ; X32-NEXT: # kill: def $cl killed $cl killed $ecx ; X32-NEXT: shrl %cl, %eax ; X32-NEXT: retl ; ; X64-LABEL: reg32_lshr_by_sub_of_negated_amts: ; X64: # %bb.0: ; X64-NEXT: movl %edx, %ecx ; X64-NEXT: movl %edi, %eax ; X64-NEXT: subl %esi, %ecx ; X64-NEXT: # kill: def $cl killed $cl killed $ecx ; X64-NEXT: shrl %cl, %eax ; X64-NEXT: retq %nega = sub i32 32, %a %negb = sub i32 32, %b %negasubnegb = sub i32 %nega, %negb %shifted = lshr i32 %val, %negasubnegb ret i32 %shifted } define i64 @reg64_lshr_by_sub_of_negated_amts(i64 %val, i64 %a, i64 %b) nounwind { ; X32-LABEL: reg64_lshr_by_sub_of_negated_amts: ; X32: # %bb.0: ; X32-NEXT: pushl %esi ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movl {{[0-9]+}}(%esp), %esi ; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx ; X32-NEXT: subl {{[0-9]+}}(%esp), %ecx ; X32-NEXT: movl %esi, %edx ; X32-NEXT: shrl %cl, %edx ; X32-NEXT: shrdl %cl, %esi, %eax ; X32-NEXT: testb $32, %cl ; X32-NEXT: je .LBB31_2 ; X32-NEXT: # %bb.1: ; X32-NEXT: movl %edx, %eax ; X32-NEXT: xorl %edx, %edx ; X32-NEXT: .LBB31_2: ; X32-NEXT: popl %esi ; X32-NEXT: retl ; ; X64-LABEL: reg64_lshr_by_sub_of_negated_amts: ; X64: # %bb.0: ; X64-NEXT: movq %rdx, %rcx ; X64-NEXT: movq %rdi, %rax ; X64-NEXT: subl %esi, %ecx ; X64-NEXT: # kill: def $cl killed $cl killed $rcx ; X64-NEXT: shrq %cl, %rax ; X64-NEXT: retq %nega = sub i64 64, %a %negb = sub i64 64, %b %negasubnegb = sub i64 %nega, %negb %shifted = lshr i64 %val, %negasubnegb ret i64 %shifted } ;==============================================================================; ; addition of negated shift amounts define i32 @reg32_lshr_by_add_of_negated_amts(i32 %val, i32 %a, i32 %b) nounwind { ; X32-LABEL: reg32_lshr_by_add_of_negated_amts: ; X32: # %bb.0: ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx ; X32-NEXT: addl {{[0-9]+}}(%esp), %ecx ; X32-NEXT: negb %cl ; X32-NEXT: # kill: def $cl killed $cl killed $ecx ; X32-NEXT: shrl %cl, %eax ; X32-NEXT: retl ; ; X64-LABEL: reg32_lshr_by_add_of_negated_amts: ; X64: # %bb.0: ; X64-NEXT: # kill: def $edx killed $edx def $rdx ; X64-NEXT: # kill: def $esi killed $esi def $rsi ; X64-NEXT: movl %edi, %eax ; X64-NEXT: leal (%rsi,%rdx), %ecx ; X64-NEXT: negb %cl ; X64-NEXT: # kill: def $cl killed $cl killed $ecx ; X64-NEXT: shrl %cl, %eax ; X64-NEXT: retq %nega = sub i32 32, %a %negb = sub i32 32, %b %negasubnegb = add i32 %nega, %negb %shifted = lshr i32 %val, %negasubnegb ret i32 %shifted } define i64 @reg64_lshr_by_add_of_negated_amts(i64 %val, i64 %a, i64 %b) nounwind { ; X32-LABEL: reg64_lshr_by_add_of_negated_amts: ; X32: # %bb.0: ; X32-NEXT: pushl %esi ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movl {{[0-9]+}}(%esp), %esi ; X32-NEXT: movl {{[0-9]+}}(%esp), %edx ; X32-NEXT: addl {{[0-9]+}}(%esp), %edx ; X32-NEXT: movb $-128, %cl ; X32-NEXT: subb %dl, %cl ; X32-NEXT: movl %esi, %edx ; X32-NEXT: shrl %cl, %edx ; X32-NEXT: shrdl %cl, %esi, %eax ; X32-NEXT: testb $32, %cl ; X32-NEXT: je .LBB33_2 ; X32-NEXT: # %bb.1: ; X32-NEXT: movl %edx, %eax ; X32-NEXT: xorl %edx, %edx ; X32-NEXT: .LBB33_2: ; X32-NEXT: popl %esi ; X32-NEXT: retl ; ; X64-LABEL: reg64_lshr_by_add_of_negated_amts: ; X64: # %bb.0: ; X64-NEXT: movq %rdi, %rax ; X64-NEXT: leal (%rdx,%rsi), %ecx ; X64-NEXT: negb %cl ; X64-NEXT: # kill: def $cl killed $cl killed $ecx ; X64-NEXT: shrq %cl, %rax ; X64-NEXT: retq %nega = sub i64 64, %a %negb = sub i64 64, %b %negasubnegb = add i64 %nega, %negb %shifted = lshr i64 %val, %negasubnegb ret i64 %shifted } ;==============================================================================; ; and patterns with an actual negation+addition define i32 @reg32_lshr_by_negated_unfolded(i32 %val, i32 %shamt) nounwind { ; X32-LABEL: reg32_lshr_by_negated_unfolded: ; X32: # %bb.0: ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: xorl %ecx, %ecx ; X32-NEXT: subb {{[0-9]+}}(%esp), %cl ; X32-NEXT: # kill: def $cl killed $cl killed $ecx ; X32-NEXT: shrl %cl, %eax ; X32-NEXT: retl ; ; X64-LABEL: reg32_lshr_by_negated_unfolded: ; X64: # %bb.0: ; X64-NEXT: movl %esi, %ecx ; X64-NEXT: movl %edi, %eax ; X64-NEXT: negb %cl ; X64-NEXT: # kill: def $cl killed $cl killed $ecx ; X64-NEXT: shrl %cl, %eax ; X64-NEXT: retq %negshamt = sub i32 0, %shamt %negaaddbitwidth = add i32 %negshamt, 32 %shifted = lshr i32 %val, %negaaddbitwidth ret i32 %shifted } define i64 @reg64_lshr_by_negated_unfolded(i64 %val, i64 %shamt) nounwind { ; X32-LABEL: reg64_lshr_by_negated_unfolded: ; X32: # %bb.0: ; X32-NEXT: pushl %esi ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movl {{[0-9]+}}(%esp), %esi ; X32-NEXT: movb $64, %cl ; X32-NEXT: subb {{[0-9]+}}(%esp), %cl ; X32-NEXT: movl %esi, %edx ; X32-NEXT: shrl %cl, %edx ; X32-NEXT: shrdl %cl, %esi, %eax ; X32-NEXT: testb $32, %cl ; X32-NEXT: je .LBB35_2 ; X32-NEXT: # %bb.1: ; X32-NEXT: movl %edx, %eax ; X32-NEXT: xorl %edx, %edx ; X32-NEXT: .LBB35_2: ; X32-NEXT: popl %esi ; X32-NEXT: retl ; ; X64-LABEL: reg64_lshr_by_negated_unfolded: ; X64: # %bb.0: ; X64-NEXT: movq %rsi, %rcx ; X64-NEXT: movq %rdi, %rax ; X64-NEXT: negb %cl ; X64-NEXT: # kill: def $cl killed $cl killed $rcx ; X64-NEXT: shrq %cl, %rax ; X64-NEXT: retq %negshamt = sub i64 0, %shamt %negaaddbitwidth = add i64 %negshamt, 64 %shifted = lshr i64 %val, %negaaddbitwidth ret i64 %shifted } define i32 @reg32_lshr_by_negated_unfolded_sub_b(i32 %val, i32 %a, i32 %b) nounwind { ; X32-LABEL: reg32_lshr_by_negated_unfolded_sub_b: ; X32: # %bb.0: ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx ; X32-NEXT: addl {{[0-9]+}}(%esp), %ecx ; X32-NEXT: negb %cl ; X32-NEXT: # kill: def $cl killed $cl killed $ecx ; X32-NEXT: shrl %cl, %eax ; X32-NEXT: retl ; ; X64-LABEL: reg32_lshr_by_negated_unfolded_sub_b: ; X64: # %bb.0: ; X64-NEXT: # kill: def $edx killed $edx def $rdx ; X64-NEXT: # kill: def $esi killed $esi def $rsi ; X64-NEXT: movl %edi, %eax ; X64-NEXT: leal (%rsi,%rdx), %ecx ; X64-NEXT: negb %cl ; X64-NEXT: # kill: def $cl killed $cl killed $ecx ; X64-NEXT: shrl %cl, %eax ; X64-NEXT: retq %nega = sub i32 0, %a %negaaddbitwidth = add i32 %nega, 32 %negaaddbitwidthsubb = sub i32 %negaaddbitwidth, %b %shifted = lshr i32 %val, %negaaddbitwidthsubb ret i32 %shifted } define i64 @reg64_lshr_by_negated_unfolded_sub_b(i64 %val, i64 %a, i64 %b) nounwind { ; X32-LABEL: reg64_lshr_by_negated_unfolded_sub_b: ; X32: # %bb.0: ; X32-NEXT: pushl %esi ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movl {{[0-9]+}}(%esp), %esi ; X32-NEXT: movl {{[0-9]+}}(%esp), %edx ; X32-NEXT: addl {{[0-9]+}}(%esp), %edx ; X32-NEXT: movb $64, %cl ; X32-NEXT: subb %dl, %cl ; X32-NEXT: movl %esi, %edx ; X32-NEXT: shrl %cl, %edx ; X32-NEXT: shrdl %cl, %esi, %eax ; X32-NEXT: testb $32, %cl ; X32-NEXT: je .LBB37_2 ; X32-NEXT: # %bb.1: ; X32-NEXT: movl %edx, %eax ; X32-NEXT: xorl %edx, %edx ; X32-NEXT: .LBB37_2: ; X32-NEXT: popl %esi ; X32-NEXT: retl ; ; X64-LABEL: reg64_lshr_by_negated_unfolded_sub_b: ; X64: # %bb.0: ; X64-NEXT: movq %rdi, %rax ; X64-NEXT: leal (%rdx,%rsi), %ecx ; X64-NEXT: negb %cl ; X64-NEXT: # kill: def $cl killed $cl killed $ecx ; X64-NEXT: shrq %cl, %rax ; X64-NEXT: retq %nega = sub i64 0, %a %negaaddbitwidth = add i64 %nega, 64 %negaaddbitwidthsubb = sub i64 %negaaddbitwidth, %b %shifted = lshr i64 %val, %negaaddbitwidthsubb ret i64 %shifted } define i32 @reg32_lshr_by_b_sub_negated_unfolded(i32 %val, i32 %a, i32 %b) nounwind { ; X32-LABEL: reg32_lshr_by_b_sub_negated_unfolded: ; X32: # %bb.0: ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx ; X32-NEXT: addl {{[0-9]+}}(%esp), %ecx ; X32-NEXT: # kill: def $cl killed $cl killed $ecx ; X32-NEXT: shrl %cl, %eax ; X32-NEXT: retl ; ; X64-LABEL: reg32_lshr_by_b_sub_negated_unfolded: ; X64: # %bb.0: ; X64-NEXT: # kill: def $edx killed $edx def $rdx ; X64-NEXT: # kill: def $esi killed $esi def $rsi ; X64-NEXT: movl %edi, %eax ; X64-NEXT: leal (%rsi,%rdx), %ecx ; X64-NEXT: # kill: def $cl killed $cl killed $ecx ; X64-NEXT: shrl %cl, %eax ; X64-NEXT: retq %nega = sub i32 0, %a %negaaddbitwidth = add i32 %nega, 32 %negaaddbitwidthsubb = sub i32 %b, %negaaddbitwidth %shifted = lshr i32 %val, %negaaddbitwidthsubb ret i32 %shifted } define i64 @reg64_lshr_by_b_sub_negated_unfolded(i64 %val, i64 %a, i64 %b) nounwind { ; X32-LABEL: reg64_lshr_by_b_sub_negated_unfolded: ; X32: # %bb.0: ; X32-NEXT: pushl %esi ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movl {{[0-9]+}}(%esp), %esi ; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx ; X32-NEXT: addl {{[0-9]+}}(%esp), %ecx ; X32-NEXT: addb $-64, %cl ; X32-NEXT: movl %esi, %edx ; X32-NEXT: shrl %cl, %edx ; X32-NEXT: shrdl %cl, %esi, %eax ; X32-NEXT: testb $32, %cl ; X32-NEXT: je .LBB39_2 ; X32-NEXT: # %bb.1: ; X32-NEXT: movl %edx, %eax ; X32-NEXT: xorl %edx, %edx ; X32-NEXT: .LBB39_2: ; X32-NEXT: popl %esi ; X32-NEXT: retl ; ; X64-LABEL: reg64_lshr_by_b_sub_negated_unfolded: ; X64: # %bb.0: ; X64-NEXT: movq %rdi, %rax ; X64-NEXT: leal (%rdx,%rsi), %ecx ; X64-NEXT: # kill: def $cl killed $cl killed $ecx ; X64-NEXT: shrq %cl, %rax ; X64-NEXT: retq %nega = sub i64 0, %a %negaaddbitwidth = add i64 %nega, 64 %negaaddbitwidthsubb = sub i64 %b, %negaaddbitwidth %shifted = lshr i64 %val, %negaaddbitwidthsubb ret i64 %shifted } define i32 @reg32_lshr_by_negated_unfolded_add_b(i32 %val, i32 %a, i32 %b) nounwind { ; X32-LABEL: reg32_lshr_by_negated_unfolded_add_b: ; X32: # %bb.0: ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx ; X32-NEXT: subl {{[0-9]+}}(%esp), %ecx ; X32-NEXT: # kill: def $cl killed $cl killed $ecx ; X32-NEXT: shrl %cl, %eax ; X32-NEXT: retl ; ; X64-LABEL: reg32_lshr_by_negated_unfolded_add_b: ; X64: # %bb.0: ; X64-NEXT: movl %edx, %ecx ; X64-NEXT: movl %edi, %eax ; X64-NEXT: subl %esi, %ecx ; X64-NEXT: # kill: def $cl killed $cl killed $ecx ; X64-NEXT: shrl %cl, %eax ; X64-NEXT: retq %nega = sub i32 0, %a %negaaddbitwidth = add i32 %nega, 32 %negaaddbitwidthaddb = add i32 %negaaddbitwidth, %b %shifted = lshr i32 %val, %negaaddbitwidthaddb ret i32 %shifted } define i64 @reg64_lshr_by_negated_unfolded_add_b(i64 %val, i64 %a, i64 %b) nounwind { ; X32-LABEL: reg64_lshr_by_negated_unfolded_add_b: ; X32: # %bb.0: ; X32-NEXT: pushl %esi ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movl {{[0-9]+}}(%esp), %esi ; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx ; X32-NEXT: subl {{[0-9]+}}(%esp), %ecx ; X32-NEXT: addb $64, %cl ; X32-NEXT: movl %esi, %edx ; X32-NEXT: shrl %cl, %edx ; X32-NEXT: shrdl %cl, %esi, %eax ; X32-NEXT: testb $32, %cl ; X32-NEXT: je .LBB41_2 ; X32-NEXT: # %bb.1: ; X32-NEXT: movl %edx, %eax ; X32-NEXT: xorl %edx, %edx ; X32-NEXT: .LBB41_2: ; X32-NEXT: popl %esi ; X32-NEXT: retl ; ; X64-LABEL: reg64_lshr_by_negated_unfolded_add_b: ; X64: # %bb.0: ; X64-NEXT: movq %rdx, %rcx ; X64-NEXT: movq %rdi, %rax ; X64-NEXT: subl %esi, %ecx ; X64-NEXT: # kill: def $cl killed $cl killed $rcx ; X64-NEXT: shrq %cl, %rax ; X64-NEXT: retq %nega = sub i64 0, %a %negaaddbitwidth = add i64 %nega, 64 %negaaddbitwidthaddb = add i64 %negaaddbitwidth, %b %shifted = lshr i64 %val, %negaaddbitwidthaddb ret i64 %shifted } ;==============================================================================; ; and patterns with an actual negation+mask define i32 @reg32_lshr_by_masked_negated_unfolded(i32 %val, i32 %shamt) nounwind { ; X32-LABEL: reg32_lshr_by_masked_negated_unfolded: ; X32: # %bb.0: ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: xorl %ecx, %ecx ; X32-NEXT: subb {{[0-9]+}}(%esp), %cl ; X32-NEXT: # kill: def $cl killed $cl killed $ecx ; X32-NEXT: shrl %cl, %eax ; X32-NEXT: retl ; ; X64-LABEL: reg32_lshr_by_masked_negated_unfolded: ; X64: # %bb.0: ; X64-NEXT: movl %esi, %ecx ; X64-NEXT: movl %edi, %eax ; X64-NEXT: negb %cl ; X64-NEXT: # kill: def $cl killed $cl killed $ecx ; X64-NEXT: shrl %cl, %eax ; X64-NEXT: retq %negshamt = sub i32 0, %shamt %negaaddbitwidth = and i32 %negshamt, 31 %shifted = lshr i32 %val, %negaaddbitwidth ret i32 %shifted } define i64 @reg64_lshr_by_masked_negated_unfolded(i64 %val, i64 %shamt) nounwind { ; X32-LABEL: reg64_lshr_by_masked_negated_unfolded: ; X32: # %bb.0: ; X32-NEXT: pushl %esi ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movl {{[0-9]+}}(%esp), %esi ; X32-NEXT: xorl %ecx, %ecx ; X32-NEXT: movzbl {{[0-9]+}}(%esp), %edx ; X32-NEXT: subb %dl, %cl ; X32-NEXT: movl %esi, %edx ; X32-NEXT: shrl %cl, %edx ; X32-NEXT: shrdl %cl, %esi, %eax ; X32-NEXT: testb $32, %cl ; X32-NEXT: je .LBB43_2 ; X32-NEXT: # %bb.1: ; X32-NEXT: movl %edx, %eax ; X32-NEXT: xorl %edx, %edx ; X32-NEXT: .LBB43_2: ; X32-NEXT: popl %esi ; X32-NEXT: retl ; ; X64-LABEL: reg64_lshr_by_masked_negated_unfolded: ; X64: # %bb.0: ; X64-NEXT: movq %rsi, %rcx ; X64-NEXT: movq %rdi, %rax ; X64-NEXT: negb %cl ; X64-NEXT: # kill: def $cl killed $cl killed $rcx ; X64-NEXT: shrq %cl, %rax ; X64-NEXT: retq %negshamt = sub i64 0, %shamt %negaaddbitwidth = and i64 %negshamt, 63 %shifted = lshr i64 %val, %negaaddbitwidth ret i64 %shifted } define i32 @reg32_lshr_by_masked_negated_unfolded_sub_b(i32 %val, i32 %a, i32 %b) nounwind { ; X32-LABEL: reg32_lshr_by_masked_negated_unfolded_sub_b: ; X32: # %bb.0: ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: xorl %ecx, %ecx ; X32-NEXT: subl {{[0-9]+}}(%esp), %ecx ; X32-NEXT: andl $31, %ecx ; X32-NEXT: subl {{[0-9]+}}(%esp), %ecx ; X32-NEXT: # kill: def $cl killed $cl killed $ecx ; X32-NEXT: shrl %cl, %eax ; X32-NEXT: retl ; ; X64-LABEL: reg32_lshr_by_masked_negated_unfolded_sub_b: ; X64: # %bb.0: ; X64-NEXT: movl %esi, %ecx ; X64-NEXT: movl %edi, %eax ; X64-NEXT: negl %ecx ; X64-NEXT: andl $31, %ecx ; X64-NEXT: subl %edx, %ecx ; X64-NEXT: # kill: def $cl killed $cl killed $ecx ; X64-NEXT: shrl %cl, %eax ; X64-NEXT: retq %nega = sub i32 0, %a %negaaddbitwidth = and i32 %nega, 31 %negaaddbitwidthsubb = sub i32 %negaaddbitwidth, %b %shifted = lshr i32 %val, %negaaddbitwidthsubb ret i32 %shifted } define i64 @reg64_lshr_by_masked_negated_unfolded_sub_b(i64 %val, i64 %a, i64 %b) nounwind { ; X32-LABEL: reg64_lshr_by_masked_negated_unfolded_sub_b: ; X32: # %bb.0: ; X32-NEXT: pushl %esi ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movl {{[0-9]+}}(%esp), %esi ; X32-NEXT: xorl %ecx, %ecx ; X32-NEXT: subl {{[0-9]+}}(%esp), %ecx ; X32-NEXT: andl $63, %ecx ; X32-NEXT: subl {{[0-9]+}}(%esp), %ecx ; X32-NEXT: movl %esi, %edx ; X32-NEXT: shrl %cl, %edx ; X32-NEXT: shrdl %cl, %esi, %eax ; X32-NEXT: testb $32, %cl ; X32-NEXT: je .LBB45_2 ; X32-NEXT: # %bb.1: ; X32-NEXT: movl %edx, %eax ; X32-NEXT: xorl %edx, %edx ; X32-NEXT: .LBB45_2: ; X32-NEXT: popl %esi ; X32-NEXT: retl ; ; X64-LABEL: reg64_lshr_by_masked_negated_unfolded_sub_b: ; X64: # %bb.0: ; X64-NEXT: movq %rsi, %rcx ; X64-NEXT: movq %rdi, %rax ; X64-NEXT: negl %ecx ; X64-NEXT: andl $63, %ecx ; X64-NEXT: subl %edx, %ecx ; X64-NEXT: # kill: def $cl killed $cl killed $rcx ; X64-NEXT: shrq %cl, %rax ; X64-NEXT: retq %nega = sub i64 0, %a %negaaddbitwidth = and i64 %nega, 63 %negaaddbitwidthsubb = sub i64 %negaaddbitwidth, %b %shifted = lshr i64 %val, %negaaddbitwidthsubb ret i64 %shifted } define i32 @reg32_lshr_by_masked_b_sub_negated_unfolded(i32 %val, i32 %a, i32 %b) nounwind { ; X32-LABEL: reg32_lshr_by_masked_b_sub_negated_unfolded: ; X32: # %bb.0: ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx ; X32-NEXT: xorl %edx, %edx ; X32-NEXT: subl {{[0-9]+}}(%esp), %edx ; X32-NEXT: andl $31, %edx ; X32-NEXT: subl %edx, %ecx ; X32-NEXT: # kill: def $cl killed $cl killed $ecx ; X32-NEXT: shrl %cl, %eax ; X32-NEXT: retl ; ; X64-LABEL: reg32_lshr_by_masked_b_sub_negated_unfolded: ; X64: # %bb.0: ; X64-NEXT: movl %edx, %ecx ; X64-NEXT: movl %edi, %eax ; X64-NEXT: negl %esi ; X64-NEXT: andl $31, %esi ; X64-NEXT: subl %esi, %ecx ; X64-NEXT: # kill: def $cl killed $cl killed $ecx ; X64-NEXT: shrl %cl, %eax ; X64-NEXT: retq %nega = sub i32 0, %a %negaaddbitwidth = and i32 %nega, 31 %negaaddbitwidthsubb = sub i32 %b, %negaaddbitwidth %shifted = lshr i32 %val, %negaaddbitwidthsubb ret i32 %shifted } define i64 @reg64_lshr_by_masked_b_sub_negated_unfolded(i64 %val, i64 %a, i64 %b) nounwind { ; X32-LABEL: reg64_lshr_by_masked_b_sub_negated_unfolded: ; X32: # %bb.0: ; X32-NEXT: pushl %esi ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movl {{[0-9]+}}(%esp), %esi ; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx ; X32-NEXT: xorl %edx, %edx ; X32-NEXT: subl {{[0-9]+}}(%esp), %edx ; X32-NEXT: andl $63, %edx ; X32-NEXT: subl %edx, %ecx ; X32-NEXT: movl %esi, %edx ; X32-NEXT: shrl %cl, %edx ; X32-NEXT: shrdl %cl, %esi, %eax ; X32-NEXT: testb $32, %cl ; X32-NEXT: je .LBB47_2 ; X32-NEXT: # %bb.1: ; X32-NEXT: movl %edx, %eax ; X32-NEXT: xorl %edx, %edx ; X32-NEXT: .LBB47_2: ; X32-NEXT: popl %esi ; X32-NEXT: retl ; ; X64-LABEL: reg64_lshr_by_masked_b_sub_negated_unfolded: ; X64: # %bb.0: ; X64-NEXT: movq %rdx, %rcx ; X64-NEXT: movq %rdi, %rax ; X64-NEXT: negl %esi ; X64-NEXT: andl $63, %esi ; X64-NEXT: subl %esi, %ecx ; X64-NEXT: # kill: def $cl killed $cl killed $rcx ; X64-NEXT: shrq %cl, %rax ; X64-NEXT: retq %nega = sub i64 0, %a %negaaddbitwidth = and i64 %nega, 63 %negaaddbitwidthsubb = sub i64 %b, %negaaddbitwidth %shifted = lshr i64 %val, %negaaddbitwidthsubb ret i64 %shifted } define i32 @reg32_lshr_by_masked_negated_unfolded_add_b(i32 %val, i32 %a, i32 %b) nounwind { ; X32-LABEL: reg32_lshr_by_masked_negated_unfolded_add_b: ; X32: # %bb.0: ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: xorl %ecx, %ecx ; X32-NEXT: subl {{[0-9]+}}(%esp), %ecx ; X32-NEXT: andl $31, %ecx ; X32-NEXT: addl {{[0-9]+}}(%esp), %ecx ; X32-NEXT: # kill: def $cl killed $cl killed $ecx ; X32-NEXT: shrl %cl, %eax ; X32-NEXT: retl ; ; X64-LABEL: reg32_lshr_by_masked_negated_unfolded_add_b: ; X64: # %bb.0: ; X64-NEXT: # kill: def $edx killed $edx def $rdx ; X64-NEXT: # kill: def $esi killed $esi def $rsi ; X64-NEXT: movl %edi, %eax ; X64-NEXT: negl %esi ; X64-NEXT: andl $31, %esi ; X64-NEXT: leal (%rsi,%rdx), %ecx ; X64-NEXT: # kill: def $cl killed $cl killed $ecx ; X64-NEXT: shrl %cl, %eax ; X64-NEXT: retq %nega = sub i32 0, %a %negaaddbitwidth = and i32 %nega, 31 %negaaddbitwidthaddb = add i32 %negaaddbitwidth, %b %shifted = lshr i32 %val, %negaaddbitwidthaddb ret i32 %shifted } define i64 @reg64_lshr_by_masked_negated_unfolded_add_b(i64 %val, i64 %a, i64 %b) nounwind { ; X32-LABEL: reg64_lshr_by_masked_negated_unfolded_add_b: ; X32: # %bb.0: ; X32-NEXT: pushl %esi ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: movl {{[0-9]+}}(%esp), %esi ; X32-NEXT: xorl %ecx, %ecx ; X32-NEXT: subl {{[0-9]+}}(%esp), %ecx ; X32-NEXT: andl $63, %ecx ; X32-NEXT: addl {{[0-9]+}}(%esp), %ecx ; X32-NEXT: movl %esi, %edx ; X32-NEXT: shrl %cl, %edx ; X32-NEXT: shrdl %cl, %esi, %eax ; X32-NEXT: testb $32, %cl ; X32-NEXT: je .LBB49_2 ; X32-NEXT: # %bb.1: ; X32-NEXT: movl %edx, %eax ; X32-NEXT: xorl %edx, %edx ; X32-NEXT: .LBB49_2: ; X32-NEXT: popl %esi ; X32-NEXT: retl ; ; X64-LABEL: reg64_lshr_by_masked_negated_unfolded_add_b: ; X64: # %bb.0: ; X64-NEXT: movq %rdi, %rax ; X64-NEXT: negl %esi ; X64-NEXT: andl $63, %esi ; X64-NEXT: leal (%rdx,%rsi), %ecx ; X64-NEXT: # kill: def $cl killed $cl killed $ecx ; X64-NEXT: shrq %cl, %rax ; X64-NEXT: retq %nega = sub i64 0, %a %negaaddbitwidth = and i64 %nega, 63 %negaaddbitwidthaddb = add i64 %negaaddbitwidth, %b %shifted = lshr i64 %val, %negaaddbitwidthaddb ret i64 %shifted } define i16 @sh_trunc_sh(i64 %x) { ; X32-LABEL: sh_trunc_sh: ; X32: # %bb.0: ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: shrl $4, %eax ; X32-NEXT: andl $15, %eax ; X32-NEXT: # kill: def $ax killed $ax killed $eax ; X32-NEXT: retl ; ; X64-LABEL: sh_trunc_sh: ; X64: # %bb.0: ; X64-NEXT: movq %rdi, %rax ; X64-NEXT: shrq $36, %rax ; X64-NEXT: andl $15, %eax ; X64-NEXT: # kill: def $ax killed $ax killed $rax ; X64-NEXT: retq %s = lshr i64 %x, 24 %t = trunc i64 %s to i16 %r = lshr i16 %t, 12 ret i16 %r }