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: movq %rdi, %rax
; X64-NEXT: andl $31, %eax
; 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 %esi, %ecx
; X64-NEXT: movl $1, %eax
; X64-NEXT: # kill: def $cl killed $cl killed $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 %esi, %ecx
; X64-NEXT: movl $32768, %eax # imm = 0x8000
; X64-NEXT: # kill: def $cl killed $cl killed $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: divb %cl
; X86-NEXT: movzbl %ah, %eax
; 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: divb %sil
; X64-NEXT: movzbl %ah, %eax
; 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
}
|