Files
clang-p2996/llvm/test/CodeGen/X86/i128-fpconv-win64.ll
Martin Storsjö d6216e2cd1 [X86] Fix handling of i128<->fp on Windows
On Windows, i128 arguments are passed as indirect arguments, and
they are returned in xmm0.

This is mostly fixed up by `WinX86_64ABIInfo::classify` in Clang, making
the IR functions return v2i64 instead of i128, and making the arguments
indirect. However for cases where libcalls are generated in the target
lowering, the lowering uses the default x86_64 calling convention for
i128, where they are passed/returned as a register pair.

Add custom lowering logic, similar to the existing logic for i128
div/mod (added in 4a406d32e9),
manually making the libcall (while overriding the return type to
v2i64 or passing the arguments as pointers to arguments on the stack).

X86CallingConv.td doesn't seem to handle i128 at all, otherwise
the windows specific behaviours would ideally be implemented as
overrides there, in generic code, handling these cases automatically.

This fixes https://bugs.llvm.org/show_bug.cgi?id=48940.

Differential Revision: https://reviews.llvm.org/D110413
2021-09-29 13:05:59 +03:00

196 lines
6.0 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc < %s -mtriple=x86_64-win32 | FileCheck %s -check-prefix=WIN64
; RUN: llc < %s -mtriple=x86_64-mingw32 | FileCheck %s -check-prefix=WIN64
define i64 @double_to_i128(double %d) nounwind {
; WIN64-LABEL: double_to_i128:
; WIN64: # %bb.0:
; WIN64-NEXT: subq $40, %rsp
; WIN64-NEXT: callq __fixdfti
; WIN64-NEXT: movq %xmm0, %rax
; WIN64-NEXT: addq $40, %rsp
; WIN64-NEXT: retq
%1 = fptosi double %d to i128
%2 = trunc i128 %1 to i64
ret i64 %2
}
define i64 @double_to_ui128(double %d) nounwind {
; WIN64-LABEL: double_to_ui128:
; WIN64: # %bb.0:
; WIN64-NEXT: subq $40, %rsp
; WIN64-NEXT: callq __fixunsdfti
; WIN64-NEXT: movq %xmm0, %rax
; WIN64-NEXT: addq $40, %rsp
; WIN64-NEXT: retq
%1 = fptoui double %d to i128
%2 = trunc i128 %1 to i64
ret i64 %2
}
define i64 @float_to_i128(float %d) nounwind {
; WIN64-LABEL: float_to_i128:
; WIN64: # %bb.0:
; WIN64-NEXT: subq $40, %rsp
; WIN64-NEXT: callq __fixsfti
; WIN64-NEXT: movq %xmm0, %rax
; WIN64-NEXT: addq $40, %rsp
; WIN64-NEXT: retq
%1 = fptosi float %d to i128
%2 = trunc i128 %1 to i64
ret i64 %2
}
define i64 @float_to_ui128(float %d) nounwind {
; WIN64-LABEL: float_to_ui128:
; WIN64: # %bb.0:
; WIN64-NEXT: subq $40, %rsp
; WIN64-NEXT: callq __fixunssfti
; WIN64-NEXT: movq %xmm0, %rax
; WIN64-NEXT: addq $40, %rsp
; WIN64-NEXT: retq
%1 = fptoui float %d to i128
%2 = trunc i128 %1 to i64
ret i64 %2
}
define i64 @longdouble_to_i128(x86_fp80* nocapture readonly %0) nounwind {
; WIN64-LABEL: longdouble_to_i128:
; WIN64: # %bb.0:
; WIN64-NEXT: subq $56, %rsp
; WIN64-NEXT: fldt (%rcx)
; WIN64-NEXT: fstpt {{[0-9]+}}(%rsp)
; WIN64-NEXT: leaq {{[0-9]+}}(%rsp), %rcx
; WIN64-NEXT: callq __fixxfti
; WIN64-NEXT: movq %xmm0, %rax
; WIN64-NEXT: addq $56, %rsp
; WIN64-NEXT: retq
%2 = load x86_fp80, x86_fp80* %0, align 16
%3 = fptosi x86_fp80 %2 to i128
%4 = trunc i128 %3 to i64
ret i64 %4
}
define i64 @longdouble_to_ui128(x86_fp80* nocapture readonly %0) nounwind {
; WIN64-LABEL: longdouble_to_ui128:
; WIN64: # %bb.0:
; WIN64-NEXT: subq $56, %rsp
; WIN64-NEXT: fldt (%rcx)
; WIN64-NEXT: fstpt {{[0-9]+}}(%rsp)
; WIN64-NEXT: leaq {{[0-9]+}}(%rsp), %rcx
; WIN64-NEXT: callq __fixunsxfti
; WIN64-NEXT: movq %xmm0, %rax
; WIN64-NEXT: addq $56, %rsp
; WIN64-NEXT: retq
%2 = load x86_fp80, x86_fp80* %0, align 16
%3 = fptoui x86_fp80 %2 to i128
%4 = trunc i128 %3 to i64
ret i64 %4
}
define double @i128_to_double(i128* nocapture readonly %0) nounwind {
; WIN64-LABEL: i128_to_double:
; WIN64: # %bb.0:
; WIN64-NEXT: subq $56, %rsp
; WIN64-NEXT: movaps (%rcx), %xmm0
; WIN64-NEXT: movaps %xmm0, {{[0-9]+}}(%rsp)
; WIN64-NEXT: leaq {{[0-9]+}}(%rsp), %rcx
; WIN64-NEXT: callq __floattidf
; WIN64-NEXT: addq $56, %rsp
; WIN64-NEXT: retq
%2 = load i128, i128* %0, align 16
%3 = sitofp i128 %2 to double
ret double %3
}
define double @ui128_to_double(i128* nocapture readonly %0) nounwind {
; WIN64-LABEL: ui128_to_double:
; WIN64: # %bb.0:
; WIN64-NEXT: subq $56, %rsp
; WIN64-NEXT: movaps (%rcx), %xmm0
; WIN64-NEXT: movaps %xmm0, {{[0-9]+}}(%rsp)
; WIN64-NEXT: leaq {{[0-9]+}}(%rsp), %rcx
; WIN64-NEXT: callq __floatuntidf
; WIN64-NEXT: addq $56, %rsp
; WIN64-NEXT: retq
%2 = load i128, i128* %0, align 16
%3 = uitofp i128 %2 to double
ret double %3
}
define float @i128_to_float(i128* nocapture readonly %0) nounwind {
; WIN64-LABEL: i128_to_float:
; WIN64: # %bb.0:
; WIN64-NEXT: subq $56, %rsp
; WIN64-NEXT: movaps (%rcx), %xmm0
; WIN64-NEXT: movaps %xmm0, {{[0-9]+}}(%rsp)
; WIN64-NEXT: leaq {{[0-9]+}}(%rsp), %rcx
; WIN64-NEXT: callq __floattisf
; WIN64-NEXT: addq $56, %rsp
; WIN64-NEXT: retq
%2 = load i128, i128* %0, align 16
%3 = sitofp i128 %2 to float
ret float %3
}
define float @ui128_to_float(i128* nocapture readonly %0) nounwind {
; WIN64-LABEL: ui128_to_float:
; WIN64: # %bb.0:
; WIN64-NEXT: subq $56, %rsp
; WIN64-NEXT: movaps (%rcx), %xmm0
; WIN64-NEXT: movaps %xmm0, {{[0-9]+}}(%rsp)
; WIN64-NEXT: leaq {{[0-9]+}}(%rsp), %rcx
; WIN64-NEXT: callq __floatuntisf
; WIN64-NEXT: addq $56, %rsp
; WIN64-NEXT: retq
%2 = load i128, i128* %0, align 16
%3 = uitofp i128 %2 to float
ret float %3
}
define void @i128_to_longdouble(x86_fp80* noalias nocapture sret(x86_fp80) align 16 %agg.result, i128* nocapture readonly %0) nounwind {
; WIN64-LABEL: i128_to_longdouble:
; WIN64: # %bb.0:
; WIN64-NEXT: pushq %rsi
; WIN64-NEXT: subq $64, %rsp
; WIN64-NEXT: movq %rcx, %rsi
; WIN64-NEXT: movaps (%rdx), %xmm0
; WIN64-NEXT: movaps %xmm0, {{[0-9]+}}(%rsp)
; WIN64-NEXT: leaq {{[0-9]+}}(%rsp), %rcx
; WIN64-NEXT: leaq {{[0-9]+}}(%rsp), %rdx
; WIN64-NEXT: callq __floattixf
; WIN64-NEXT: fldt {{[0-9]+}}(%rsp)
; WIN64-NEXT: fstpt (%rsi)
; WIN64-NEXT: movq %rsi, %rax
; WIN64-NEXT: addq $64, %rsp
; WIN64-NEXT: popq %rsi
; WIN64-NEXT: retq
%2 = load i128, i128* %0, align 16
%3 = sitofp i128 %2 to x86_fp80
store x86_fp80 %3, x86_fp80* %agg.result, align 16
ret void
}
define void @ui128_to_longdouble(x86_fp80* noalias nocapture sret(x86_fp80) align 16 %agg.result, i128* nocapture readonly %0) nounwind {
; WIN64-LABEL: ui128_to_longdouble:
; WIN64: # %bb.0:
; WIN64-NEXT: pushq %rsi
; WIN64-NEXT: subq $64, %rsp
; WIN64-NEXT: movq %rcx, %rsi
; WIN64-NEXT: movaps (%rdx), %xmm0
; WIN64-NEXT: movaps %xmm0, {{[0-9]+}}(%rsp)
; WIN64-NEXT: leaq {{[0-9]+}}(%rsp), %rcx
; WIN64-NEXT: leaq {{[0-9]+}}(%rsp), %rdx
; WIN64-NEXT: callq __floatuntixf
; WIN64-NEXT: fldt {{[0-9]+}}(%rsp)
; WIN64-NEXT: fstpt (%rsi)
; WIN64-NEXT: movq %rsi, %rax
; WIN64-NEXT: addq $64, %rsp
; WIN64-NEXT: popq %rsi
; WIN64-NEXT: retq
%2 = load i128, i128* %0, align 16
%3 = uitofp i128 %2 to x86_fp80
store x86_fp80 %3, x86_fp80* %agg.result, align 16
ret void
}