1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2; RUN: llc < %s -mtriple=i686-apple-darwin | FileCheck %s --check-prefix=X32-NOF16C 3; RUN: llc < %s -mtriple=i686-apple-darwin -mattr=f16c | FileCheck %s --check-prefix=X32-F16C 4; RUN: llc < %s -mtriple=x86_64-apple-darwin | FileCheck %s --check-prefix=X64-NOF16C 5; RUN: llc < %s -mtriple=x86_64-apple-darwin -mattr=f16c | FileCheck %s --check-prefix=X64-F16C 6 7@a = global half 0xH0000, align 2 8@b = global half 0xH0000, align 2 9@c = global half 0xH0000, align 2 10 11define float @half_to_float() strictfp { 12; X32-NOF16C-LABEL: half_to_float: 13; X32-NOF16C: ## %bb.0: 14; X32-NOF16C-NEXT: subl $12, %esp 15; X32-NOF16C-NEXT: .cfi_def_cfa_offset 16 16; X32-NOF16C-NEXT: movzwl _a, %eax 17; X32-NOF16C-NEXT: movl %eax, (%esp) 18; X32-NOF16C-NEXT: calll ___extendhfsf2 19; X32-NOF16C-NEXT: addl $12, %esp 20; X32-NOF16C-NEXT: retl 21; 22; X32-F16C-LABEL: half_to_float: 23; X32-F16C: ## %bb.0: 24; X32-F16C-NEXT: pushl %eax 25; X32-F16C-NEXT: .cfi_def_cfa_offset 8 26; X32-F16C-NEXT: movzwl _a, %eax 27; X32-F16C-NEXT: vmovd %eax, %xmm0 28; X32-F16C-NEXT: vcvtph2ps %xmm0, %xmm0 29; X32-F16C-NEXT: vmovss %xmm0, (%esp) 30; X32-F16C-NEXT: flds (%esp) 31; X32-F16C-NEXT: wait 32; X32-F16C-NEXT: popl %eax 33; X32-F16C-NEXT: retl 34; 35; X64-NOF16C-LABEL: half_to_float: 36; X64-NOF16C: ## %bb.0: 37; X64-NOF16C-NEXT: pushq %rax 38; X64-NOF16C-NEXT: .cfi_def_cfa_offset 16 39; X64-NOF16C-NEXT: movzwl _a(%rip), %edi 40; X64-NOF16C-NEXT: callq ___extendhfsf2 41; X64-NOF16C-NEXT: popq %rax 42; X64-NOF16C-NEXT: retq 43; 44; X64-F16C-LABEL: half_to_float: 45; X64-F16C: ## %bb.0: 46; X64-F16C-NEXT: movzwl _a(%rip), %eax 47; X64-F16C-NEXT: vmovd %eax, %xmm0 48; X64-F16C-NEXT: vcvtph2ps %xmm0, %xmm0 49; X64-F16C-NEXT: retq 50 %1 = load half, half* @a, align 2 51 %2 = tail call float @llvm.experimental.constrained.fpext.f32.f16(half %1, metadata !"fpexcept.strict") #0 52 ret float %2 53} 54 55define double @half_to_double() strictfp { 56; X32-NOF16C-LABEL: half_to_double: 57; X32-NOF16C: ## %bb.0: 58; X32-NOF16C-NEXT: subl $12, %esp 59; X32-NOF16C-NEXT: .cfi_def_cfa_offset 16 60; X32-NOF16C-NEXT: movzwl _a, %eax 61; X32-NOF16C-NEXT: movl %eax, (%esp) 62; X32-NOF16C-NEXT: calll ___extendhfsf2 63; X32-NOF16C-NEXT: addl $12, %esp 64; X32-NOF16C-NEXT: retl 65; 66; X32-F16C-LABEL: half_to_double: 67; X32-F16C: ## %bb.0: 68; X32-F16C-NEXT: subl $12, %esp 69; X32-F16C-NEXT: .cfi_def_cfa_offset 16 70; X32-F16C-NEXT: movzwl _a, %eax 71; X32-F16C-NEXT: vmovd %eax, %xmm0 72; X32-F16C-NEXT: vcvtph2ps %xmm0, %xmm0 73; X32-F16C-NEXT: vcvtss2sd %xmm0, %xmm0, %xmm0 74; X32-F16C-NEXT: vmovsd %xmm0, (%esp) 75; X32-F16C-NEXT: fldl (%esp) 76; X32-F16C-NEXT: wait 77; X32-F16C-NEXT: addl $12, %esp 78; X32-F16C-NEXT: retl 79; 80; X64-NOF16C-LABEL: half_to_double: 81; X64-NOF16C: ## %bb.0: 82; X64-NOF16C-NEXT: pushq %rax 83; X64-NOF16C-NEXT: .cfi_def_cfa_offset 16 84; X64-NOF16C-NEXT: movzwl _a(%rip), %edi 85; X64-NOF16C-NEXT: callq ___extendhfsf2 86; X64-NOF16C-NEXT: cvtss2sd %xmm0, %xmm0 87; X64-NOF16C-NEXT: popq %rax 88; X64-NOF16C-NEXT: retq 89; 90; X64-F16C-LABEL: half_to_double: 91; X64-F16C: ## %bb.0: 92; X64-F16C-NEXT: movzwl _a(%rip), %eax 93; X64-F16C-NEXT: vmovd %eax, %xmm0 94; X64-F16C-NEXT: vcvtph2ps %xmm0, %xmm0 95; X64-F16C-NEXT: vcvtss2sd %xmm0, %xmm0, %xmm0 96; X64-F16C-NEXT: retq 97 %1 = load half, half* @a, align 2 98 %2 = tail call double @llvm.experimental.constrained.fpext.f64.f16(half %1, metadata !"fpexcept.strict") #0 99 ret double %2 100} 101 102define x86_fp80 @half_to_fp80() strictfp { 103; X32-NOF16C-LABEL: half_to_fp80: 104; X32-NOF16C: ## %bb.0: 105; X32-NOF16C-NEXT: subl $12, %esp 106; X32-NOF16C-NEXT: .cfi_def_cfa_offset 16 107; X32-NOF16C-NEXT: movzwl _a, %eax 108; X32-NOF16C-NEXT: movl %eax, (%esp) 109; X32-NOF16C-NEXT: calll ___extendhfsf2 110; X32-NOF16C-NEXT: addl $12, %esp 111; X32-NOF16C-NEXT: retl 112; 113; X32-F16C-LABEL: half_to_fp80: 114; X32-F16C: ## %bb.0: 115; X32-F16C-NEXT: pushl %eax 116; X32-F16C-NEXT: .cfi_def_cfa_offset 8 117; X32-F16C-NEXT: movzwl _a, %eax 118; X32-F16C-NEXT: vmovd %eax, %xmm0 119; X32-F16C-NEXT: vcvtph2ps %xmm0, %xmm0 120; X32-F16C-NEXT: vmovss %xmm0, (%esp) 121; X32-F16C-NEXT: flds (%esp) 122; X32-F16C-NEXT: wait 123; X32-F16C-NEXT: popl %eax 124; X32-F16C-NEXT: retl 125; 126; X64-NOF16C-LABEL: half_to_fp80: 127; X64-NOF16C: ## %bb.0: 128; X64-NOF16C-NEXT: pushq %rax 129; X64-NOF16C-NEXT: .cfi_def_cfa_offset 16 130; X64-NOF16C-NEXT: movzwl _a(%rip), %edi 131; X64-NOF16C-NEXT: callq ___extendhfsf2 132; X64-NOF16C-NEXT: movss %xmm0, {{[0-9]+}}(%rsp) 133; X64-NOF16C-NEXT: flds {{[0-9]+}}(%rsp) 134; X64-NOF16C-NEXT: wait 135; X64-NOF16C-NEXT: popq %rax 136; X64-NOF16C-NEXT: retq 137; 138; X64-F16C-LABEL: half_to_fp80: 139; X64-F16C: ## %bb.0: 140; X64-F16C-NEXT: movzwl _a(%rip), %eax 141; X64-F16C-NEXT: vmovd %eax, %xmm0 142; X64-F16C-NEXT: vcvtph2ps %xmm0, %xmm0 143; X64-F16C-NEXT: vmovss %xmm0, -{{[0-9]+}}(%rsp) 144; X64-F16C-NEXT: flds -{{[0-9]+}}(%rsp) 145; X64-F16C-NEXT: wait 146; X64-F16C-NEXT: retq 147 %1 = load half, half* @a, align 2 148 %2 = tail call x86_fp80 @llvm.experimental.constrained.fpext.f80.f16(half %1, metadata !"fpexcept.strict") #0 149 ret x86_fp80 %2 150} 151 152define void @float_to_half(float %0) strictfp { 153; X32-NOF16C-LABEL: float_to_half: 154; X32-NOF16C: ## %bb.0: 155; X32-NOF16C-NEXT: subl $12, %esp 156; X32-NOF16C-NEXT: .cfi_def_cfa_offset 16 157; X32-NOF16C-NEXT: flds {{[0-9]+}}(%esp) 158; X32-NOF16C-NEXT: fstps (%esp) 159; X32-NOF16C-NEXT: wait 160; X32-NOF16C-NEXT: calll ___truncsfhf2 161; X32-NOF16C-NEXT: movw %ax, _a 162; X32-NOF16C-NEXT: addl $12, %esp 163; X32-NOF16C-NEXT: retl 164; 165; X32-F16C-LABEL: float_to_half: 166; X32-F16C: ## %bb.0: 167; X32-F16C-NEXT: vmovss {{.*#+}} xmm0 = mem[0],zero,zero,zero 168; X32-F16C-NEXT: vcvtps2ph $4, %xmm0, %xmm0 169; X32-F16C-NEXT: vpextrw $0, %xmm0, _a 170; X32-F16C-NEXT: retl 171; 172; X64-NOF16C-LABEL: float_to_half: 173; X64-NOF16C: ## %bb.0: 174; X64-NOF16C-NEXT: pushq %rax 175; X64-NOF16C-NEXT: .cfi_def_cfa_offset 16 176; X64-NOF16C-NEXT: callq ___truncsfhf2 177; X64-NOF16C-NEXT: movw %ax, _a(%rip) 178; X64-NOF16C-NEXT: popq %rax 179; X64-NOF16C-NEXT: retq 180; 181; X64-F16C-LABEL: float_to_half: 182; X64-F16C: ## %bb.0: 183; X64-F16C-NEXT: vxorps %xmm1, %xmm1, %xmm1 184; X64-F16C-NEXT: vblendps {{.*#+}} xmm0 = xmm0[0],xmm1[1,2,3] 185; X64-F16C-NEXT: vcvtps2ph $4, %xmm0, %xmm0 186; X64-F16C-NEXT: vpextrw $0, %xmm0, _a(%rip) 187; X64-F16C-NEXT: retq 188 %2 = tail call half @llvm.experimental.constrained.fptrunc.f16.f32(float %0, metadata !"round.tonearest", metadata !"fpexcept.strict") #0 189 store half %2, half* @a, align 2 190 ret void 191} 192 193define void @double_to_half(double %0) strictfp { 194; X32-NOF16C-LABEL: double_to_half: 195; X32-NOF16C: ## %bb.0: 196; X32-NOF16C-NEXT: subl $12, %esp 197; X32-NOF16C-NEXT: .cfi_def_cfa_offset 16 198; X32-NOF16C-NEXT: fldl {{[0-9]+}}(%esp) 199; X32-NOF16C-NEXT: fstpl (%esp) 200; X32-NOF16C-NEXT: wait 201; X32-NOF16C-NEXT: calll ___truncdfhf2 202; X32-NOF16C-NEXT: movw %ax, _a 203; X32-NOF16C-NEXT: addl $12, %esp 204; X32-NOF16C-NEXT: retl 205; 206; X32-F16C-LABEL: double_to_half: 207; X32-F16C: ## %bb.0: 208; X32-F16C-NEXT: subl $12, %esp 209; X32-F16C-NEXT: .cfi_def_cfa_offset 16 210; X32-F16C-NEXT: vmovsd {{.*#+}} xmm0 = mem[0],zero 211; X32-F16C-NEXT: vmovsd %xmm0, (%esp) 212; X32-F16C-NEXT: calll ___truncdfhf2 213; X32-F16C-NEXT: movw %ax, _a 214; X32-F16C-NEXT: addl $12, %esp 215; X32-F16C-NEXT: retl 216; 217; X64-NOF16C-LABEL: double_to_half: 218; X64-NOF16C: ## %bb.0: 219; X64-NOF16C-NEXT: pushq %rax 220; X64-NOF16C-NEXT: .cfi_def_cfa_offset 16 221; X64-NOF16C-NEXT: callq ___truncdfhf2 222; X64-NOF16C-NEXT: movw %ax, _a(%rip) 223; X64-NOF16C-NEXT: popq %rax 224; X64-NOF16C-NEXT: retq 225; 226; X64-F16C-LABEL: double_to_half: 227; X64-F16C: ## %bb.0: 228; X64-F16C-NEXT: pushq %rax 229; X64-F16C-NEXT: .cfi_def_cfa_offset 16 230; X64-F16C-NEXT: callq ___truncdfhf2 231; X64-F16C-NEXT: movw %ax, _a(%rip) 232; X64-F16C-NEXT: popq %rax 233; X64-F16C-NEXT: retq 234 %2 = tail call half @llvm.experimental.constrained.fptrunc.f16.f64(double %0, metadata !"round.tonearest", metadata !"fpexcept.strict") #0 235 store half %2, half* @a, align 2 236 ret void 237} 238 239define void @fp80_to_half(x86_fp80 %0) strictfp { 240; X32-NOF16C-LABEL: fp80_to_half: 241; X32-NOF16C: ## %bb.0: 242; X32-NOF16C-NEXT: subl $28, %esp 243; X32-NOF16C-NEXT: .cfi_def_cfa_offset 32 244; X32-NOF16C-NEXT: fldt {{[0-9]+}}(%esp) 245; X32-NOF16C-NEXT: fstpt (%esp) 246; X32-NOF16C-NEXT: wait 247; X32-NOF16C-NEXT: calll ___truncxfhf2 248; X32-NOF16C-NEXT: movw %ax, _a 249; X32-NOF16C-NEXT: addl $28, %esp 250; X32-NOF16C-NEXT: retl 251; 252; X32-F16C-LABEL: fp80_to_half: 253; X32-F16C: ## %bb.0: 254; X32-F16C-NEXT: subl $28, %esp 255; X32-F16C-NEXT: .cfi_def_cfa_offset 32 256; X32-F16C-NEXT: fldt {{[0-9]+}}(%esp) 257; X32-F16C-NEXT: fstpt (%esp) 258; X32-F16C-NEXT: wait 259; X32-F16C-NEXT: calll ___truncxfhf2 260; X32-F16C-NEXT: movw %ax, _a 261; X32-F16C-NEXT: addl $28, %esp 262; X32-F16C-NEXT: retl 263; 264; X64-NOF16C-LABEL: fp80_to_half: 265; X64-NOF16C: ## %bb.0: 266; X64-NOF16C-NEXT: subq $24, %rsp 267; X64-NOF16C-NEXT: .cfi_def_cfa_offset 32 268; X64-NOF16C-NEXT: fldt {{[0-9]+}}(%rsp) 269; X64-NOF16C-NEXT: fstpt (%rsp) 270; X64-NOF16C-NEXT: wait 271; X64-NOF16C-NEXT: callq ___truncxfhf2 272; X64-NOF16C-NEXT: movw %ax, _a(%rip) 273; X64-NOF16C-NEXT: addq $24, %rsp 274; X64-NOF16C-NEXT: retq 275; 276; X64-F16C-LABEL: fp80_to_half: 277; X64-F16C: ## %bb.0: 278; X64-F16C-NEXT: subq $24, %rsp 279; X64-F16C-NEXT: .cfi_def_cfa_offset 32 280; X64-F16C-NEXT: fldt {{[0-9]+}}(%rsp) 281; X64-F16C-NEXT: fstpt (%rsp) 282; X64-F16C-NEXT: wait 283; X64-F16C-NEXT: callq ___truncxfhf2 284; X64-F16C-NEXT: movw %ax, _a(%rip) 285; X64-F16C-NEXT: addq $24, %rsp 286; X64-F16C-NEXT: retq 287 %2 = tail call half @llvm.experimental.constrained.fptrunc.f16.f80(x86_fp80 %0, metadata !"round.tonearest", metadata !"fpexcept.strict") #0 288 store half %2, half* @a, align 2 289 ret void 290} 291 292define void @add() strictfp { 293; X32-NOF16C-LABEL: add: 294; X32-NOF16C: ## %bb.0: 295; X32-NOF16C-NEXT: subl $12, %esp 296; X32-NOF16C-NEXT: .cfi_def_cfa_offset 16 297; X32-NOF16C-NEXT: movzwl _a, %eax 298; X32-NOF16C-NEXT: movl %eax, (%esp) 299; X32-NOF16C-NEXT: calll ___extendhfsf2 300; X32-NOF16C-NEXT: fstps {{[-0-9]+}}(%e{{[sb]}}p) ## 4-byte Folded Spill 301; X32-NOF16C-NEXT: wait 302; X32-NOF16C-NEXT: movzwl _b, %eax 303; X32-NOF16C-NEXT: movl %eax, (%esp) 304; X32-NOF16C-NEXT: calll ___extendhfsf2 305; X32-NOF16C-NEXT: flds {{[-0-9]+}}(%e{{[sb]}}p) ## 4-byte Folded Reload 306; X32-NOF16C-NEXT: faddp %st, %st(1) 307; X32-NOF16C-NEXT: fstps (%esp) 308; X32-NOF16C-NEXT: wait 309; X32-NOF16C-NEXT: calll ___truncsfhf2 310; X32-NOF16C-NEXT: movw %ax, _c 311; X32-NOF16C-NEXT: addl $12, %esp 312; X32-NOF16C-NEXT: retl 313; 314; X32-F16C-LABEL: add: 315; X32-F16C: ## %bb.0: 316; X32-F16C-NEXT: movzwl _a, %eax 317; X32-F16C-NEXT: vmovd %eax, %xmm0 318; X32-F16C-NEXT: vcvtph2ps %xmm0, %xmm0 319; X32-F16C-NEXT: movzwl _b, %eax 320; X32-F16C-NEXT: vmovd %eax, %xmm1 321; X32-F16C-NEXT: vcvtph2ps %xmm1, %xmm1 322; X32-F16C-NEXT: vaddss %xmm1, %xmm0, %xmm0 323; X32-F16C-NEXT: vxorps %xmm1, %xmm1, %xmm1 324; X32-F16C-NEXT: vblendps {{.*#+}} xmm0 = xmm0[0],xmm1[1,2,3] 325; X32-F16C-NEXT: vcvtps2ph $4, %xmm0, %xmm0 326; X32-F16C-NEXT: vpextrw $0, %xmm0, _c 327; X32-F16C-NEXT: retl 328; 329; X64-NOF16C-LABEL: add: 330; X64-NOF16C: ## %bb.0: 331; X64-NOF16C-NEXT: pushq %rax 332; X64-NOF16C-NEXT: .cfi_def_cfa_offset 16 333; X64-NOF16C-NEXT: movzwl _a(%rip), %edi 334; X64-NOF16C-NEXT: callq ___extendhfsf2 335; X64-NOF16C-NEXT: movss %xmm0, {{[-0-9]+}}(%r{{[sb]}}p) ## 4-byte Spill 336; X64-NOF16C-NEXT: movzwl _b(%rip), %edi 337; X64-NOF16C-NEXT: callq ___extendhfsf2 338; X64-NOF16C-NEXT: addss {{[-0-9]+}}(%r{{[sb]}}p), %xmm0 ## 4-byte Folded Reload 339; X64-NOF16C-NEXT: callq ___truncsfhf2 340; X64-NOF16C-NEXT: movw %ax, _c(%rip) 341; X64-NOF16C-NEXT: popq %rax 342; X64-NOF16C-NEXT: retq 343; 344; X64-F16C-LABEL: add: 345; X64-F16C: ## %bb.0: 346; X64-F16C-NEXT: movzwl _a(%rip), %eax 347; X64-F16C-NEXT: vmovd %eax, %xmm0 348; X64-F16C-NEXT: vcvtph2ps %xmm0, %xmm0 349; X64-F16C-NEXT: movzwl _b(%rip), %eax 350; X64-F16C-NEXT: vmovd %eax, %xmm1 351; X64-F16C-NEXT: vcvtph2ps %xmm1, %xmm1 352; X64-F16C-NEXT: vaddss %xmm1, %xmm0, %xmm0 353; X64-F16C-NEXT: vxorps %xmm1, %xmm1, %xmm1 354; X64-F16C-NEXT: vblendps {{.*#+}} xmm0 = xmm0[0],xmm1[1,2,3] 355; X64-F16C-NEXT: vcvtps2ph $4, %xmm0, %xmm0 356; X64-F16C-NEXT: vpextrw $0, %xmm0, _c(%rip) 357; X64-F16C-NEXT: retq 358 %1 = load half, half* @a, align 2 359 %2 = tail call float @llvm.experimental.constrained.fpext.f32.f16(half %1, metadata !"fpexcept.strict") #0 360 %3 = load half, half* @b, align 2 361 %4 = tail call float @llvm.experimental.constrained.fpext.f32.f16(half %3, metadata !"fpexcept.strict") #0 362 %5 = tail call float @llvm.experimental.constrained.fadd.f32(float %2, float %4, metadata !"round.tonearest", metadata !"fpexcept.strict") #0 363 %6 = tail call half @llvm.experimental.constrained.fptrunc.f16.f32(float %5, metadata !"round.tonearest", metadata !"fpexcept.strict") #0 364 store half %6, half* @c, align 2 365 ret void 366} 367 368declare float @llvm.experimental.constrained.fpext.f32.f16(half, metadata) 369declare double @llvm.experimental.constrained.fpext.f64.f16(half, metadata) 370declare x86_fp80 @llvm.experimental.constrained.fpext.f80.f16(half, metadata) 371declare float @llvm.experimental.constrained.fadd.f32(float, float, metadata, metadata) 372declare half @llvm.experimental.constrained.fptrunc.f16.f32(float, metadata, metadata) 373declare half @llvm.experimental.constrained.fptrunc.f16.f64(double, metadata, metadata) 374declare half @llvm.experimental.constrained.fptrunc.f16.f80(x86_fp80, metadata, metadata) 375 376attributes #0 = { strictfp } 377 378