blob: 4eb8b693101da696e39e938a42770f3fbd49e53a [file] [edit]
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc < %s -mtriple=x86_64-- -mattr=+sse4.2 | FileCheck %s
; Verify when widening a divide/remainder operation, we only generate a
; divide/rem per element since divide/remainder can trap.
define void @div_extract(ptr %dst, ptr %lhs, ptr %rhs) nounwind {
; CHECK-LABEL: div_extract:
; CHECK: # %bb.0:
; CHECK-NEXT: movzwl (%rsi), %eax
; CHECK-NEXT: movd %eax, %xmm0
; CHECK-NEXT: movzwl (%rdx), %eax
; CHECK-NEXT: movd %eax, %xmm1
; CHECK-NEXT: pmovzxbd {{.*#+}} xmm1 = xmm1[0],zero,zero,zero,xmm1[1],zero,zero,zero,xmm1[2],zero,zero,zero,xmm1[3],zero,zero,zero
; CHECK-NEXT: cvtdq2ps %xmm1, %xmm1
; CHECK-NEXT: pmovzxbd {{.*#+}} xmm0 = xmm0[0],zero,zero,zero,xmm0[1],zero,zero,zero,xmm0[2],zero,zero,zero,xmm0[3],zero,zero,zero
; CHECK-NEXT: cvtdq2ps %xmm0, %xmm0
; CHECK-NEXT: divps %xmm1, %xmm0
; CHECK-NEXT: cvttps2dq %xmm0, %xmm0
; CHECK-NEXT: pextrb $0, %xmm0, (%rdi)
; CHECK-NEXT: pextrb $4, %xmm0, 1(%rdi)
; CHECK-NEXT: retq
%a = load <2 x i8>, ptr %lhs
%b = load <2 x i8>, ptr %rhs
%quot = udiv <2 x i8> %a, %b
%elt0 = extractelement <2 x i8> %quot, i64 0
store i8 %elt0, ptr %dst, align 1
%next = getelementptr inbounds nuw i8, ptr %dst, i64 1
%elt1 = extractelement <2 x i8> %quot, i64 1
store i8 %elt1, ptr %next, align 1
ret void
}
define void @vectorDiv (ptr addrspace(1) %nsource, ptr addrspace(1) %dsource, ptr addrspace(1) %qdest) nounwind {
; CHECK-LABEL: vectorDiv:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: movq %rdi, -{{[0-9]+}}(%rsp)
; CHECK-NEXT: movq %rsi, -{{[0-9]+}}(%rsp)
; CHECK-NEXT: movq %rdx, -{{[0-9]+}}(%rsp)
; CHECK-NEXT: movslq -{{[0-9]+}}(%rsp), %rax
; CHECK-NEXT: cvtdq2pd (%rsi,%rax,8), %xmm0
; CHECK-NEXT: cvtdq2pd (%rdi,%rax,8), %xmm1
; CHECK-NEXT: divpd %xmm0, %xmm1
; CHECK-NEXT: cvttpd2dq %xmm1, %xmm0
; CHECK-NEXT: movlpd %xmm0, (%rdx,%rax,8)
; CHECK-NEXT: retq
entry:
%nsource.addr = alloca ptr addrspace(1), align 4
%dsource.addr = alloca ptr addrspace(1), align 4
%qdest.addr = alloca ptr addrspace(1), align 4
%index = alloca i32, align 4
store ptr addrspace(1) %nsource, ptr %nsource.addr
store ptr addrspace(1) %dsource, ptr %dsource.addr
store ptr addrspace(1) %qdest, ptr %qdest.addr
%tmp = load ptr addrspace(1), ptr %qdest.addr
%tmp1 = load i32, ptr %index
%arrayidx = getelementptr <2 x i32>, ptr addrspace(1) %tmp, i32 %tmp1
%tmp2 = load ptr addrspace(1), ptr %nsource.addr
%tmp3 = load i32, ptr %index
%arrayidx4 = getelementptr <2 x i32>, ptr addrspace(1) %tmp2, i32 %tmp3
%tmp5 = load <2 x i32>, ptr addrspace(1) %arrayidx4
%tmp6 = load ptr addrspace(1), ptr %dsource.addr
%tmp7 = load i32, ptr %index
%arrayidx8 = getelementptr <2 x i32>, ptr addrspace(1) %tmp6, i32 %tmp7
%tmp9 = load <2 x i32>, ptr addrspace(1) %arrayidx8
%tmp10 = sdiv <2 x i32> %tmp5, %tmp9
store <2 x i32> %tmp10, ptr addrspace(1) %arrayidx
ret void
}
define <3 x i8> @test_char_div(<3 x i8> %num, <3 x i8> %div) {
; CHECK-LABEL: test_char_div:
; CHECK: # %bb.0:
; CHECK-NEXT: movd %edi, %xmm0
; CHECK-NEXT: pinsrb $1, %esi, %xmm0
; CHECK-NEXT: pinsrb $2, %edx, %xmm0
; CHECK-NEXT: movd %ecx, %xmm1
; CHECK-NEXT: pinsrb $1, %r8d, %xmm1
; CHECK-NEXT: pinsrb $2, %r9d, %xmm1
; CHECK-NEXT: pmovsxbd %xmm1, %xmm1
; CHECK-NEXT: cvtdq2ps %xmm1, %xmm1
; CHECK-NEXT: pmovsxbd %xmm0, %xmm0
; CHECK-NEXT: cvtdq2ps %xmm0, %xmm0
; CHECK-NEXT: divps %xmm1, %xmm0
; CHECK-NEXT: cvttps2dq %xmm0, %xmm0
; CHECK-NEXT: packssdw %xmm0, %xmm0
; CHECK-NEXT: packsswb %xmm0, %xmm0
; CHECK-NEXT: movd %xmm0, %eax
; CHECK-NEXT: pextrb $1, %xmm0, %edx
; CHECK-NEXT: pextrb $2, %xmm0, %ecx
; CHECK-NEXT: # kill: def $al killed $al killed $eax
; CHECK-NEXT: # kill: def $dl killed $dl killed $edx
; CHECK-NEXT: # kill: def $cl killed $cl killed $ecx
; CHECK-NEXT: retq
%div.r = sdiv <3 x i8> %num, %div
ret <3 x i8> %div.r
}
define <3 x i8> @test_uchar_div(<3 x i8> %num, <3 x i8> %div) {
; CHECK-LABEL: test_uchar_div:
; CHECK: # %bb.0:
; CHECK-NEXT: movd %edi, %xmm0
; CHECK-NEXT: pinsrb $1, %esi, %xmm0
; CHECK-NEXT: pinsrb $2, %edx, %xmm0
; CHECK-NEXT: movd %ecx, %xmm1
; CHECK-NEXT: pinsrb $1, %r8d, %xmm1
; CHECK-NEXT: pinsrb $2, %r9d, %xmm1
; CHECK-NEXT: pmovzxbd {{.*#+}} xmm1 = xmm1[0],zero,zero,zero,xmm1[1],zero,zero,zero,xmm1[2],zero,zero,zero,xmm1[3],zero,zero,zero
; CHECK-NEXT: cvtdq2ps %xmm1, %xmm1
; CHECK-NEXT: pmovzxbd {{.*#+}} xmm0 = xmm0[0],zero,zero,zero,xmm0[1],zero,zero,zero,xmm0[2],zero,zero,zero,xmm0[3],zero,zero,zero
; CHECK-NEXT: cvtdq2ps %xmm0, %xmm0
; CHECK-NEXT: divps %xmm1, %xmm0
; CHECK-NEXT: cvttps2dq %xmm0, %xmm0
; CHECK-NEXT: packusdw %xmm0, %xmm0
; CHECK-NEXT: packuswb %xmm0, %xmm0
; CHECK-NEXT: movd %xmm0, %eax
; CHECK-NEXT: pextrb $1, %xmm0, %edx
; CHECK-NEXT: pextrb $2, %xmm0, %ecx
; CHECK-NEXT: # kill: def $al killed $al killed $eax
; CHECK-NEXT: # kill: def $dl killed $dl killed $edx
; CHECK-NEXT: # kill: def $cl killed $cl killed $ecx
; CHECK-NEXT: retq
%div.r = udiv <3 x i8> %num, %div
ret <3 x i8> %div.r
}
define <5 x i16> @test_short_div(<5 x i16> %num, <5 x i16> %div) {
; CHECK-LABEL: test_short_div:
; CHECK: # %bb.0:
; CHECK-NEXT: pmovsxwd %xmm1, %xmm2
; CHECK-NEXT: cvtdq2ps %xmm2, %xmm2
; CHECK-NEXT: pmovsxwd %xmm0, %xmm3
; CHECK-NEXT: cvtdq2ps %xmm3, %xmm3
; CHECK-NEXT: divps %xmm2, %xmm3
; CHECK-NEXT: cvttps2dq %xmm3, %xmm2
; CHECK-NEXT: packssdw %xmm2, %xmm2
; CHECK-NEXT: pshufd {{.*#+}} xmm1 = xmm1[2,3,2,3]
; CHECK-NEXT: pmovsxwd %xmm1, %xmm1
; CHECK-NEXT: cvtdq2ps %xmm1, %xmm1
; CHECK-NEXT: pshufd {{.*#+}} xmm0 = xmm0[2,3,2,3]
; CHECK-NEXT: pmovsxwd %xmm0, %xmm0
; CHECK-NEXT: cvtdq2ps %xmm0, %xmm0
; CHECK-NEXT: divps %xmm1, %xmm0
; CHECK-NEXT: cvttps2dq %xmm0, %xmm0
; CHECK-NEXT: punpcklqdq {{.*#+}} xmm2 = xmm2[0],xmm0[0]
; CHECK-NEXT: movdqa %xmm2, %xmm0
; CHECK-NEXT: retq
%div.r = sdiv <5 x i16> %num, %div
ret <5 x i16> %div.r
}
define <4 x i16> @test_ushort_div(<4 x i16> %num, <4 x i16> %div) {
; CHECK-LABEL: test_ushort_div:
; CHECK: # %bb.0:
; CHECK-NEXT: pmovzxwd {{.*#+}} xmm1 = xmm1[0],zero,xmm1[1],zero,xmm1[2],zero,xmm1[3],zero
; CHECK-NEXT: cvtdq2ps %xmm1, %xmm1
; CHECK-NEXT: pmovzxwd {{.*#+}} xmm0 = xmm0[0],zero,xmm0[1],zero,xmm0[2],zero,xmm0[3],zero
; CHECK-NEXT: cvtdq2ps %xmm0, %xmm0
; CHECK-NEXT: divps %xmm1, %xmm0
; CHECK-NEXT: cvttps2dq %xmm0, %xmm0
; CHECK-NEXT: packusdw %xmm0, %xmm0
; CHECK-NEXT: retq
%div.r = udiv <4 x i16> %num, %div
ret <4 x i16> %div.r
}
define <3 x i32> @test_uint_div(<3 x i32> %num, <3 x i32> %div) {
; CHECK-LABEL: test_uint_div:
; CHECK: # %bb.0:
; CHECK-NEXT: pextrd $2, %xmm0, %eax
; CHECK-NEXT: pextrd $2, %xmm1, %ecx
; CHECK-NEXT: xorl %edx, %edx
; CHECK-NEXT: divl %ecx
; CHECK-NEXT: movl %eax, %ecx
; CHECK-NEXT: pextrd $1, %xmm0, %eax
; CHECK-NEXT: pextrd $1, %xmm1, %esi
; CHECK-NEXT: xorl %edx, %edx
; CHECK-NEXT: divl %esi
; CHECK-NEXT: movl %eax, %esi
; CHECK-NEXT: movd %xmm0, %eax
; CHECK-NEXT: movd %xmm1, %edi
; CHECK-NEXT: xorl %edx, %edx
; CHECK-NEXT: divl %edi
; CHECK-NEXT: movd %eax, %xmm0
; CHECK-NEXT: pinsrd $1, %esi, %xmm0
; CHECK-NEXT: pinsrd $2, %ecx, %xmm0
; CHECK-NEXT: retq
%div.r = udiv <3 x i32> %num, %div
ret <3 x i32> %div.r
}
define <3 x i64> @test_long_div(<3 x i64> %num, <3 x i64> %div) {
; CHECK-LABEL: test_long_div:
; CHECK: # %bb.0:
; CHECK-NEXT: movq %rdx, %r10
; CHECK-NEXT: movq %rdi, %rax
; CHECK-NEXT: cqto
; CHECK-NEXT: idivq %rcx
; CHECK-NEXT: movq %rax, %rcx
; CHECK-NEXT: movq %rsi, %rax
; CHECK-NEXT: cqto
; CHECK-NEXT: idivq %r8
; CHECK-NEXT: movq %rax, %rsi
; CHECK-NEXT: movq %r10, %rax
; CHECK-NEXT: cqto
; CHECK-NEXT: idivq %r9
; CHECK-NEXT: movq %rax, %rdi
; CHECK-NEXT: movq %rcx, %rax
; CHECK-NEXT: movq %rsi, %rdx
; CHECK-NEXT: movq %rdi, %rcx
; CHECK-NEXT: retq
%div.r = sdiv <3 x i64> %num, %div
ret <3 x i64> %div.r
}
define <3 x i64> @test_ulong_div(<3 x i64> %num, <3 x i64> %div) {
; CHECK-LABEL: test_ulong_div:
; CHECK: # %bb.0:
; CHECK-NEXT: movq %rdx, %r10
; CHECK-NEXT: movq %rdi, %rax
; CHECK-NEXT: xorl %edx, %edx
; CHECK-NEXT: divq %rcx
; CHECK-NEXT: movq %rax, %rcx
; CHECK-NEXT: movq %rsi, %rax
; CHECK-NEXT: xorl %edx, %edx
; CHECK-NEXT: divq %r8
; CHECK-NEXT: movq %rax, %rsi
; CHECK-NEXT: movq %r10, %rax
; CHECK-NEXT: xorl %edx, %edx
; CHECK-NEXT: divq %r9
; CHECK-NEXT: movq %rax, %rdi
; CHECK-NEXT: movq %rcx, %rax
; CHECK-NEXT: movq %rsi, %rdx
; CHECK-NEXT: movq %rdi, %rcx
; CHECK-NEXT: retq
%div.r = udiv <3 x i64> %num, %div
ret <3 x i64> %div.r
}
define <4 x i8> @test_char_rem(<4 x i8> %num, <4 x i8> %rem) {
; CHECK-LABEL: test_char_rem:
; CHECK: # %bb.0:
; CHECK-NEXT: pmovsxbd %xmm1, %xmm2
; CHECK-NEXT: cvtdq2ps %xmm2, %xmm2
; CHECK-NEXT: pmovsxbd %xmm0, %xmm3
; CHECK-NEXT: cvtdq2ps %xmm3, %xmm3
; CHECK-NEXT: divps %xmm2, %xmm3
; CHECK-NEXT: cvttps2dq %xmm3, %xmm2
; CHECK-NEXT: packssdw %xmm2, %xmm2
; CHECK-NEXT: pmovzxbw {{.*#+}} xmm1 = xmm1[0],zero,xmm1[1],zero,xmm1[2],zero,xmm1[3],zero,xmm1[4],zero,xmm1[5],zero,xmm1[6],zero,xmm1[7],zero
; CHECK-NEXT: pmullw %xmm2, %xmm1
; CHECK-NEXT: pshufb {{.*#+}} xmm1 = xmm1[0,2,4,6,u,u,u,u,u,u,u,u,u,u,u,u]
; CHECK-NEXT: psubb %xmm1, %xmm0
; CHECK-NEXT: retq
%rem.r = srem <4 x i8> %num, %rem
ret <4 x i8> %rem.r
}
define <5 x i16> @test_short_rem(<5 x i16> %num, <5 x i16> %rem) {
; CHECK-LABEL: test_short_rem:
; CHECK: # %bb.0:
; CHECK-NEXT: pmovsxwd %xmm1, %xmm2
; CHECK-NEXT: cvtdq2ps %xmm2, %xmm2
; CHECK-NEXT: pmovsxwd %xmm0, %xmm3
; CHECK-NEXT: cvtdq2ps %xmm3, %xmm3
; CHECK-NEXT: divps %xmm2, %xmm3
; CHECK-NEXT: cvttps2dq %xmm3, %xmm2
; CHECK-NEXT: packssdw %xmm2, %xmm2
; CHECK-NEXT: pshufd {{.*#+}} xmm3 = xmm1[2,3,2,3]
; CHECK-NEXT: pmovsxwd %xmm3, %xmm3
; CHECK-NEXT: cvtdq2ps %xmm3, %xmm3
; CHECK-NEXT: pshufd {{.*#+}} xmm4 = xmm0[2,3,2,3]
; CHECK-NEXT: pmovsxwd %xmm4, %xmm4
; CHECK-NEXT: cvtdq2ps %xmm4, %xmm4
; CHECK-NEXT: divps %xmm3, %xmm4
; CHECK-NEXT: cvttps2dq %xmm4, %xmm3
; CHECK-NEXT: punpcklqdq {{.*#+}} xmm2 = xmm2[0],xmm3[0]
; CHECK-NEXT: pmullw %xmm1, %xmm2
; CHECK-NEXT: psubw %xmm2, %xmm0
; CHECK-NEXT: retq
%rem.r = srem <5 x i16> %num, %rem
ret <5 x i16> %rem.r
}
define <4 x i32> @test_uint_rem(<4 x i32> %num, <4 x i32> %rem) {
; CHECK-LABEL: test_uint_rem:
; CHECK: # %bb.0:
; CHECK-NEXT: cvtdq2pd %xmm1, %xmm2
; CHECK-NEXT: cvtdq2pd %xmm0, %xmm3
; CHECK-NEXT: divpd %xmm2, %xmm3
; CHECK-NEXT: cvttpd2dq %xmm3, %xmm2
; CHECK-NEXT: pshufd {{.*#+}} xmm3 = xmm1[2,3,2,3]
; CHECK-NEXT: cvtdq2pd %xmm3, %xmm3
; CHECK-NEXT: pshufd {{.*#+}} xmm4 = xmm0[2,3,2,3]
; CHECK-NEXT: cvtdq2pd %xmm4, %xmm4
; CHECK-NEXT: divpd %xmm3, %xmm4
; CHECK-NEXT: cvttpd2dq %xmm4, %xmm3
; CHECK-NEXT: unpcklpd {{.*#+}} xmm2 = xmm2[0],xmm3[0]
; CHECK-NEXT: pmulld %xmm1, %xmm2
; CHECK-NEXT: psubd %xmm2, %xmm0
; CHECK-NEXT: retq
%rem.r = srem <4 x i32> %num, %rem
ret <4 x i32> %rem.r
}
define <5 x i64> @test_ulong_rem(<5 x i64> %num, <5 x i64> %rem) {
; CHECK-LABEL: test_ulong_rem:
; CHECK: # %bb.0:
; CHECK-NEXT: movq %rdx, %rax
; CHECK-NEXT: xorl %edx, %edx
; CHECK-NEXT: divq {{[0-9]+}}(%rsp)
; CHECK-NEXT: movq %rdx, %xmm0
; CHECK-NEXT: movq %rsi, %rax
; CHECK-NEXT: xorl %edx, %edx
; CHECK-NEXT: divq {{[0-9]+}}(%rsp)
; CHECK-NEXT: movq %rdx, %xmm1
; CHECK-NEXT: punpcklqdq {{.*#+}} xmm1 = xmm1[0],xmm0[0]
; CHECK-NEXT: movq %r8, %rax
; CHECK-NEXT: xorl %edx, %edx
; CHECK-NEXT: divq {{[0-9]+}}(%rsp)
; CHECK-NEXT: movq %rdx, %xmm0
; CHECK-NEXT: movq %rcx, %rax
; CHECK-NEXT: xorl %edx, %edx
; CHECK-NEXT: divq {{[0-9]+}}(%rsp)
; CHECK-NEXT: movq %rdx, %xmm2
; CHECK-NEXT: punpcklqdq {{.*#+}} xmm2 = xmm2[0],xmm0[0]
; CHECK-NEXT: movq %r9, %rax
; CHECK-NEXT: xorl %edx, %edx
; CHECK-NEXT: divq {{[0-9]+}}(%rsp)
; CHECK-NEXT: movq %rdx, 32(%rdi)
; CHECK-NEXT: movdqa %xmm2, 16(%rdi)
; CHECK-NEXT: movdqa %xmm1, (%rdi)
; CHECK-NEXT: movq %rdi, %rax
; CHECK-NEXT: retq
%rem.r = urem <5 x i64> %num, %rem
ret <5 x i64> %rem.r
}
define void @test_int_div(ptr %dest, ptr %old, i32 %n) {
; CHECK-LABEL: test_int_div:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: testl %edx, %edx
; CHECK-NEXT: jle .LBB13_3
; CHECK-NEXT: # %bb.1: # %bb.nph
; CHECK-NEXT: xorl %eax, %eax
; CHECK-NEXT: .p2align 4
; CHECK-NEXT: .LBB13_2: # %for.body
; CHECK-NEXT: # =>This Inner Loop Header: Depth=1
; CHECK-NEXT: movdqa (%rdi,%rax), %xmm0
; CHECK-NEXT: movdqa (%rsi,%rax), %xmm1
; CHECK-NEXT: pshufd {{.*#+}} xmm2 = xmm1[2,3,2,3]
; CHECK-NEXT: cvtdq2pd %xmm2, %xmm2
; CHECK-NEXT: pshufd {{.*#+}} xmm3 = xmm0[2,3,2,3]
; CHECK-NEXT: cvtdq2pd %xmm3, %xmm3
; CHECK-NEXT: divpd %xmm2, %xmm3
; CHECK-NEXT: cvttpd2dq %xmm3, %xmm2
; CHECK-NEXT: cvtdq2pd %xmm1, %xmm1
; CHECK-NEXT: cvtdq2pd %xmm0, %xmm0
; CHECK-NEXT: divpd %xmm1, %xmm0
; CHECK-NEXT: cvttpd2dq %xmm0, %xmm0
; CHECK-NEXT: movlpd %xmm0, (%rdi,%rax)
; CHECK-NEXT: movss %xmm2, 8(%rdi,%rax)
; CHECK-NEXT: addq $16, %rax
; CHECK-NEXT: decl %edx
; CHECK-NEXT: jne .LBB13_2
; CHECK-NEXT: .LBB13_3: # %for.end
; CHECK-NEXT: retq
entry:
%cmp13 = icmp sgt i32 %n, 0
br i1 %cmp13, label %bb.nph, label %for.end
bb.nph:
br label %for.body
for.body:
%i.014 = phi i32 [ 0, %bb.nph ], [ %inc, %for.body ]
%arrayidx11 = getelementptr <3 x i32>, ptr %dest, i32 %i.014
%tmp4 = load <3 x i32>, ptr %arrayidx11 ; <<3 x i32>> [#uses=1]
%arrayidx7 = getelementptr inbounds <3 x i32>, ptr %old, i32 %i.014
%tmp8 = load <3 x i32>, ptr %arrayidx7 ; <<3 x i32>> [#uses=1]
%div = sdiv <3 x i32> %tmp4, %tmp8
store <3 x i32> %div, ptr %arrayidx11
%inc = add nsw i32 %i.014, 1
%exitcond = icmp eq i32 %inc, %n
br i1 %exitcond, label %for.end, label %for.body
for.end: ; preds = %for.body, %entry
ret void
}