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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
|
; Test insertions of i32s into the low half of an i64.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Insertion of an i32 can be done using LR.
define i64 @f1(i64 %a, i32 %b) {
; CHECK-LABEL: f1:
; CHECK-NOT: {{%r[23]}}
; CHECK: lr %r2, %r3
; CHECK: br %r14
%low = zext i32 %b to i64
%high = and i64 %a, -4294967296
%res = or i64 %high, %low
ret i64 %res
}
; ... and again with the operands reversed.
define i64 @f2(i64 %a, i32 %b) {
; CHECK-LABEL: f2:
; CHECK-NOT: {{%r[23]}}
; CHECK: lr %r2, %r3
; CHECK: br %r14
%low = zext i32 %b to i64
%high = and i64 %a, -4294967296
%res = or i64 %low, %high
ret i64 %res
}
; Like f1, but with "in register" zero extension.
define i64 @f3(i64 %a, i64 %b) {
; CHECK-LABEL: f3:
; CHECK-NOT: {{%r[23]}}
; CHECK: lr %r2, %r3
; CHECK: br %r14
%low = and i64 %b, 4294967295
%high = and i64 %a, -4294967296
%res = or i64 %high, %low
ret i64 %res
}
; ... and again with the operands reversed.
define i64 @f4(i64 %a, i64 %b) {
; CHECK-LABEL: f4:
; CHECK-NOT: {{%r[23]}}
; CHECK: lr %r2, %r3
; CHECK: br %r14
%low = and i64 %b, 4294967295
%high = and i64 %a, -4294967296
%res = or i64 %low, %high
ret i64 %res
}
; Unary operations can be done directly into the low half.
define i64 @f5(i64 %a, i32 %b) {
; CHECK-LABEL: f5:
; CHECK-NOT: {{%r[23]}}
; CHECK: lcr %r2, %r3
; CHECK: br %r14
%neg = sub i32 0, %b
%low = zext i32 %neg to i64
%high = and i64 %a, -4294967296
%res = or i64 %high, %low
ret i64 %res
}
; ...likewise three-operand binary operations like RLL.
define i64 @f6(i64 %a, i32 %b) {
; CHECK-LABEL: f6:
; CHECK-NOT: {{%r[23]}}
; CHECK: rll %r2, %r3, 1
; CHECK: br %r14
%parta = shl i32 %b, 1
%partb = lshr i32 %b, 31
%rot = or i32 %parta, %partb
%low = zext i32 %rot to i64
%high = and i64 %a, -4294967296
%res = or i64 %low, %high
ret i64 %res
}
; Loads can be done directly into the low half. The range of L is checked
; in the move tests.
define i64 @f7(i64 %a, i32 *%src) {
; CHECK-LABEL: f7:
; CHECK-NOT: {{%r[23]}}
; CHECK: l %r2, 0(%r3)
; CHECK: br %r14
%b = load i32 *%src
%low = zext i32 %b to i64
%high = and i64 %a, -4294967296
%res = or i64 %high, %low
ret i64 %res
}
; ...likewise extending loads.
define i64 @f8(i64 %a, i8 *%src) {
; CHECK-LABEL: f8:
; CHECK-NOT: {{%r[23]}}
; CHECK: lb %r2, 0(%r3)
; CHECK: br %r14
%byte = load i8 *%src
%b = sext i8 %byte to i32
%low = zext i32 %b to i64
%high = and i64 %a, -4294967296
%res = or i64 %high, %low
ret i64 %res
}
; Check a case like f1 in which there is no AND. We simply know from context
; that the upper half of one OR operand and the lower half of the other are
; both clear.
define i64 @f9(i64 %a, i32 %b) {
; CHECK-LABEL: f9:
; CHECK: sllg %r2, %r2, 32
; CHECK: lr %r2, %r3
; CHECK: br %r14
%shift = shl i64 %a, 32
%low = zext i32 %b to i64
%or = or i64 %shift, %low
ret i64 %or
}
; ...and again with the operands reversed.
define i64 @f10(i64 %a, i32 %b) {
; CHECK-LABEL: f10:
; CHECK: sllg %r2, %r2, 32
; CHECK: lr %r2, %r3
; CHECK: br %r14
%shift = shl i64 %a, 32
%low = zext i32 %b to i64
%or = or i64 %low, %shift
ret i64 %or
}
; Like f9, but with "in register" zero extension.
define i64 @f11(i64 %a, i64 %b) {
; CHECK-LABEL: f11:
; CHECK: lr %r2, %r3
; CHECK: br %r14
%shift = shl i64 %a, 32
%low = and i64 %b, 4294967295
%or = or i64 %shift, %low
ret i64 %or
}
; ...and again with the operands reversed.
define i64 @f12(i64 %a, i64 %b) {
; CHECK-LABEL: f12:
; CHECK: lr %r2, %r3
; CHECK: br %r14
%shift = shl i64 %a, 32
%low = and i64 %b, 4294967295
%or = or i64 %low, %shift
ret i64 %or
}
; Like f9, but for larger shifts than 32.
define i64 @f13(i64 %a, i32 %b) {
; CHECK-LABEL: f13:
; CHECK: sllg %r2, %r2, 60
; CHECK: lr %r2, %r3
; CHECK: br %r14
%shift = shl i64 %a, 60
%low = zext i32 %b to i64
%or = or i64 %shift, %low
ret i64 %or
}
; We previously wrongly removed the upper AND as dead.
define i64 @f14(i64 %a, i64 %b) {
; CHECK-LABEL: f14:
; CHECK: risbg {{%r[0-5]}}, %r2, 6, 134, 0
; CHECK: br %r14
%and1 = and i64 %a, 144115188075855872
%and2 = and i64 %b, 15
%or = or i64 %and1, %and2
%res = icmp eq i64 %or, 0
%ext = sext i1 %res to i64
ret i64 %ext
}
; Check another representation of f8.
define i64 @f15(i64 %a, i8 *%src) {
; CHECK-LABEL: f15:
; CHECK-NOT: {{%r[23]}}
; CHECK: lb %r2, 0(%r3)
; CHECK: br %r14
%byte = load i8 *%src
%b = sext i8 %byte to i64
%low = and i64 %b, 4294967295
%high = and i64 %a, -4294967296
%res = or i64 %high, %low
ret i64 %res
}
|