1 ; RUN: llc -mtriple=arm64-linux-gnu -verify-machineinstrs -mcpu=cyclone -aarch64-enable-atomic-cfg-tidy=0 < %s | FileCheck -enable-var-scope %s
3 @lhs = global fp128 zeroinitializer, align 16
4 @rhs = global fp128 zeroinitializer, align 16
6 define fp128 @test_add() {
7 ; CHECK-LABEL: test_add:
9 %lhs = load fp128, fp128* @lhs, align 16
10 %rhs = load fp128, fp128* @rhs, align 16
11 ; CHECK: ldr q0, [{{x[0-9]+}}, :lo12:lhs]
12 ; CHECK: ldr q1, [{{x[0-9]+}}, :lo12:rhs]
14 %val = fadd fp128 %lhs, %rhs
19 define fp128 @test_sub() {
20 ; CHECK-LABEL: test_sub:
22 %lhs = load fp128, fp128* @lhs, align 16
23 %rhs = load fp128, fp128* @rhs, align 16
24 ; CHECK: ldr q0, [{{x[0-9]+}}, :lo12:lhs]
25 ; CHECK: ldr q1, [{{x[0-9]+}}, :lo12:rhs]
27 %val = fsub fp128 %lhs, %rhs
32 define fp128 @test_mul() {
33 ; CHECK-LABEL: test_mul:
35 %lhs = load fp128, fp128* @lhs, align 16
36 %rhs = load fp128, fp128* @rhs, align 16
37 ; CHECK: ldr q0, [{{x[0-9]+}}, :lo12:lhs]
38 ; CHECK: ldr q1, [{{x[0-9]+}}, :lo12:rhs]
40 %val = fmul fp128 %lhs, %rhs
45 define fp128 @test_div() {
46 ; CHECK-LABEL: test_div:
48 %lhs = load fp128, fp128* @lhs, align 16
49 %rhs = load fp128, fp128* @rhs, align 16
50 ; CHECK: ldr q0, [{{x[0-9]+}}, :lo12:lhs]
51 ; CHECK: ldr q1, [{{x[0-9]+}}, :lo12:rhs]
53 %val = fdiv fp128 %lhs, %rhs
61 define void @test_fptosi() {
62 ; CHECK-LABEL: test_fptosi:
63 %val = load fp128, fp128* @lhs, align 16
65 %val32 = fptosi fp128 %val to i32
66 store i32 %val32, i32* @var32
69 %val64 = fptosi fp128 %val to i64
70 store i64 %val64, i64* @var64
76 define void @test_fptoui() {
77 ; CHECK-LABEL: test_fptoui:
78 %val = load fp128, fp128* @lhs, align 16
80 %val32 = fptoui fp128 %val to i32
81 store i32 %val32, i32* @var32
82 ; CHECK: bl __fixunstfsi
84 %val64 = fptoui fp128 %val to i64
85 store i64 %val64, i64* @var64
86 ; CHECK: bl __fixunstfdi
91 define void @test_sitofp() {
92 ; CHECK-LABEL: test_sitofp:
94 %src32 = load i32, i32* @var32
95 %val32 = sitofp i32 %src32 to fp128
96 store volatile fp128 %val32, fp128* @lhs
97 ; CHECK: bl __floatsitf
99 %src64 = load i64, i64* @var64
100 %val64 = sitofp i64 %src64 to fp128
101 store volatile fp128 %val64, fp128* @lhs
102 ; CHECK: bl __floatditf
107 define void @test_uitofp() {
108 ; CHECK-LABEL: test_uitofp:
110 %src32 = load i32, i32* @var32
111 %val32 = uitofp i32 %src32 to fp128
112 store volatile fp128 %val32, fp128* @lhs
113 ; CHECK: bl __floatunsitf
115 %src64 = load i64, i64* @var64
116 %val64 = uitofp i64 %src64 to fp128
117 store volatile fp128 %val64, fp128* @lhs
118 ; CHECK: bl __floatunditf
123 define i1 @test_setcc1() {
124 ; CHECK-LABEL: test_setcc1:
126 %lhs = load fp128, fp128* @lhs, align 16
127 %rhs = load fp128, fp128* @rhs, align 16
128 ; CHECK: ldr q0, [{{x[0-9]+}}, :lo12:lhs]
129 ; CHECK: ldr q1, [{{x[0-9]+}}, :lo12:rhs]
131 ; Technically, everything after the call to __letf2 is redundant, but we'll let
132 ; LLVM have its fun for now.
133 %val = fcmp ole fp128 %lhs, %rhs
142 define i1 @test_setcc2() {
143 ; CHECK-LABEL: test_setcc2:
145 %lhs = load fp128, fp128* @lhs, align 16
146 %rhs = load fp128, fp128* @rhs, align 16
147 ; CHECK: ldr q0, [{{x[0-9]+}}, :lo12:lhs]
148 ; CHECK: ldr q1, [{{x[0-9]+}}, :lo12:rhs]
150 %val = fcmp ugt fp128 %lhs, %rhs
159 define i1 @test_setcc3() {
160 ; CHECK-LABEL: test_setcc3:
162 %lhs = load fp128, fp128* @lhs, align 16
163 %rhs = load fp128, fp128* @rhs, align 16
164 ; CHECK: ldr q0, [{{x[0-9]+}}, :lo12:lhs]
165 ; CHECK: ldr q1, [{{x[0-9]+}}, :lo12:rhs]
167 %val = fcmp ueq fp128 %lhs, %rhs
170 ; CHECK: cset w19, eq
171 ; CHECK: bl __unordtf2
174 ; CHECK: orr w0, w8, w19
181 define i32 @test_br_cc() {
182 ; CHECK-LABEL: test_br_cc:
184 %lhs = load fp128, fp128* @lhs, align 16
185 %rhs = load fp128, fp128* @rhs, align 16
186 ; CHECK: ldr q0, [{{x[0-9]+}}, :lo12:lhs]
187 ; CHECK: ldr q1, [{{x[0-9]+}}, :lo12:rhs]
189 ; olt == !uge, which LLVM optimizes this to.
190 %cond = fcmp olt fp128 %lhs, %rhs
192 ; CHECK-NEXT: cmp w0, #0
193 ; CHECK-NEXT: b.ge {{.LBB[0-9]+_[0-9]+}}
194 br i1 %cond, label %iftrue, label %iffalse
199 ; CHECK-NEXT: mov w0, #42
207 define void @test_select(i1 %cond, fp128 %lhs, fp128 %rhs) {
208 ; CHECK-LABEL: test_select:
210 %val = select i1 %cond, fp128 %lhs, fp128 %rhs
211 store fp128 %val, fp128* @lhs, align 16
212 ; CHECK: tst w0, #0x1
213 ; CHECK-NEXT: b.eq [[IFFALSE:.LBB[0-9]+_[0-9]+]]
215 ; CHECK-NEXT: mov v[[VAL:[0-9]+]].16b, v0.16b
216 ; CHECK-NEXT: [[IFFALSE]]:
217 ; CHECK: str q[[VAL]], [{{x[0-9]+}}, :lo12:lhs]
222 @varfloat = global float 0.0, align 4
223 @vardouble = global double 0.0, align 8
225 define void @test_round() {
226 ; CHECK-LABEL: test_round:
228 %val = load fp128, fp128* @lhs, align 16
230 %float = fptrunc fp128 %val to float
231 store float %float, float* @varfloat, align 4
232 ; CHECK: bl __trunctfsf2
233 ; CHECK: str s0, [{{x[0-9]+}}, :lo12:varfloat]
235 %double = fptrunc fp128 %val to double
236 store double %double, double* @vardouble, align 8
237 ; CHECK: bl __trunctfdf2
238 ; CHECK: str d0, [{{x[0-9]+}}, :lo12:vardouble]
243 define void @test_extend() {
244 ; CHECK-LABEL: test_extend:
246 %val = load fp128, fp128* @lhs, align 16
248 %float = load float, float* @varfloat
249 %fromfloat = fpext float %float to fp128
250 store volatile fp128 %fromfloat, fp128* @lhs, align 16
251 ; CHECK: bl __extendsftf2
252 ; CHECK: str q0, [{{x[0-9]+}}, :lo12:lhs]
254 %double = load double, double* @vardouble
255 %fromdouble = fpext double %double to fp128
256 store volatile fp128 %fromdouble, fp128* @lhs, align 16
257 ; CHECK: bl __extenddftf2
258 ; CHECK: str q0, [{{x[0-9]+}}, :lo12:lhs]
264 define fp128 @test_neg(fp128 %in) {
265 ; CHECK: [[$MINUS0:.LCPI[0-9]+_0]]:
266 ; Make sure the weird hex constant below *is* -0.0
267 ; CHECK-NEXT: fp128 -0
269 ; CHECK-LABEL: test_neg:
271 ; Could in principle be optimized to fneg which we can't select, this makes
272 ; sure that doesn't happen.
273 %ret = fsub fp128 0xL00000000000000008000000000000000, %in
274 ; CHECK: mov v1.16b, v0.16b
275 ; CHECK: ldr q0, [{{x[0-9]+}}, :lo12:[[$MINUS0]]]