Files
clang-p2996/llvm/test/CodeGen/RISCV/rvv/fold-binary-reduce.ll
Michael Maitland 142787d368 [RISCV][VLOPT] Add support for checkUsers when UserMI is a Single-Width Integer Reduction (#120345)
Reductions are weird because for some operands, they are vector
registers but only read the first lane. For these operands, we do not
need to check to make sure the EEW and EMUL ratios match. The EEWs,
however, do need to match.
2025-01-07 17:56:07 -05:00

444 lines
14 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=riscv64 -mattr=+d,+zvfh,+v,+zbb -target-abi=lp64d -verify-machineinstrs < %s | FileCheck %s
define i64 @reduce_add(i64 %x, <4 x i64> %v) {
; CHECK-LABEL: reduce_add:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: vsetivli zero, 4, e64, m2, ta, ma
; CHECK-NEXT: vmv.s.x v10, a0
; CHECK-NEXT: vredsum.vs v8, v8, v10
; CHECK-NEXT: vmv.x.s a0, v8
; CHECK-NEXT: ret
entry:
%rdx = call i64 @llvm.vector.reduce.add.v4i64(<4 x i64> %v)
%res = add i64 %rdx, %x
ret i64 %res
}
define i64 @reduce_add2(<4 x i64> %v) {
; CHECK-LABEL: reduce_add2:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: vsetivli zero, 1, e64, m1, ta, ma
; CHECK-NEXT: vmv.v.i v10, 8
; CHECK-NEXT: vsetivli zero, 4, e64, m2, ta, ma
; CHECK-NEXT: vredsum.vs v8, v8, v10
; CHECK-NEXT: vmv.x.s a0, v8
; CHECK-NEXT: ret
entry:
%rdx = call i64 @llvm.vector.reduce.add.v4i64(<4 x i64> %v)
%res = add i64 %rdx, 8
ret i64 %res
}
define i64 @reduce_and(i64 %x, <4 x i64> %v) {
; CHECK-LABEL: reduce_and:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: vsetivli zero, 4, e64, m2, ta, ma
; CHECK-NEXT: vredand.vs v8, v8, v8
; CHECK-NEXT: vmv.x.s a1, v8
; CHECK-NEXT: and a0, a1, a0
; CHECK-NEXT: ret
entry:
%rdx = call i64 @llvm.vector.reduce.and.v4i64(<4 x i64> %v)
%res = and i64 %rdx, %x
ret i64 %res
}
define i64 @reduce_and2(<4 x i64> %v) {
; CHECK-LABEL: reduce_and2:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: vsetivli zero, 4, e64, m2, ta, ma
; CHECK-NEXT: vredand.vs v8, v8, v8
; CHECK-NEXT: vmv.x.s a0, v8
; CHECK-NEXT: andi a0, a0, 8
; CHECK-NEXT: ret
entry:
%rdx = call i64 @llvm.vector.reduce.and.v4i64(<4 x i64> %v)
%res = and i64 %rdx, 8
ret i64 %res
}
define i64 @reduce_or(i64 %x, <4 x i64> %v) {
; CHECK-LABEL: reduce_or:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: vsetivli zero, 4, e64, m2, ta, ma
; CHECK-NEXT: vredor.vs v8, v8, v8
; CHECK-NEXT: vmv.x.s a1, v8
; CHECK-NEXT: or a0, a1, a0
; CHECK-NEXT: ret
entry:
%rdx = call i64 @llvm.vector.reduce.or.v4i64(<4 x i64> %v)
%res = or i64 %rdx, %x
ret i64 %res
}
define i64 @reduce_or2(<4 x i64> %v) {
; CHECK-LABEL: reduce_or2:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: vsetivli zero, 4, e64, m2, ta, ma
; CHECK-NEXT: vredor.vs v8, v8, v8
; CHECK-NEXT: vmv.x.s a0, v8
; CHECK-NEXT: ori a0, a0, 8
; CHECK-NEXT: ret
entry:
%rdx = call i64 @llvm.vector.reduce.or.v4i64(<4 x i64> %v)
%res = or i64 %rdx, 8
ret i64 %res
}
define i64 @reduce_xor(i64 %x, <4 x i64> %v) {
; CHECK-LABEL: reduce_xor:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: vsetivli zero, 4, e64, m2, ta, ma
; CHECK-NEXT: vmv.s.x v10, a0
; CHECK-NEXT: vredxor.vs v8, v8, v10
; CHECK-NEXT: vmv.x.s a0, v8
; CHECK-NEXT: ret
entry:
%rdx = call i64 @llvm.vector.reduce.xor.v4i64(<4 x i64> %v)
%res = xor i64 %rdx, %x
ret i64 %res
}
define i64 @reduce_xor2(<4 x i64> %v) {
; CHECK-LABEL: reduce_xor2:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: vsetivli zero, 4, e64, m2, ta, ma
; CHECK-NEXT: vmv.s.x v10, zero
; CHECK-NEXT: vredxor.vs v8, v8, v10
; CHECK-NEXT: vmv.x.s a0, v8
; CHECK-NEXT: andi a0, a0, 8
; CHECK-NEXT: ret
entry:
%rdx = call i64 @llvm.vector.reduce.xor.v4i64(<4 x i64> %v)
%res = and i64 %rdx, 8
ret i64 %res
}
define i64 @reduce_umax(i64 %x, <4 x i64> %v) {
; CHECK-LABEL: reduce_umax:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: vsetivli zero, 4, e64, m2, ta, ma
; CHECK-NEXT: vredmaxu.vs v8, v8, v8
; CHECK-NEXT: vmv.x.s a1, v8
; CHECK-NEXT: maxu a0, a1, a0
; CHECK-NEXT: ret
entry:
%rdx = call i64 @llvm.vector.reduce.umax.v4i64(<4 x i64> %v)
%res = call i64 @llvm.umax.i64(i64 %rdx, i64 %x)
ret i64 %res
}
define i64 @reduce_umax2(<4 x i64> %v) {
; CHECK-LABEL: reduce_umax2:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: vsetivli zero, 4, e64, m2, ta, ma
; CHECK-NEXT: vredmaxu.vs v8, v8, v8
; CHECK-NEXT: vmv.x.s a0, v8
; CHECK-NEXT: li a1, 8
; CHECK-NEXT: maxu a0, a0, a1
; CHECK-NEXT: ret
entry:
%rdx = call i64 @llvm.vector.reduce.umax.v4i64(<4 x i64> %v)
%res = call i64 @llvm.umax.i64(i64 %rdx, i64 8)
ret i64 %res
}
define i64 @reduce_umin(i64 %x, <4 x i64> %v) {
; CHECK-LABEL: reduce_umin:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: vsetivli zero, 4, e64, m2, ta, ma
; CHECK-NEXT: vredminu.vs v8, v8, v8
; CHECK-NEXT: vmv.x.s a1, v8
; CHECK-NEXT: minu a0, a1, a0
; CHECK-NEXT: ret
entry:
%rdx = call i64 @llvm.vector.reduce.umin.v4i64(<4 x i64> %v)
%res = call i64 @llvm.umin.i64(i64 %rdx, i64 %x)
ret i64 %res
}
define i64 @reduce_umin2(<4 x i64> %v) {
; CHECK-LABEL: reduce_umin2:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: vsetivli zero, 4, e64, m2, ta, ma
; CHECK-NEXT: vredminu.vs v8, v8, v8
; CHECK-NEXT: vmv.x.s a0, v8
; CHECK-NEXT: li a1, 8
; CHECK-NEXT: minu a0, a0, a1
; CHECK-NEXT: ret
entry:
%rdx = call i64 @llvm.vector.reduce.umin.v4i64(<4 x i64> %v)
%res = call i64 @llvm.umin.i64(i64 %rdx, i64 8)
ret i64 %res
}
define i64 @reduce_smax(i64 %x, <4 x i64> %v) {
; CHECK-LABEL: reduce_smax:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: vsetivli zero, 4, e64, m2, ta, ma
; CHECK-NEXT: vredmax.vs v8, v8, v8
; CHECK-NEXT: vmv.x.s a1, v8
; CHECK-NEXT: max a0, a1, a0
; CHECK-NEXT: ret
entry:
%rdx = call i64 @llvm.vector.reduce.smax.v4i64(<4 x i64> %v)
%res = call i64 @llvm.smax.i64(i64 %rdx, i64 %x)
ret i64 %res
}
define i64 @reduce_smax2(<4 x i64> %v) {
; CHECK-LABEL: reduce_smax2:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: vsetivli zero, 4, e64, m2, ta, ma
; CHECK-NEXT: vredmax.vs v8, v8, v8
; CHECK-NEXT: vmv.x.s a0, v8
; CHECK-NEXT: li a1, 8
; CHECK-NEXT: max a0, a0, a1
; CHECK-NEXT: ret
entry:
%rdx = call i64 @llvm.vector.reduce.smax.v4i64(<4 x i64> %v)
%res = call i64 @llvm.smax.i64(i64 %rdx, i64 8)
ret i64 %res
}
define i64 @reduce_smin(i64 %x, <4 x i64> %v) {
; CHECK-LABEL: reduce_smin:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: vsetivli zero, 4, e64, m2, ta, ma
; CHECK-NEXT: vredmin.vs v8, v8, v8
; CHECK-NEXT: vmv.x.s a1, v8
; CHECK-NEXT: min a0, a1, a0
; CHECK-NEXT: ret
entry:
%rdx = call i64 @llvm.vector.reduce.smin.v4i64(<4 x i64> %v)
%res = call i64 @llvm.smin.i64(i64 %rdx, i64 %x)
ret i64 %res
}
define i64 @reduce_smin2(<4 x i64> %v) {
; CHECK-LABEL: reduce_smin2:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: vsetivli zero, 4, e64, m2, ta, ma
; CHECK-NEXT: vredmin.vs v8, v8, v8
; CHECK-NEXT: vmv.x.s a0, v8
; CHECK-NEXT: li a1, 8
; CHECK-NEXT: min a0, a0, a1
; CHECK-NEXT: ret
entry:
%rdx = call i64 @llvm.vector.reduce.smin.v4i64(<4 x i64> %v)
%res = call i64 @llvm.smin.i64(i64 %rdx, i64 8)
ret i64 %res
}
define float @reduce_fadd(float %x, <4 x float> %v) {
; CHECK-LABEL: reduce_fadd:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: vsetivli zero, 4, e32, m1, ta, ma
; CHECK-NEXT: vfmv.s.f v9, fa0
; CHECK-NEXT: vfredusum.vs v8, v8, v9
; CHECK-NEXT: vfmv.f.s fa0, v8
; CHECK-NEXT: ret
entry:
%rdx = call fast float @llvm.vector.reduce.fadd.v4f32(float %x, <4 x float> %v)
ret float %rdx
}
define float @reduce_fadd2(float %x, <4 x float> %v) {
; CHECK-LABEL: reduce_fadd2:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: vsetivli zero, 4, e32, m1, ta, ma
; CHECK-NEXT: vfmv.s.f v9, fa0
; CHECK-NEXT: vfredusum.vs v8, v8, v9
; CHECK-NEXT: vfmv.f.s fa0, v8
; CHECK-NEXT: ret
entry:
%rdx = call fast float @llvm.vector.reduce.fadd.v4f32(float 0.0, <4 x float> %v)
%res = fadd fast float %rdx, %x
ret float %res
}
define float @reduce_fadd3(float %x, <4 x float> %v, ptr %rdxptr) {
; CHECK-LABEL: reduce_fadd3:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: vsetivli zero, 4, e32, m1, ta, ma
; CHECK-NEXT: vmv.s.x v9, zero
; CHECK-NEXT: vfredusum.vs v8, v8, v9
; CHECK-NEXT: vfmv.f.s fa5, v8
; CHECK-NEXT: fadd.s fa0, fa5, fa0
; CHECK-NEXT: vsetivli zero, 1, e32, m1, ta, ma
; CHECK-NEXT: vse32.v v8, (a0)
; CHECK-NEXT: ret
entry:
%rdx = call fast float @llvm.vector.reduce.fadd.v4f32(float -0.0, <4 x float> %v)
%res = fadd fast float %rdx, %x
store float %rdx, ptr %rdxptr
ret float %res
}
define float @reduce_fadd4(float %x, float %y, <4 x float> %v, <4 x float> %w) {
; CHECK-LABEL: reduce_fadd4:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: vsetivli zero, 4, e32, m1, ta, ma
; CHECK-NEXT: vfmv.s.f v10, fa0
; CHECK-NEXT: vfredusum.vs v8, v8, v10
; CHECK-NEXT: vfmv.s.f v10, fa1
; CHECK-NEXT: vfredusum.vs v9, v9, v10
; CHECK-NEXT: vfmv.f.s fa5, v8
; CHECK-NEXT: vfmv.f.s fa4, v9
; CHECK-NEXT: fdiv.s fa0, fa5, fa4
; CHECK-NEXT: ret
entry:
%rdx = call fast float @llvm.vector.reduce.fadd.v4f32(float -0.0, <4 x float> %v)
%rdx2 = call fast float @llvm.vector.reduce.fadd.v4f32(float -0.0, <4 x float> %w)
%res = fadd fast float %rdx, %x
%res2 = fadd fast float %rdx2, %y
%div = fdiv fast float %res, %res2
ret float %div
}
define float @reduce_fmax(float %x, <4 x float> %v) {
; CHECK-LABEL: reduce_fmax:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: vsetivli zero, 4, e32, m1, ta, ma
; CHECK-NEXT: vfredmax.vs v8, v8, v8
; CHECK-NEXT: vfmv.f.s fa5, v8
; CHECK-NEXT: fmax.s fa0, fa0, fa5
; CHECK-NEXT: ret
entry:
%rdx = call float @llvm.vector.reduce.fmax.v4f32(<4 x float> %v)
%res = call float @llvm.maxnum.f32(float %x, float %rdx)
ret float %res
}
define float @reduce_fmin(float %x, <4 x float> %v) {
; CHECK-LABEL: reduce_fmin:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: vsetivli zero, 4, e32, m1, ta, ma
; CHECK-NEXT: vfredmin.vs v8, v8, v8
; CHECK-NEXT: vfmv.f.s fa5, v8
; CHECK-NEXT: fmin.s fa0, fa0, fa5
; CHECK-NEXT: ret
entry:
%rdx = call float @llvm.vector.reduce.fmin.v4f32(<4 x float> %v)
%res = call float @llvm.minnum.f32(float %x, float %rdx)
ret float %res
}
; Function Attrs: nofree nosync nounwind readnone willreturn
declare i64 @llvm.vector.reduce.add.v4i64(<4 x i64>)
declare i64 @llvm.vector.reduce.and.v4i64(<4 x i64>)
declare i64 @llvm.vector.reduce.or.v4i64(<4 x i64>)
declare i64 @llvm.vector.reduce.xor.v4i64(<4 x i64>)
declare i64 @llvm.vector.reduce.umax.v4i64(<4 x i64>)
declare i64 @llvm.vector.reduce.umin.v4i64(<4 x i64>)
declare i64 @llvm.vector.reduce.smax.v4i64(<4 x i64>)
declare i64 @llvm.vector.reduce.smin.v4i64(<4 x i64>)
declare float @llvm.vector.reduce.fadd.v4f32(float, <4 x float>)
declare float @llvm.vector.reduce.fmax.v4f32(<4 x float>)
declare float @llvm.vector.reduce.fmin.v4f32(<4 x float>)
declare i64 @llvm.umax.i64(i64, i64)
declare i64 @llvm.umin.i64(i64, i64)
declare i64 @llvm.smax.i64(i64, i64)
declare i64 @llvm.smin.i64(i64, i64)
declare float @llvm.maxnum.f32(float ,float)
declare float @llvm.minnum.f32(float ,float)
define void @crash(<2 x i32> %0) {
; CHECK-LABEL: crash:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: vsetivli zero, 1, e32, m1, ta, ma
; CHECK-NEXT: vmv.x.s a0, v8
; CHECK-NEXT: vsetivli zero, 4, e16, mf2, ta, ma
; CHECK-NEXT: vmv.v.i v8, 0
; CHECK-NEXT: vmv.s.x v9, a0
; CHECK-NEXT: vredsum.vs v8, v8, v9
; CHECK-NEXT: vmv.x.s a0, v8
; CHECK-NEXT: sb a0, 0(zero)
; CHECK-NEXT: ret
entry:
%1 = extractelement <2 x i32> %0, i64 0
%2 = tail call i16 @llvm.vector.reduce.add.v4i16(<4 x i16> zeroinitializer)
%3 = zext i16 %2 to i32
%op.rdx = add i32 %1, %3
%conv18.us = trunc i32 %op.rdx to i8
store i8 %conv18.us, ptr null, align 1
ret void
}
declare i16 @llvm.vector.reduce.add.v4i16(<4 x i16>)
define i64 @op_then_reduce(<4 x i64> %v, <4 x i64> %v2) {
; CHECK-LABEL: op_then_reduce:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: vsetivli zero, 4, e64, m2, ta, ma
; CHECK-NEXT: vadd.vv v8, v8, v10
; CHECK-NEXT: vmv.s.x v10, zero
; CHECK-NEXT: vredsum.vs v8, v8, v10
; CHECK-NEXT: vmv.x.s a0, v8
; CHECK-NEXT: ret
entry:
%rdx1 = call i64 @llvm.vector.reduce.add.v4i64(<4 x i64> %v)
%rdx2 = call i64 @llvm.vector.reduce.add.v4i64(<4 x i64> %v2)
%res = add i64 %rdx1, %rdx2
ret i64 %res
}
define i64 @two_reduce_scalar_bypass(<4 x i64> %v, <4 x i64> %v2) {
; CHECK-LABEL: two_reduce_scalar_bypass:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: vsetivli zero, 4, e64, m2, ta, ma
; CHECK-NEXT: vmv.s.x v12, zero
; CHECK-NEXT: vredxor.vs v8, v8, v12
; CHECK-NEXT: vredsum.vs v8, v10, v8
; CHECK-NEXT: vmv.x.s a0, v8
; CHECK-NEXT: ret
entry:
%rdx1 = call i64 @llvm.vector.reduce.xor.v4i64(<4 x i64> %v)
%rdx2 = call i64 @llvm.vector.reduce.add.v4i64(<4 x i64> %v2)
%res = add i64 %rdx1, %rdx2
ret i64 %res
}
define i64 @two_reduce_scalar_bypass_zext(<4 x i64> %v, <4 x i32> %v2) {
; CHECK-LABEL: two_reduce_scalar_bypass_zext:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: vsetivli zero, 4, e32, m1, ta, ma
; CHECK-NEXT: vmv.s.x v11, zero
; CHECK-NEXT: vredsum.vs v10, v10, v11
; CHECK-NEXT: vmv.x.s a0, v10
; CHECK-NEXT: slli a0, a0, 32
; CHECK-NEXT: srli a0, a0, 32
; CHECK-NEXT: vsetvli zero, zero, e64, m2, ta, ma
; CHECK-NEXT: vmv.s.x v10, a0
; CHECK-NEXT: vredsum.vs v8, v8, v10
; CHECK-NEXT: vmv.x.s a0, v8
; CHECK-NEXT: ret
entry:
%rdx1 = call i64 @llvm.vector.reduce.add.v4i64(<4 x i64> %v)
%rdx2 = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> %v2)
%rdx2.zext = zext i32 %rdx2 to i64
%res = add i64 %rdx1, %rdx2.zext
ret i64 %res
}
define i64 @two_reduce_scalar_bypass_sext(<4 x i64> %v, <4 x i32> %v2) {
; CHECK-LABEL: two_reduce_scalar_bypass_sext:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: vsetivli zero, 4, e32, m1, ta, ma
; CHECK-NEXT: vmv.s.x v11, zero
; CHECK-NEXT: vredsum.vs v10, v10, v11
; CHECK-NEXT: vmv.x.s a0, v10
; CHECK-NEXT: vsetvli zero, zero, e64, m2, ta, ma
; CHECK-NEXT: vmv.s.x v10, a0
; CHECK-NEXT: vredsum.vs v8, v8, v10
; CHECK-NEXT: vmv.x.s a0, v8
; CHECK-NEXT: ret
entry:
%rdx1 = call i64 @llvm.vector.reduce.add.v4i64(<4 x i64> %v)
%rdx2 = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> %v2)
%rdx2.zext = sext i32 %rdx2 to i64
%res = add i64 %rdx1, %rdx2.zext
ret i64 %res
}