aboutsummaryrefslogtreecommitdiffstats
path: root/test/CodeGen/SystemZ/int-sub-06.ll
blob: c26383e9df03b1426c05e6e9fb652ae213a3d3dd (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
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
; Test 128-bit addition in which the second operand is a zero-extended i32.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s

; Check register additions.  The XOR ensures that we don't instead zero-extend
; %b into a register and use memory addition.
define void @f1(i128 *%aptr, i32 %b) {
; CHECK-LABEL: f1:
; CHECK: slgfr {{%r[0-5]}}, %r3
; CHECK: slbgr
; CHECK: br %r14
  %a = load i128 , i128 *%aptr
  %xor = xor i128 %a, 127
  %bext = zext i32 %b to i128
  %sub = sub i128 %xor, %bext
  store i128 %sub, i128 *%aptr
  ret void
}

; Like f1, but using an "in-register" extension.
define void @f2(i128 *%aptr, i64 %b) {
; CHECK-LABEL: f2:
; CHECK: slgfr {{%r[0-5]}}, %r3
; CHECK: slbgr
; CHECK: br %r14
  %a = load i128 , i128 *%aptr
  %xor = xor i128 %a, 127
  %trunc = trunc i64 %b to i32
  %bext = zext i32 %trunc to i128
  %sub = sub i128 %xor, %bext
  store i128 %sub, i128 *%aptr
  ret void
}

; Test register addition in cases where the second operand is zero extended
; from i64 rather than i32, but is later masked to i32 range.
define void @f3(i128 *%aptr, i64 %b) {
; CHECK-LABEL: f3:
; CHECK: slgfr {{%r[0-5]}}, %r3
; CHECK: slbgr
; CHECK: br %r14
  %a = load i128 , i128 *%aptr
  %xor = xor i128 %a, 127
  %bext = zext i64 %b to i128
  %and = and i128 %bext, 4294967295
  %sub = sub i128 %xor, %and
  store i128 %sub, i128 *%aptr
  ret void
}

; Test SLGF with no offset.
define void @f4(i128 *%aptr, i32 *%bsrc) {
; CHECK-LABEL: f4:
; CHECK: slgf {{%r[0-5]}}, 0(%r3)
; CHECK: slbgr
; CHECK: br %r14
  %a = load i128 , i128 *%aptr
  %xor = xor i128 %a, 127
  %b = load i32 , i32 *%bsrc
  %bext = zext i32 %b to i128
  %sub = sub i128 %xor, %bext
  store i128 %sub, i128 *%aptr
  ret void
}

; Check the high end of the SLGF range.
define void @f5(i128 *%aptr, i32 *%bsrc) {
; CHECK-LABEL: f5:
; CHECK: slgf {{%r[0-5]}}, 524284(%r3)
; CHECK: slbgr
; CHECK: br %r14
  %a = load i128 , i128 *%aptr
  %xor = xor i128 %a, 127
  %ptr = getelementptr i32, i32 *%bsrc, i64 131071
  %b = load i32 , i32 *%ptr
  %bext = zext i32 %b to i128
  %sub = sub i128 %xor, %bext
  store i128 %sub, i128 *%aptr
  ret void
}

; Check the next word up, which must use separate address logic.
; Other sequences besides this one would be OK.
define void @f6(i128 *%aptr, i32 *%bsrc) {
; CHECK-LABEL: f6:
; CHECK: agfi %r3, 524288
; CHECK: slgf {{%r[0-5]}}, 0(%r3)
; CHECK: slbgr
; CHECK: br %r14
  %a = load i128 , i128 *%aptr
  %xor = xor i128 %a, 127
  %ptr = getelementptr i32, i32 *%bsrc, i64 131072
  %b = load i32 , i32 *%ptr
  %bext = zext i32 %b to i128
  %sub = sub i128 %xor, %bext
  store i128 %sub, i128 *%aptr
  ret void
}

; Check the high end of the negative aligned SLGF range.
define void @f7(i128 *%aptr, i32 *%bsrc) {
; CHECK-LABEL: f7:
; CHECK: slgf {{%r[0-5]}}, -4(%r3)
; CHECK: slbgr
; CHECK: br %r14
  %a = load i128 , i128 *%aptr
  %xor = xor i128 %a, 127
  %ptr = getelementptr i32, i32 *%bsrc, i128 -1
  %b = load i32 , i32 *%ptr
  %bext = zext i32 %b to i128
  %sub = sub i128 %xor, %bext
  store i128 %sub, i128 *%aptr
  ret void
}

; Check the low end of the SLGF range.
define void @f8(i128 *%aptr, i32 *%bsrc) {
; CHECK-LABEL: f8:
; CHECK: slgf {{%r[0-5]}}, -524288(%r3)
; CHECK: slbgr
; CHECK: br %r14
  %a = load i128 , i128 *%aptr
  %xor = xor i128 %a, 127
  %ptr = getelementptr i32, i32 *%bsrc, i128 -131072
  %b = load i32 , i32 *%ptr
  %bext = zext i32 %b to i128
  %sub = sub i128 %xor, %bext
  store i128 %sub, i128 *%aptr
  ret void
}

; Check the next word down, which needs separate address logic.
; Other sequences besides this one would be OK.
define void @f9(i128 *%aptr, i32 *%bsrc) {
; CHECK-LABEL: f9:
; CHECK: agfi %r3, -524292
; CHECK: slgf {{%r[0-5]}}, 0(%r3)
; CHECK: slbgr
; CHECK: br %r14
  %a = load i128 , i128 *%aptr
  %xor = xor i128 %a, 127
  %ptr = getelementptr i32, i32 *%bsrc, i128 -131073
  %b = load i32 , i32 *%ptr
  %bext = zext i32 %b to i128
  %sub = sub i128 %xor, %bext
  store i128 %sub, i128 *%aptr
  ret void
}

; Check that SLGF allows an index.
define void @f10(i128 *%aptr, i64 %src, i64 %index) {
; CHECK-LABEL: f10:
; CHECK: slgf {{%r[0-5]}}, 524284({{%r4,%r3|%r3,%r4}})
; CHECK: br %r14
  %a = load i128 , i128 *%aptr
  %xor = xor i128 %a, 127
  %add1 = add i64 %src, %index
  %add2 = add i64 %add1, 524284
  %ptr = inttoptr i64 %add2 to i32 *
  %b = load i32 , i32 *%ptr
  %bext = zext i32 %b to i128
  %sub = sub i128 %xor, %bext
  store i128 %sub, i128 *%aptr
  ret void
}