1 ; RUN: llc -mtriple=arm64-linux-gnu -verify-machineinstrs -mcpu=cyclone -aarch64-atomic-cfg-tidy=0 < %s | FileCheck %s 2 3 @lhs = global fp128 zeroinitializer, align 16 4 @rhs = global fp128 zeroinitializer, align 16 5 6 define fp128 @test_add() { 7 ; CHECK-LABEL: test_add: 8 9 %lhs = load fp128* @lhs, align 16 10 %rhs = load fp128* @rhs, align 16 11 ; CHECK: ldr q0, [{{x[0-9]+}}, :lo12:lhs] 12 ; CHECK: ldr q1, [{{x[0-9]+}}, :lo12:rhs] 13 14 %val = fadd fp128 %lhs, %rhs 15 ; CHECK: bl __addtf3 16 ret fp128 %val 17 } 18 19 define fp128 @test_sub() { 20 ; CHECK-LABEL: test_sub: 21 22 %lhs = load fp128* @lhs, align 16 23 %rhs = load fp128* @rhs, align 16 24 ; CHECK: ldr q0, [{{x[0-9]+}}, :lo12:lhs] 25 ; CHECK: ldr q1, [{{x[0-9]+}}, :lo12:rhs] 26 27 %val = fsub fp128 %lhs, %rhs 28 ; CHECK: bl __subtf3 29 ret fp128 %val 30 } 31 32 define fp128 @test_mul() { 33 ; CHECK-LABEL: test_mul: 34 35 %lhs = load fp128* @lhs, align 16 36 %rhs = load fp128* @rhs, align 16 37 ; CHECK: ldr q0, [{{x[0-9]+}}, :lo12:lhs] 38 ; CHECK: ldr q1, [{{x[0-9]+}}, :lo12:rhs] 39 40 %val = fmul fp128 %lhs, %rhs 41 ; CHECK: bl __multf3 42 ret fp128 %val 43 } 44 45 define fp128 @test_div() { 46 ; CHECK-LABEL: test_div: 47 48 %lhs = load fp128* @lhs, align 16 49 %rhs = load fp128* @rhs, align 16 50 ; CHECK: ldr q0, [{{x[0-9]+}}, :lo12:lhs] 51 ; CHECK: ldr q1, [{{x[0-9]+}}, :lo12:rhs] 52 53 %val = fdiv fp128 %lhs, %rhs 54 ; CHECK: bl __divtf3 55 ret fp128 %val 56 } 57 58 @var32 = global i32 0 59 @var64 = global i64 0 60 61 define void @test_fptosi() { 62 ; CHECK-LABEL: test_fptosi: 63 %val = load fp128* @lhs, align 16 64 65 %val32 = fptosi fp128 %val to i32 66 store i32 %val32, i32* @var32 67 ; CHECK: bl __fixtfsi 68 69 %val64 = fptosi fp128 %val to i64 70 store i64 %val64, i64* @var64 71 ; CHECK: bl __fixtfdi 72 73 ret void 74 } 75 76 define void @test_fptoui() { 77 ; CHECK-LABEL: test_fptoui: 78 %val = load fp128* @lhs, align 16 79 80 %val32 = fptoui fp128 %val to i32 81 store i32 %val32, i32* @var32 82 ; CHECK: bl __fixunstfsi 83 84 %val64 = fptoui fp128 %val to i64 85 store i64 %val64, i64* @var64 86 ; CHECK: bl __fixunstfdi 87 88 ret void 89 } 90 91 define void @test_sitofp() { 92 ; CHECK-LABEL: test_sitofp: 93 94 %src32 = load i32* @var32 95 %val32 = sitofp i32 %src32 to fp128 96 store volatile fp128 %val32, fp128* @lhs 97 ; CHECK: bl __floatsitf 98 99 %src64 = load i64* @var64 100 %val64 = sitofp i64 %src64 to fp128 101 store volatile fp128 %val64, fp128* @lhs 102 ; CHECK: bl __floatditf 103 104 ret void 105 } 106 107 define void @test_uitofp() { 108 ; CHECK-LABEL: test_uitofp: 109 110 %src32 = load i32* @var32 111 %val32 = uitofp i32 %src32 to fp128 112 store volatile fp128 %val32, fp128* @lhs 113 ; CHECK: bl __floatunsitf 114 115 %src64 = load i64* @var64 116 %val64 = uitofp i64 %src64 to fp128 117 store volatile fp128 %val64, fp128* @lhs 118 ; CHECK: bl __floatunditf 119 120 ret void 121 } 122 123 define i1 @test_setcc1() { 124 ; CHECK-LABEL: test_setcc1: 125 126 %lhs = load fp128* @lhs, align 16 127 %rhs = load fp128* @rhs, align 16 128 ; CHECK: ldr q0, [{{x[0-9]+}}, :lo12:lhs] 129 ; CHECK: ldr q1, [{{x[0-9]+}}, :lo12:rhs] 130 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 134 ; CHECK: bl __letf2 135 ; CHECK: cmp w0, #0 136 ; CHECK: cset w0, le 137 138 ret i1 %val 139 ; CHECK: ret 140 } 141 142 define i1 @test_setcc2() { 143 ; CHECK-LABEL: test_setcc2: 144 145 %lhs = load fp128* @lhs, align 16 146 %rhs = load fp128* @rhs, align 16 147 ; CHECK: ldr q0, [{{x[0-9]+}}, :lo12:lhs] 148 ; CHECK: ldr q1, [{{x[0-9]+}}, :lo12:rhs] 149 150 %val = fcmp ugt fp128 %lhs, %rhs 151 ; CHECK: bl __gttf2 152 ; CHECK: cmp w0, #0 153 ; CHECK: cset [[GT:w[0-9]+]], gt 154 155 ; CHECK: bl __unordtf2 156 ; CHECK: cmp w0, #0 157 ; CHECK: cset [[UNORDERED:w[0-9]+]], ne 158 ; CHECK: orr w0, [[UNORDERED]], [[GT]] 159 160 ret i1 %val 161 ; CHECK: ret 162 } 163 164 define i32 @test_br_cc() { 165 ; CHECK-LABEL: test_br_cc: 166 167 %lhs = load fp128* @lhs, align 16 168 %rhs = load fp128* @rhs, align 16 169 ; CHECK: ldr q0, [{{x[0-9]+}}, :lo12:lhs] 170 ; CHECK: ldr q1, [{{x[0-9]+}}, :lo12:rhs] 171 172 ; olt == !uge, which LLVM unfortunately "optimizes" this to. 173 %cond = fcmp olt fp128 %lhs, %rhs 174 ; CHECK: bl __getf2 175 ; CHECK: cmp w0, #0 176 ; CHECK: cset [[OGE:w[0-9]+]], ge 177 178 ; CHECK: bl __unordtf2 179 ; CHECK: cmp w0, #0 180 ; CHECK: cset [[UNORDERED:w[0-9]+]], ne 181 182 ; CHECK: orr [[UGE:w[0-9]+]], [[UNORDERED]], [[OGE]] 183 ; CHECK: cbnz [[UGE]], [[RET29:.LBB[0-9]+_[0-9]+]] 184 br i1 %cond, label %iftrue, label %iffalse 185 186 iftrue: 187 ret i32 42 188 ; CHECK-NEXT: BB# 189 ; CHECK-NEXT: movz w0, #0x2a 190 ; CHECK-NEXT: b [[REALRET:.LBB[0-9]+_[0-9]+]] 191 192 iffalse: 193 ret i32 29 194 ; CHECK: [[RET29]]: 195 ; CHECK-NEXT: movz w0, #0x1d 196 ; CHECK-NEXT: [[REALRET]]: 197 ; CHECK: ret 198 } 199 200 define void @test_select(i1 %cond, fp128 %lhs, fp128 %rhs) { 201 ; CHECK-LABEL: test_select: 202 203 %val = select i1 %cond, fp128 %lhs, fp128 %rhs 204 store fp128 %val, fp128* @lhs, align 16 205 ; CHECK: tst w0, #0x1 206 ; CHECK-NEXT: b.eq [[IFFALSE:.LBB[0-9]+_[0-9]+]] 207 ; CHECK-NEXT: BB# 208 ; CHECK-NEXT: mov v[[VAL:[0-9]+]].16b, v0.16b 209 ; CHECK-NEXT: [[IFFALSE]]: 210 ; CHECK: str q[[VAL]], [{{x[0-9]+}}, :lo12:lhs] 211 ret void 212 ; CHECK: ret 213 } 214 215 @varfloat = global float 0.0, align 4 216 @vardouble = global double 0.0, align 8 217 218 define void @test_round() { 219 ; CHECK-LABEL: test_round: 220 221 %val = load fp128* @lhs, align 16 222 223 %float = fptrunc fp128 %val to float 224 store float %float, float* @varfloat, align 4 225 ; CHECK: bl __trunctfsf2 226 ; CHECK: str s0, [{{x[0-9]+}}, :lo12:varfloat] 227 228 %double = fptrunc fp128 %val to double 229 store double %double, double* @vardouble, align 8 230 ; CHECK: bl __trunctfdf2 231 ; CHECK: str d0, [{{x[0-9]+}}, :lo12:vardouble] 232 233 ret void 234 } 235 236 define void @test_extend() { 237 ; CHECK-LABEL: test_extend: 238 239 %val = load fp128* @lhs, align 16 240 241 %float = load float* @varfloat 242 %fromfloat = fpext float %float to fp128 243 store volatile fp128 %fromfloat, fp128* @lhs, align 16 244 ; CHECK: bl __extendsftf2 245 ; CHECK: str q0, [{{x[0-9]+}}, :lo12:lhs] 246 247 %double = load double* @vardouble 248 %fromdouble = fpext double %double to fp128 249 store volatile fp128 %fromdouble, fp128* @lhs, align 16 250 ; CHECK: bl __extenddftf2 251 ; CHECK: str q0, [{{x[0-9]+}}, :lo12:lhs] 252 253 ret void 254 ; CHECK: ret 255 } 256 257 define fp128 @test_neg(fp128 %in) { 258 ; CHECK: [[MINUS0:.LCPI[0-9]+_0]]: 259 ; Make sure the weird hex constant below *is* -0.0 260 ; CHECK-NEXT: fp128 -0 261 262 ; CHECK-LABEL: test_neg: 263 264 ; Could in principle be optimized to fneg which we can't select, this makes 265 ; sure that doesn't happen. 266 %ret = fsub fp128 0xL00000000000000008000000000000000, %in 267 ; CHECK: mov v1.16b, v0.16b 268 ; CHECK: ldr q0, [{{x[0-9]+}}, :lo12:[[MINUS0]]] 269 ; CHECK: bl __subtf3 270 271 ret fp128 %ret 272 ; CHECK: ret 273 } 274