Index: llvm/lib/Target/X86/X86ISelLowering.cpp =================================================================== --- llvm/lib/Target/X86/X86ISelLowering.cpp +++ llvm/lib/Target/X86/X86ISelLowering.cpp @@ -602,6 +602,15 @@ setOperationAction(ISD::FSIN , VT, Expand); setOperationAction(ISD::FCOS , VT, Expand); setOperationAction(ISD::FSINCOS, VT, Expand); + + // Handle constrained floating-point operations of scalar. + setOperationAction(ISD::STRICT_FADD , VT, Legal); + setOperationAction(ISD::STRICT_FSUB , VT, Legal); + setOperationAction(ISD::STRICT_FMUL , VT, Legal); + setOperationAction(ISD::STRICT_FDIV , VT, Legal); + setOperationAction(ISD::STRICT_FSQRT , VT, Legal); + setOperationAction(ISD::STRICT_FP_ROUND , VT, Legal); + setOperationAction(ISD::STRICT_FP_EXTEND, VT, Legal); } } @@ -665,6 +674,15 @@ setOperationAction(ISD::LLROUND, MVT::f80, Expand); setOperationAction(ISD::LRINT, MVT::f80, Expand); setOperationAction(ISD::LLRINT, MVT::f80, Expand); + + // Handle constrained floating-point operations of scalar. + setOperationAction(ISD::STRICT_FADD , MVT::f80, Legal); + setOperationAction(ISD::STRICT_FSUB , MVT::f80, Legal); + setOperationAction(ISD::STRICT_FMUL , MVT::f80, Legal); + setOperationAction(ISD::STRICT_FDIV , MVT::f80, Legal); + setOperationAction(ISD::STRICT_FSQRT , MVT::f80, Legal); + setOperationAction(ISD::STRICT_FP_ROUND , MVT::f80, Legal); + setOperationAction(ISD::STRICT_FP_EXTEND, MVT::f80, Legal); } // f128 uses xmm registers, but most operations require libcalls. Index: llvm/lib/Target/X86/X86InstrFPStack.td =================================================================== --- llvm/lib/Target/X86/X86InstrFPStack.td +++ llvm/lib/Target/X86/X86InstrFPStack.td @@ -286,26 +286,26 @@ // FPBinary_rr just defines pseudo-instructions, no need to set a scheduling // resources. let hasNoSchedulingInfo = 1 in { -defm ADD : FPBinary_rr; -defm SUB : FPBinary_rr; -defm MUL : FPBinary_rr; -defm DIV : FPBinary_rr; +defm ADD : FPBinary_rr; +defm SUB : FPBinary_rr; +defm MUL : FPBinary_rr; +defm DIV : FPBinary_rr; } // Sets the scheduling resources for the actual NAME#_Fm defintions. let SchedRW = [WriteFAddLd] in { -defm ADD : FPBinary; -defm SUB : FPBinary; -defm SUBR: FPBinary; +defm ADD : FPBinary; +defm SUB : FPBinary; +defm SUBR: FPBinary; } let SchedRW = [WriteFMulLd] in { -defm MUL : FPBinary; +defm MUL : FPBinary; } let SchedRW = [WriteFDivLd] in { -defm DIV : FPBinary; -defm DIVR: FPBinary; +defm DIV : FPBinary; +defm DIVR: FPBinary; } } // Uses = [FPCW], mayRaiseFPException = 1 @@ -366,7 +366,7 @@ let Uses = [FPCW], mayRaiseFPException = 1 in { let SchedRW = [WriteFSqrt80] in -defm SQRT: FPUnary; +defm SQRT: FPUnary; let SchedRW = [WriteFCom] in { let hasSideEffects = 0 in { @@ -790,19 +790,19 @@ // FP extensions map onto simple pseudo-value conversions if they are to/from // the FP stack. -def : Pat<(f64 (fpextend RFP32:$src)), (COPY_TO_REGCLASS RFP32:$src, RFP64)>, +def : Pat<(f64 (any_fpextend RFP32:$src)), (COPY_TO_REGCLASS RFP32:$src, RFP64)>, Requires<[FPStackf32]>; -def : Pat<(f80 (fpextend RFP32:$src)), (COPY_TO_REGCLASS RFP32:$src, RFP80)>, +def : Pat<(f80 (any_fpextend RFP32:$src)), (COPY_TO_REGCLASS RFP32:$src, RFP80)>, Requires<[FPStackf32]>; -def : Pat<(f80 (fpextend RFP64:$src)), (COPY_TO_REGCLASS RFP64:$src, RFP80)>, +def : Pat<(f80 (any_fpextend RFP64:$src)), (COPY_TO_REGCLASS RFP64:$src, RFP80)>, Requires<[FPStackf64]>; // FP truncations map onto simple pseudo-value conversions if they are to/from // the FP stack. We have validated that only value-preserving truncations make // it through isel. -def : Pat<(f32 (fpround RFP64:$src)), (COPY_TO_REGCLASS RFP64:$src, RFP32)>, +def : Pat<(f32 (any_fpround RFP64:$src)), (COPY_TO_REGCLASS RFP64:$src, RFP32)>, Requires<[FPStackf32]>; -def : Pat<(f32 (fpround RFP80:$src)), (COPY_TO_REGCLASS RFP80:$src, RFP32)>, +def : Pat<(f32 (any_fpround RFP80:$src)), (COPY_TO_REGCLASS RFP80:$src, RFP32)>, Requires<[FPStackf32]>; -def : Pat<(f64 (fpround RFP80:$src)), (COPY_TO_REGCLASS RFP80:$src, RFP64)>, +def : Pat<(f64 (any_fpround RFP80:$src)), (COPY_TO_REGCLASS RFP80:$src, RFP64)>, Requires<[FPStackf64]>; Index: llvm/test/CodeGen/X86/fp-strict-scalar.ll =================================================================== --- llvm/test/CodeGen/X86/fp-strict-scalar.ll +++ llvm/test/CodeGen/X86/fp-strict-scalar.ll @@ -5,7 +5,7 @@ ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+avx -O3 | FileCheck %s --check-prefixes=CHECK,AVX ; RUN: llc < %s -mtriple=i686-unknown-unknown -mattr=+avx512f -mattr=+avx512vl -O3 | FileCheck %s --check-prefixes=CHECK,AVX ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+avx512f -mattr=+avx512vl -O3 | FileCheck %s --check-prefixes=CHECK,AVX -; RUN: llc < %s -mtriple=i686-unknown-unknown -mattr=-sse -O3 | FileCheck %s --check-prefixes=X87 +; RUN: llc < %s -mtriple=i686-unknown-unknown -mattr=-sse -O3 | FileCheck %s --check-prefixes=CHECK,X87 declare double @llvm.experimental.constrained.fadd.f64(double, double, metadata, metadata) declare float @llvm.experimental.constrained.fadd.f32(float, float, metadata, metadata) @@ -15,19 +15,23 @@ declare float @llvm.experimental.constrained.fmul.f32(float, float, metadata, metadata) declare double @llvm.experimental.constrained.fdiv.f64(double, double, metadata, metadata) declare float @llvm.experimental.constrained.fdiv.f32(float, float, metadata, metadata) +declare double @llvm.experimental.constrained.fpext.f64.f32(float, metadata) +declare float @llvm.experimental.constrained.fptrunc.f64.f32(double, metadata, metadata) +declare float @llvm.experimental.constrained.sqrt.f32(float, metadata, metadata) +declare double @llvm.experimental.constrained.sqrt.f64(double, metadata, metadata) -define x86_regcallcc double @f1(double %a, double %b) #0 { -; SSE-LABEL: f1: +define x86_regcallcc double @fadd_f64(double %a, double %b) #0 { +; SSE-LABEL: fadd_f64: ; SSE: # %bb.0: ; SSE-NEXT: addsd %xmm1, %xmm0 ; SSE-NEXT: ret{{[l|q]}} ; -; AVX-LABEL: f1: +; AVX-LABEL: fadd_f64: ; AVX: # %bb.0: ; AVX-NEXT: vaddsd %xmm1, %xmm0, %xmm0 ; AVX-NEXT: ret{{[l|q]}} ; -; X87-LABEL: f1: +; X87-LABEL: fadd_f64: ; X87: # %bb.0: ; X87-NEXT: fldl {{[0-9]+}}(%esp) ; X87-NEXT: faddl {{[0-9]+}}(%esp) @@ -38,18 +42,18 @@ ret double %ret } -define x86_regcallcc float @f2(float %a, float %b) #0 { -; SSE-LABEL: f2: +define x86_regcallcc float @fadd_f32(float %a, float %b) #0 { +; SSE-LABEL: fadd_f32: ; SSE: # %bb.0: ; SSE-NEXT: addss %xmm1, %xmm0 ; SSE-NEXT: ret{{[l|q]}} ; -; AVX-LABEL: f2: +; AVX-LABEL: fadd_f32: ; AVX: # %bb.0: ; AVX-NEXT: vaddss %xmm1, %xmm0, %xmm0 ; AVX-NEXT: ret{{[l|q]}} ; -; X87-LABEL: f2: +; X87-LABEL: fadd_f32: ; X87: # %bb.0: ; X87-NEXT: flds {{[0-9]+}}(%esp) ; X87-NEXT: fadds {{[0-9]+}}(%esp) @@ -60,18 +64,18 @@ ret float %ret } -define x86_regcallcc double @f3(double %a, double %b) #0 { -; SSE-LABEL: f3: +define x86_regcallcc double @fsub_f64(double %a, double %b) #0 { +; SSE-LABEL: fsub_f64: ; SSE: # %bb.0: ; SSE-NEXT: subsd %xmm1, %xmm0 ; SSE-NEXT: ret{{[l|q]}} ; -; AVX-LABEL: f3: +; AVX-LABEL: fsub_f64: ; AVX: # %bb.0: ; AVX-NEXT: vsubsd %xmm1, %xmm0, %xmm0 ; AVX-NEXT: ret{{[l|q]}} ; -; X87-LABEL: f3: +; X87-LABEL: fsub_f64: ; X87: # %bb.0: ; X87-NEXT: fldl {{[0-9]+}}(%esp) ; X87-NEXT: fsubl {{[0-9]+}}(%esp) @@ -82,18 +86,18 @@ ret double %ret } -define x86_regcallcc float @f4(float %a, float %b) #0 { -; SSE-LABEL: f4: +define x86_regcallcc float @fsub_f32(float %a, float %b) #0 { +; SSE-LABEL: fsub_f32: ; SSE: # %bb.0: ; SSE-NEXT: subss %xmm1, %xmm0 ; SSE-NEXT: ret{{[l|q]}} ; -; AVX-LABEL: f4: +; AVX-LABEL: fsub_f32: ; AVX: # %bb.0: ; AVX-NEXT: vsubss %xmm1, %xmm0, %xmm0 ; AVX-NEXT: ret{{[l|q]}} ; -; X87-LABEL: f4: +; X87-LABEL: fsub_f32: ; X87: # %bb.0: ; X87-NEXT: flds {{[0-9]+}}(%esp) ; X87-NEXT: fsubs {{[0-9]+}}(%esp) @@ -104,18 +108,18 @@ ret float %ret } -define x86_regcallcc double @f5(double %a, double %b) #0 { -; SSE-LABEL: f5: +define x86_regcallcc double @fmul_f64(double %a, double %b) #0 { +; SSE-LABEL: fmul_f64: ; SSE: # %bb.0: ; SSE-NEXT: mulsd %xmm1, %xmm0 ; SSE-NEXT: ret{{[l|q]}} ; -; AVX-LABEL: f5: +; AVX-LABEL: fmul_f64: ; AVX: # %bb.0: ; AVX-NEXT: vmulsd %xmm1, %xmm0, %xmm0 ; AVX-NEXT: ret{{[l|q]}} ; -; X87-LABEL: f5: +; X87-LABEL: fmul_f64: ; X87: # %bb.0: ; X87-NEXT: fldl {{[0-9]+}}(%esp) ; X87-NEXT: fmull {{[0-9]+}}(%esp) @@ -126,18 +130,18 @@ ret double %ret } -define x86_regcallcc float @f6(float %a, float %b) #0 { -; SSE-LABEL: f6: +define x86_regcallcc float @fmul_f32(float %a, float %b) #0 { +; SSE-LABEL: fmul_f32: ; SSE: # %bb.0: ; SSE-NEXT: mulss %xmm1, %xmm0 ; SSE-NEXT: ret{{[l|q]}} ; -; AVX-LABEL: f6: +; AVX-LABEL: fmul_f32: ; AVX: # %bb.0: ; AVX-NEXT: vmulss %xmm1, %xmm0, %xmm0 ; AVX-NEXT: ret{{[l|q]}} ; -; X87-LABEL: f6: +; X87-LABEL: fmul_f32: ; X87: # %bb.0: ; X87-NEXT: flds {{[0-9]+}}(%esp) ; X87-NEXT: fmuls {{[0-9]+}}(%esp) @@ -148,18 +152,18 @@ ret float %ret } -define x86_regcallcc double @f7(double %a, double %b) #0 { -; SSE-LABEL: f7: +define x86_regcallcc double @fdiv_f64(double %a, double %b) #0 { +; SSE-LABEL: fdiv_f64: ; SSE: # %bb.0: ; SSE-NEXT: divsd %xmm1, %xmm0 ; SSE-NEXT: ret{{[l|q]}} ; -; AVX-LABEL: f7: +; AVX-LABEL: fdiv_f64: ; AVX: # %bb.0: ; AVX-NEXT: vdivsd %xmm1, %xmm0, %xmm0 ; AVX-NEXT: ret{{[l|q]}} ; -; X87-LABEL: f7: +; X87-LABEL: fdiv_f64: ; X87: # %bb.0: ; X87-NEXT: fldl {{[0-9]+}}(%esp) ; X87-NEXT: fdivl {{[0-9]+}}(%esp) @@ -170,18 +174,18 @@ ret double %ret } -define x86_regcallcc float @f8(float %a, float %b) #0 { -; SSE-LABEL: f8: +define x86_regcallcc float @fdiv_f32(float %a, float %b) #0 { +; SSE-LABEL: fdiv_f32: ; SSE: # %bb.0: ; SSE-NEXT: divss %xmm1, %xmm0 ; SSE-NEXT: ret{{[l|q]}} ; -; AVX-LABEL: f8: +; AVX-LABEL: fdiv_f32: ; AVX: # %bb.0: ; AVX-NEXT: vdivss %xmm1, %xmm0, %xmm0 ; AVX-NEXT: ret{{[l|q]}} ; -; X87-LABEL: f8: +; X87-LABEL: fdiv_f32: ; X87: # %bb.0: ; X87-NEXT: flds {{[0-9]+}}(%esp) ; X87-NEXT: fdivs {{[0-9]+}}(%esp) @@ -192,4 +196,123 @@ ret float %ret } +define x86_regcallcc void @fpext1(float* %val, double* %ret) #0 { +; SSE-LABEL: fpext1: +; SSE: # %bb.0: +; SSE-NEXT: movss {{.*#+}} xmm0 = mem[0],zero,zero,zero +; SSE-NEXT: cvtss2sd %xmm0, %xmm0 +; SSE-NEXT: movsd %xmm0, (%{{[r|e]}}cx) +; SSE-NEXT: ret{{q|l}} +; +; AVX-LABEL: fpext1: +; AVX: # %bb.0: +; AVX-NEXT: vmovss {{.*#+}} xmm0 = mem[0],zero,zero,zero +; AVX-NEXT: vcvtss2sd %xmm0, %xmm0, %xmm0 +; AVX-NEXT: vmovsd %xmm0, (%{{[r|e]}}cx) +; AVX-NEXT: ret{{q|l}} +; +; X87-LABEL: fpext1: +; X87: # %bb.0: +; X87-NEXT: flds (%eax) +; X87-NEXT: fstpl (%ecx) +; X87-NEXT: retl + %1 = load float, float* %val, align 4 + %res = call double @llvm.experimental.constrained.fpext.f64.f32(float %1, + metadata !"fpexcept.strict") #0 + store double %res, double* %ret, align 8 + ret void +} + +define x86_regcallcc void @fptrunc1(double* %val, float *%ret) #0 { +; SSE-LABEL: fptrunc1: +; SSE: # %bb.0: +; SSE-NEXT: movsd {{.*#+}} xmm0 = mem[0],zero +; SSE-NEXT: cvtsd2ss %xmm0, %xmm0 +; SSE-NEXT: movss %xmm0, (%{{r|e}}cx) +; SSE-NEXT: ret{{q|l}} +; +; AVX-LABEL: fptrunc1: +; AVX: # %bb.0: +; AVX-NEXT: vmovsd {{.*#+}} xmm0 = mem[0],zero +; AVX-NEXT: vcvtsd2ss %xmm0, %xmm0, %xmm0 +; AVX-NEXT: vmovss %xmm0, (%{{r|e}}cx) +; AVX-NEXT: ret{{q|l}} +; +; X87-LABEL: fptrunc1: +; X87: # %bb.0: +; X87-NEXT: pushl %eax +; X87-NEXT: .cfi_def_cfa_offset 8 +; X87-NEXT: fldl (%eax) +; X87-NEXT: fstps (%esp) +; X87-NEXT: flds (%esp) +; X87-NEXT: fstps (%ecx) +; X87-NEXT: popl %eax +; X87-NEXT: .cfi_def_cfa_offset 4 +; X87-NEXT: retl + %1 = load double, double* %val, align 8 + %res = call float @llvm.experimental.constrained.fptrunc.f64.f32(double %1, + metadata !"round.dynamic", + metadata !"fpexcept.strict") #0 + store float %res, float* %ret, align 4 + ret void +} + +define x86_regcallcc void @fsqrt_f32(float* %a) #0 { +; SSE-LABEL: fsqrt_f32: +; SSE: # %bb.0: +; SSE-NEXT: movss {{.*#+}} xmm0 = mem[0],zero,zero,zero +; SSE-NEXT: sqrtss %xmm0, %xmm0 +; SSE-NEXT: movss %xmm0, (%{{r|e}}ax) +; SSE-NEXT: ret{{q|l}} +; +; AVX-LABEL: fsqrt_f32: +; AVX: # %bb.0: +; AVX-NEXT: vmovss {{.*#+}} xmm0 = mem[0],zero,zero,zero +; AVX-NEXT: vsqrtss %xmm0, %xmm0, %xmm0 +; AVX-NEXT: vmovss %xmm0, (%{{r|e}}ax) +; AVX-NEXT: ret{{q|l}} +; +; X87-LABEL: fsqrt_f32: +; X87: # %bb.0: +; X87-NEXT: flds (%eax) +; X87-NEXT: fsqrt +; X87-NEXT: fstps (%eax) +; X87-NEXT: retl + %1 = load float, float* %a, align 4 + %res = call float @llvm.experimental.constrained.sqrt.f32(float %1, + metadata !"round.dynamic", + metadata !"fpexcept.strict") #0 + store float %res, float* %a, align 4 + ret void +} + +define x86_regcallcc void @fsqrt_f64(double* %a) #0 { +; SSE-LABEL: fsqrt_f64: +; SSE: # %bb.0: +; SSE-NEXT: movsd {{.*#+}} xmm0 = mem[0],zero +; SSE-NEXT: sqrtsd %xmm0, %xmm0 +; SSE-NEXT: movsd %xmm0, (%{{r|e}}ax) +; SSE-NEXT: ret{{q|l}} +; +; AVX-LABEL: fsqrt_f64: +; AVX: # %bb.0: +; AVX-NEXT: vmovsd {{.*#+}} xmm0 = mem[0],zero +; AVX-NEXT: vsqrtsd %xmm0, %xmm0, %xmm0 +; AVX-NEXT: vmovsd %xmm0, (%{{r|e}}ax) +; AVX-NEXT: ret{{q|l}} +; +; X87-LABEL: fsqrt_f64: +; X87: # %bb.0: +; X87-NEXT: fldl (%eax) +; X87-NEXT: fsqrt +; X87-NEXT: fstpl (%eax) +; X87-NEXT: retl + %1 = load double, double* %a, align 8 + %res = call double @llvm.experimental.constrained.sqrt.f64(double %1, + metadata !"round.dynamic", + metadata !"fpexcept.strict") #0 + store double %res, double* %a, align 8 + ret void +} + attributes #0 = { strictfp } Index: llvm/test/CodeGen/X86/fp80-strict-scalar.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/X86/fp80-strict-scalar.ll @@ -0,0 +1,135 @@ +; RUN: llc < %s -mtriple=i686-unknown-unknown -mattr=-sse -O3 | FileCheck %s --check-prefixes=CHECK,X87 +; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=-sse -O3 | FileCheck %s --check-prefixes=CHECK,X87 + +declare x86_fp80 @llvm.experimental.constrained.fadd.x86_fp80(x86_fp80, x86_fp80, metadata, metadata) +declare x86_fp80 @llvm.experimental.constrained.fsub.x86_fp80(x86_fp80, x86_fp80, metadata, metadata) +declare x86_fp80 @llvm.experimental.constrained.fmul.x86_fp80(x86_fp80, x86_fp80, metadata, metadata) +declare x86_fp80 @llvm.experimental.constrained.fdiv.x86_fp80(x86_fp80, x86_fp80, metadata, metadata) +declare x86_fp80 @llvm.experimental.constrained.fpext.x86_fp80.f32(float, metadata) +declare x86_fp80 @llvm.experimental.constrained.fpext.x86_fp80.f64(double, metadata) +declare x86_fp80 @llvm.experimental.constrained.sqrt.x86_fp80(x86_fp80, metadata, metadata) +declare float @llvm.experimental.constrained.fptrunc.x86_fp80.f32(x86_fp80, metadata, metadata) +declare double @llvm.experimental.constrained.fptrunc.x86_fp80.f64(x86_fp80, metadata, metadata) + +define x86_regcallcc x86_fp80 @fadd_fp80(x86_fp80 %a, x86_fp80 %b) #0 { +; X87-LABEL: fadd_fp80: +; X87: # %bb.0: +; X87-NEXT: fldt {{[0-9]+}}(%{{[r|e]}}sp) +; X87-NEXT: faddp %st, %st(1) +; X87-NEXT: ret{{[l|q]}} + %ret = call x86_fp80 @llvm.experimental.constrained.fadd.x86_fp80(x86_fp80 %a, x86_fp80 %b, + metadata !"round.dynamic", + metadata !"fpexcept.strict") #0 + ret x86_fp80 %ret +} + +define x86_regcallcc x86_fp80 @fsub_fp80(x86_fp80 %a, x86_fp80 %b) #0 { +; X87-LABEL: fsub_fp80: +; X87: # %bb.0: +; X87-NEXT: fldt {{[0-9]+}}(%{{[r|e]}}sp) +; X87-NEXT: fsubrp %st, %st(1) +; X87-NEXT: ret{{[l|q]}} + %ret = call x86_fp80 @llvm.experimental.constrained.fsub.x86_fp80(x86_fp80 %a, x86_fp80 %b, + metadata !"round.dynamic", + metadata !"fpexcept.strict") #0 + ret x86_fp80 %ret +} + +define x86_regcallcc x86_fp80 @fmul_fp80(x86_fp80 %a, x86_fp80 %b) #0 { +; X87-LABEL: fmul_fp80: +; X87: # %bb.0: +; X87-NEXT: fldt {{[0-9]+}}(%{{[r|e]}}sp) +; X87-NEXT: fmulp %st, %st(1) +; X87-NEXT: ret{{[l|q]}} + %ret = call x86_fp80 @llvm.experimental.constrained.fmul.x86_fp80(x86_fp80 %a, x86_fp80 %b, + metadata !"round.dynamic", + metadata !"fpexcept.strict") #0 + ret x86_fp80 %ret +} + +define x86_regcallcc x86_fp80 @fdiv_fp80(x86_fp80 %a, x86_fp80 %b) #0 { +; X87-LABEL: fdiv_fp80: +; X87: # %bb.0: +; X87-NEXT: fldt {{[0-9]+}}(%{{[r|e]}}sp) +; X87-NEXT: fdivrp %st, %st(1) +; X87-NEXT: ret{{[l|q]}} + %ret = call x86_fp80 @llvm.experimental.constrained.fdiv.x86_fp80(x86_fp80 %a, x86_fp80 %b, + metadata !"round.dynamic", + metadata !"fpexcept.strict") #0 + ret x86_fp80 %ret +} + +define x86_regcallcc void @fpext1(float* %val, x86_fp80* %ret) #0 { +; X87-LABEL: fpext1: +; X87: # %bb.0: +; X87-NEXT: flds (%{{[r|e]}}ax) +; X87-NEXT: fstpt (%{{[r|e]}}cx) +; X87-NEXT: ret{{[l|q]}} + %1 = load float, float* %val, align 4 + %res = call x86_fp80 @llvm.experimental.constrained.fpext.x86_fp80.f32(float %1, + metadata !"fpexcept.strict") #0 + store x86_fp80 %res, x86_fp80* %ret, align 16 + ret void +} + +define x86_regcallcc void @fpext2(double* %val, x86_fp80* %ret) #0 { +; X87-LABEL: fpext2: +; X87: # %bb.0: +; X87-NEXT: fldl (%{{[r|e]}}ax) +; X87-NEXT: fstpt (%{{[r|e]}}cx) +; X87-NEXT: ret{{[l|q]}} + %1 = load double, double* %val, align 8 + %res = call x86_fp80 @llvm.experimental.constrained.fpext.x86_fp80.f64(double %1, + metadata !"fpexcept.strict") #0 + store x86_fp80 %res, x86_fp80* %ret, align 16 + ret void +} + +define x86_regcallcc void @fptrunc1(x86_fp80* %val, float *%ret) #0 { +; X87-LABEL: fptrunc1: +; X87: # %bb.0: +; X87: fldt (%{{[r|e]}}ax) +; X87-NEXT: fstps {{.*}}(%{{[r|e]}}sp) +; X87-NEXT: flds {{.*}}(%{{[r|e]}}sp) +; X87-NEXT: fstps (%{{[r|e]}}cx) +; X87: ret{{[l|q]}} + %1 = load x86_fp80, x86_fp80* %val, align 16 + %res = call float @llvm.experimental.constrained.fptrunc.x86_fp80.f32(x86_fp80 %1, + metadata !"round.dynamic", + metadata !"fpexcept.strict") #0 + store float %res, float* %ret, align 4 + ret void +} + +define x86_regcallcc void @fptrunc2(x86_fp80* %val, double* %ret) #0 { +; X87-LABEL: fptrunc2: +; X87: # %bb.0: +; X87: fldt (%{{[r|e]}}ax) +; X87-NEXT: fstpl {{.*}}(%{{[r|e]}}sp) +; X87-NEXT: fldl {{.*}}(%{{[r|e]}}sp) +; X87-NEXT: fstpl (%{{[r|e]}}cx) +; X87: ret{{[l|q]}} + %1 = load x86_fp80, x86_fp80* %val, align 16 + %res = call double @llvm.experimental.constrained.fptrunc.x86_fp80.f64(x86_fp80 %1, + metadata !"round.dynamic", + metadata !"fpexcept.strict") #0 + store double %res, double* %ret, align 8 + ret void +} + +define x86_regcallcc void @fsqrt_fp80(x86_fp80* %a) #0 { +; X87-LABEL: fsqrt_fp80: +; X87: # %bb.0: +; X87-NEXT: fldt (%{{[r|e]}}ax) +; X87-NEXT: fsqrt +; X87-NEXT: fstpt (%{{[r|e]}}ax) +; X87-NEXT: ret{{[l|q]}} + %1 = load x86_fp80, x86_fp80* %a, align 16 + %res = call x86_fp80 @llvm.experimental.constrained.sqrt.x86_fp80(x86_fp80 %1, + metadata !"round.dynamic", + metadata !"fpexcept.strict") #0 + store x86_fp80 %res, x86_fp80* %a, align 16 + ret void +} + +attributes #0 = { strictfp }