summaryrefslogtreecommitdiff
path: root/test/CodeGen/X86/urem-power-of-two.ll
blob: 2610beda415f83bcf95824aae1abc6c66e15974f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc < %s -mtriple=i686-unknown-unknown -mattr=+sse2 | FileCheck %s --check-prefix=X86
; RUN: llc < %s -mtriple=x86_64-unknown-unknown | FileCheck %s --check-prefix=X64

; The easy case: a constant power-of-2 divisor.

define i64 @const_pow_2(i64 %x) {
; X86-LABEL: const_pow_2:
; X86:       # %bb.0:
; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
; X86-NEXT:    andl $31, %eax
; X86-NEXT:    xorl %edx, %edx
; X86-NEXT:    retl
;
; X64-LABEL: const_pow_2:
; X64:       # %bb.0:
; X64-NEXT:    andl $31, %edi
; X64-NEXT:    movq %rdi, %rax
; X64-NEXT:    retq
  %urem = urem i64 %x, 32
  ret i64 %urem
}

; A left-shifted power-of-2 divisor. Use a weird type for wider coverage.

define i25 @shift_left_pow_2(i25 %x, i25 %y) {
; X86-LABEL: shift_left_pow_2:
; X86:       # %bb.0:
; X86-NEXT:    movb {{[0-9]+}}(%esp), %cl
; X86-NEXT:    movl $1, %eax
; X86-NEXT:    shll %cl, %eax
; X86-NEXT:    addl $33554431, %eax # imm = 0x1FFFFFF
; X86-NEXT:    andl {{[0-9]+}}(%esp), %eax
; X86-NEXT:    retl
;
; X64-LABEL: shift_left_pow_2:
; X64:       # %bb.0:
; X64-NEXT:    movl $1, %eax
; X64-NEXT:    movl %esi, %ecx
; X64-NEXT:    shll %cl, %eax
; X64-NEXT:    addl $33554431, %eax # imm = 0x1FFFFFF
; X64-NEXT:    andl %edi, %eax
; X64-NEXT:    retq
  %shl = shl i25 1, %y
  %urem = urem i25 %x, %shl
  ret i25 %urem
}

; A logically right-shifted sign bit is a power-of-2 or UB.

define i16 @shift_right_pow_2(i16 %x, i16 %y) {
; X86-LABEL: shift_right_pow_2:
; X86:       # %bb.0:
; X86-NEXT:    movb {{[0-9]+}}(%esp), %cl
; X86-NEXT:    movl $32768, %eax # imm = 0x8000
; X86-NEXT:    shrl %cl, %eax
; X86-NEXT:    decl %eax
; X86-NEXT:    andw {{[0-9]+}}(%esp), %ax
; X86-NEXT:    # kill: def %ax killed %ax killed %eax
; X86-NEXT:    retl
;
; X64-LABEL: shift_right_pow_2:
; X64:       # %bb.0:
; X64-NEXT:    movl $32768, %eax # imm = 0x8000
; X64-NEXT:    movl %esi, %ecx
; X64-NEXT:    shrl %cl, %eax
; X64-NEXT:    decl %eax
; X64-NEXT:    andl %edi, %eax
; X64-NEXT:    # kill: def %ax killed %ax killed %eax
; X64-NEXT:    retq
  %shr = lshr i16 -32768, %y
  %urem = urem i16 %x, %shr
  ret i16 %urem
}

; FIXME: A zero divisor would be UB, so this could be reduced to an 'and' with 3.

define i8 @and_pow_2(i8 %x, i8 %y) {
; X86-LABEL: and_pow_2:
; X86:       # %bb.0:
; X86-NEXT:    movb {{[0-9]+}}(%esp), %cl
; X86-NEXT:    andb $4, %cl
; X86-NEXT:    movzbl {{[0-9]+}}(%esp), %eax
; X86-NEXT:    # kill: def %eax killed %eax def %ax
; X86-NEXT:    divb %cl
; X86-NEXT:    movzbl %ah, %eax # NOREX
; X86-NEXT:    # kill: def %al killed %al killed %eax
; X86-NEXT:    retl
;
; X64-LABEL: and_pow_2:
; X64:       # %bb.0:
; X64-NEXT:    andb $4, %sil
; X64-NEXT:    movzbl %dil, %eax
; X64-NEXT:    # kill: def %eax killed %eax def %ax
; X64-NEXT:    divb %sil
; X64-NEXT:    movzbl %ah, %eax # NOREX
; X64-NEXT:    # kill: def %al killed %al killed %eax
; X64-NEXT:    retq
  %and = and i8 %y, 4
  %urem = urem i8 %x, %and
  ret i8 %urem
}

; A vector constant divisor should get the same treatment as a scalar.

define <4 x i32> @vec_const_uniform_pow_2(<4 x i32> %x) {
; X86-LABEL: vec_const_uniform_pow_2:
; X86:       # %bb.0:
; X86-NEXT:    andps {{\.LCPI.*}}, %xmm0
; X86-NEXT:    retl
;
; X64-LABEL: vec_const_uniform_pow_2:
; X64:       # %bb.0:
; X64-NEXT:    andps {{.*}}(%rip), %xmm0
; X64-NEXT:    retq
  %urem = urem <4 x i32> %x, <i32 16, i32 16, i32 16, i32 16>
  ret <4 x i32> %urem
}

define <4 x i32> @vec_const_nonuniform_pow_2(<4 x i32> %x) {
; X86-LABEL: vec_const_nonuniform_pow_2:
; X86:       # %bb.0:
; X86-NEXT:    andps {{\.LCPI.*}}, %xmm0
; X86-NEXT:    retl
;
; X64-LABEL: vec_const_nonuniform_pow_2:
; X64:       # %bb.0:
; X64-NEXT:    andps {{.*}}(%rip), %xmm0
; X64-NEXT:    retq
  %urem = urem <4 x i32> %x, <i32 2, i32 4, i32 8, i32 16>
  ret <4 x i32> %urem
}