diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -1447,6 +1447,8 @@ setOperationAction(ISD::VECREDUCE_FADD, VT, Custom); setOperationAction(ISD::VECREDUCE_FMAX, VT, Custom); setOperationAction(ISD::VECREDUCE_FMIN, VT, Custom); + setOperationAction(ISD::VECREDUCE_FMAXIMUM, VT, Custom); + setOperationAction(ISD::VECREDUCE_FMINIMUM, VT, Custom); setOperationAction(ISD::VECREDUCE_SEQ_FADD, VT, Custom); setOperationAction(ISD::VECTOR_SPLICE, VT, Custom); setOperationAction(ISD::VECTOR_DEINTERLEAVE, VT, Custom); @@ -1858,6 +1860,8 @@ setOperationAction(ISD::VECREDUCE_FADD, VT, Custom); setOperationAction(ISD::VECREDUCE_FMAX, VT, Custom); setOperationAction(ISD::VECREDUCE_FMIN, VT, Custom); + setOperationAction(ISD::VECREDUCE_FMAXIMUM, VT, Custom); + setOperationAction(ISD::VECREDUCE_FMINIMUM, VT, Custom); setOperationAction(ISD::VECREDUCE_OR, VT, Custom); setOperationAction(ISD::VECREDUCE_SEQ_FADD, VT, Custom); setOperationAction(ISD::VECREDUCE_SMAX, VT, Custom); @@ -5979,6 +5983,8 @@ case ISD::VECREDUCE_FADD: case ISD::VECREDUCE_FMAX: case ISD::VECREDUCE_FMIN: + case ISD::VECREDUCE_FMAXIMUM: + case ISD::VECREDUCE_FMINIMUM: return LowerVECREDUCE(Op, DAG); case ISD::ATOMIC_LOAD_SUB: return LowerATOMIC_LOAD_SUB(Op, DAG); @@ -13574,6 +13580,10 @@ return LowerReductionToSVE(AArch64ISD::FMAXNMV_PRED, Op, DAG); case ISD::VECREDUCE_FMIN: return LowerReductionToSVE(AArch64ISD::FMINNMV_PRED, Op, DAG); + case ISD::VECREDUCE_FMAXIMUM: + return LowerReductionToSVE(AArch64ISD::FMAXV_PRED, Op, DAG); + case ISD::VECREDUCE_FMINIMUM: + return LowerReductionToSVE(AArch64ISD::FMINV_PRED, Op, DAG); default: llvm_unreachable("Unhandled fixed length reduction"); } diff --git a/llvm/test/CodeGen/AArch64/sve-fixed-length-fp-reduce.ll b/llvm/test/CodeGen/AArch64/sve-fixed-length-fp-reduce.ll --- a/llvm/test/CodeGen/AArch64/sve-fixed-length-fp-reduce.ll +++ b/llvm/test/CodeGen/AArch64/sve-fixed-length-fp-reduce.ll @@ -54,7 +54,7 @@ define half @fadda_v32f16(half %start, ptr %a) #0 { ; VBITS_GE_256-LABEL: fadda_v32f16: ; VBITS_GE_256: // %bb.0: -; VBITS_GE_256-NEXT: mov x8, #16 +; VBITS_GE_256-NEXT: mov x8, #16 // =0x10 ; VBITS_GE_256-NEXT: ptrue p0.h, vl16 ; VBITS_GE_256-NEXT: // kill: def $h0 killed $h0 def $z0 ; VBITS_GE_256-NEXT: ld1h { z1.h }, p0/z, [x0, x8, lsl #1] @@ -150,7 +150,7 @@ define float @fadda_v16f32(float %start, ptr %a) #0 { ; VBITS_GE_256-LABEL: fadda_v16f32: ; VBITS_GE_256: // %bb.0: -; VBITS_GE_256-NEXT: mov x8, #8 +; VBITS_GE_256-NEXT: mov x8, #8 // =0x8 ; VBITS_GE_256-NEXT: ptrue p0.s, vl8 ; VBITS_GE_256-NEXT: // kill: def $s0 killed $s0 def $z0 ; VBITS_GE_256-NEXT: ld1w { z1.s }, p0/z, [x0, x8, lsl #2] @@ -242,7 +242,7 @@ define double @fadda_v8f64(double %start, ptr %a) #0 { ; VBITS_GE_256-LABEL: fadda_v8f64: ; VBITS_GE_256: // %bb.0: -; VBITS_GE_256-NEXT: mov x8, #4 +; VBITS_GE_256-NEXT: mov x8, #4 // =0x4 ; VBITS_GE_256-NEXT: ptrue p0.d, vl4 ; VBITS_GE_256-NEXT: // kill: def $d0 killed $d0 def $z0 ; VBITS_GE_256-NEXT: ld1d { z1.d }, p0/z, [x0, x8, lsl #3] @@ -339,7 +339,7 @@ define half @faddv_v32f16(half %start, ptr %a) #0 { ; VBITS_GE_256-LABEL: faddv_v32f16: ; VBITS_GE_256: // %bb.0: -; VBITS_GE_256-NEXT: mov x8, #16 +; VBITS_GE_256-NEXT: mov x8, #16 // =0x10 ; VBITS_GE_256-NEXT: ptrue p0.h, vl16 ; VBITS_GE_256-NEXT: ld1h { z1.h }, p0/z, [x0, x8, lsl #1] ; VBITS_GE_256-NEXT: ld1h { z2.h }, p0/z, [x0] @@ -426,7 +426,7 @@ define float @faddv_v16f32(float %start, ptr %a) #0 { ; VBITS_GE_256-LABEL: faddv_v16f32: ; VBITS_GE_256: // %bb.0: -; VBITS_GE_256-NEXT: mov x8, #8 +; VBITS_GE_256-NEXT: mov x8, #8 // =0x8 ; VBITS_GE_256-NEXT: ptrue p0.s, vl8 ; VBITS_GE_256-NEXT: ld1w { z1.s }, p0/z, [x0, x8, lsl #2] ; VBITS_GE_256-NEXT: ld1w { z2.s }, p0/z, [x0] @@ -510,7 +510,7 @@ define double @faddv_v8f64(double %start, ptr %a) #0 { ; VBITS_GE_256-LABEL: faddv_v8f64: ; VBITS_GE_256: // %bb.0: -; VBITS_GE_256-NEXT: mov x8, #4 +; VBITS_GE_256-NEXT: mov x8, #4 // =0x4 ; VBITS_GE_256-NEXT: ptrue p0.d, vl4 ; VBITS_GE_256-NEXT: ld1d { z1.d }, p0/z, [x0, x8, lsl #3] ; VBITS_GE_256-NEXT: ld1d { z2.d }, p0/z, [x0] @@ -558,7 +558,7 @@ } ; -; FMAXV +; FMAXNMV ; ; No NEON 16-bit vector FMAXNMV support. Use SVE. @@ -597,7 +597,7 @@ define half @fmaxv_v32f16(ptr %a) #0 { ; VBITS_GE_256-LABEL: fmaxv_v32f16: ; VBITS_GE_256: // %bb.0: -; VBITS_GE_256-NEXT: mov x8, #16 +; VBITS_GE_256-NEXT: mov x8, #16 // =0x10 ; VBITS_GE_256-NEXT: ptrue p0.h, vl16 ; VBITS_GE_256-NEXT: ld1h { z0.h }, p0/z, [x0, x8, lsl #1] ; VBITS_GE_256-NEXT: ld1h { z1.h }, p0/z, [x0] @@ -680,7 +680,7 @@ define float @fmaxv_v16f32(ptr %a) #0 { ; VBITS_GE_256-LABEL: fmaxv_v16f32: ; VBITS_GE_256: // %bb.0: -; VBITS_GE_256-NEXT: mov x8, #8 +; VBITS_GE_256-NEXT: mov x8, #8 // =0x8 ; VBITS_GE_256-NEXT: ptrue p0.s, vl8 ; VBITS_GE_256-NEXT: ld1w { z0.s }, p0/z, [x0, x8, lsl #2] ; VBITS_GE_256-NEXT: ld1w { z1.s }, p0/z, [x0] @@ -762,7 +762,7 @@ define double @fmaxv_v8f64(ptr %a) #0 { ; VBITS_GE_256-LABEL: fmaxv_v8f64: ; VBITS_GE_256: // %bb.0: -; VBITS_GE_256-NEXT: mov x8, #4 +; VBITS_GE_256-NEXT: mov x8, #4 // =0x4 ; VBITS_GE_256-NEXT: ptrue p0.d, vl4 ; VBITS_GE_256-NEXT: ld1d { z0.d }, p0/z, [x0, x8, lsl #3] ; VBITS_GE_256-NEXT: ld1d { z1.d }, p0/z, [x0] @@ -810,7 +810,7 @@ } ; -; FMINV +; FMINNMV ; ; No NEON 16-bit vector FMINNMV support. Use SVE. @@ -849,7 +849,7 @@ define half @fminv_v32f16(ptr %a) #0 { ; VBITS_GE_256-LABEL: fminv_v32f16: ; VBITS_GE_256: // %bb.0: -; VBITS_GE_256-NEXT: mov x8, #16 +; VBITS_GE_256-NEXT: mov x8, #16 // =0x10 ; VBITS_GE_256-NEXT: ptrue p0.h, vl16 ; VBITS_GE_256-NEXT: ld1h { z0.h }, p0/z, [x0, x8, lsl #1] ; VBITS_GE_256-NEXT: ld1h { z1.h }, p0/z, [x0] @@ -932,7 +932,7 @@ define float @fminv_v16f32(ptr %a) #0 { ; VBITS_GE_256-LABEL: fminv_v16f32: ; VBITS_GE_256: // %bb.0: -; VBITS_GE_256-NEXT: mov x8, #8 +; VBITS_GE_256-NEXT: mov x8, #8 // =0x8 ; VBITS_GE_256-NEXT: ptrue p0.s, vl8 ; VBITS_GE_256-NEXT: ld1w { z0.s }, p0/z, [x0, x8, lsl #2] ; VBITS_GE_256-NEXT: ld1w { z1.s }, p0/z, [x0] @@ -1014,7 +1014,7 @@ define double @fminv_v8f64(ptr %a) #0 { ; VBITS_GE_256-LABEL: fminv_v8f64: ; VBITS_GE_256: // %bb.0: -; VBITS_GE_256-NEXT: mov x8, #4 +; VBITS_GE_256-NEXT: mov x8, #4 // =0x4 ; VBITS_GE_256-NEXT: ptrue p0.d, vl4 ; VBITS_GE_256-NEXT: ld1d { z0.d }, p0/z, [x0, x8, lsl #3] ; VBITS_GE_256-NEXT: ld1d { z1.d }, p0/z, [x0] @@ -1061,6 +1061,506 @@ ret double %res } +; +; FMAXV +; + +define half @fmaximumv_v4f16(<4 x half> %a) vscale_range(2,0) #0 { +; CHECK-LABEL: fmaximumv_v4f16: +; CHECK: // %bb.0: +; CHECK-NEXT: fmaxv h0, v0.4h +; CHECK-NEXT: ret + %res = call half @llvm.vector.reduce.fmaximum.v4f16(<4 x half> %a) + ret half %res +} + +define half @fmaximumv_v8f16(<8 x half> %a) vscale_range(2,0) #0 { +; CHECK-LABEL: fmaximumv_v8f16: +; CHECK: // %bb.0: +; CHECK-NEXT: fmaxv h0, v0.8h +; CHECK-NEXT: ret + %res = call half @llvm.vector.reduce.fmaximum.v8f16(<8 x half> %a) + ret half %res +} + +define half @fmaximumv_v16f16(ptr %a) vscale_range(2,0) #0 { +; CHECK-LABEL: fmaximumv_v16f16: +; CHECK: // %bb.0: +; CHECK-NEXT: ptrue p0.h, vl16 +; CHECK-NEXT: ld1h { z0.h }, p0/z, [x0] +; CHECK-NEXT: fmaxv h0, p0, z0.h +; CHECK-NEXT: // kill: def $h0 killed $h0 killed $z0 +; CHECK-NEXT: ret + %op = load <16 x half>, ptr %a + %res = call half @llvm.vector.reduce.fmaximum.v16f16(<16 x half> %op) + ret half %res +} + +define half @fmaximumv_v32f16(ptr %a) #0 { +; VBITS_GE_256-LABEL: fmaximumv_v32f16: +; VBITS_GE_256: // %bb.0: +; VBITS_GE_256-NEXT: mov x8, #16 // =0x10 +; VBITS_GE_256-NEXT: ptrue p0.h, vl16 +; VBITS_GE_256-NEXT: ld1h { z0.h }, p0/z, [x0, x8, lsl #1] +; VBITS_GE_256-NEXT: ld1h { z1.h }, p0/z, [x0] +; VBITS_GE_256-NEXT: fmax z0.h, p0/m, z0.h, z1.h +; VBITS_GE_256-NEXT: fmaxv h0, p0, z0.h +; VBITS_GE_256-NEXT: // kill: def $h0 killed $h0 killed $z0 +; VBITS_GE_256-NEXT: ret +; +; VBITS_GE_512-LABEL: fmaximumv_v32f16: +; VBITS_GE_512: // %bb.0: +; VBITS_GE_512-NEXT: ptrue p0.h, vl32 +; VBITS_GE_512-NEXT: ld1h { z0.h }, p0/z, [x0] +; VBITS_GE_512-NEXT: fmaxv h0, p0, z0.h +; VBITS_GE_512-NEXT: // kill: def $h0 killed $h0 killed $z0 +; VBITS_GE_512-NEXT: ret + %op = load <32 x half>, ptr %a + %res = call half @llvm.vector.reduce.fmaximum.v32f16(<32 x half> %op) + ret half %res +} + +define half @fmaximumv_v64f16(ptr %a) vscale_range(8,0) #0 { +; CHECK-LABEL: fmaximumv_v64f16: +; CHECK: // %bb.0: +; CHECK-NEXT: ptrue p0.h, vl64 +; CHECK-NEXT: ld1h { z0.h }, p0/z, [x0] +; CHECK-NEXT: fmaxv h0, p0, z0.h +; CHECK-NEXT: // kill: def $h0 killed $h0 killed $z0 +; CHECK-NEXT: ret + %op = load <64 x half>, ptr %a + %res = call half @llvm.vector.reduce.fmaximum.v64f16(<64 x half> %op) + ret half %res +} + +define half @fmaximumv_v128f16(ptr %a) vscale_range(16,0) #0 { +; CHECK-LABEL: fmaximumv_v128f16: +; CHECK: // %bb.0: +; CHECK-NEXT: ptrue p0.h, vl128 +; CHECK-NEXT: ld1h { z0.h }, p0/z, [x0] +; CHECK-NEXT: fmaxv h0, p0, z0.h +; CHECK-NEXT: // kill: def $h0 killed $h0 killed $z0 +; CHECK-NEXT: ret + %op = load <128 x half>, ptr %a + %res = call half @llvm.vector.reduce.fmaximum.v128f16(<128 x half> %op) + ret half %res +} + +; Don't use SVE for 64-bit f32 vectors. +define float @fmaximumv_v2f32(<2 x float> %a) vscale_range(2,0) #0 { +; CHECK-LABEL: fmaximumv_v2f32: +; CHECK: // %bb.0: +; CHECK-NEXT: fmaxp s0, v0.2s +; CHECK-NEXT: ret + %res = call float @llvm.vector.reduce.fmaximum.v2f32(<2 x float> %a) + ret float %res +} + +; Don't use SVE for 128-bit f32 vectors. +define float @fmaximumv_v4f32(<4 x float> %a) vscale_range(2,0) #0 { +; CHECK-LABEL: fmaximumv_v4f32: +; CHECK: // %bb.0: +; CHECK-NEXT: fmaxv s0, v0.4s +; CHECK-NEXT: ret + %res = call float @llvm.vector.reduce.fmaximum.v4f32(<4 x float> %a) + ret float %res +} + +define float @fmaximumv_v8f32(ptr %a) vscale_range(2,0) #0 { +; CHECK-LABEL: fmaximumv_v8f32: +; CHECK: // %bb.0: +; CHECK-NEXT: ptrue p0.s, vl8 +; CHECK-NEXT: ld1w { z0.s }, p0/z, [x0] +; CHECK-NEXT: fmaxv s0, p0, z0.s +; CHECK-NEXT: // kill: def $s0 killed $s0 killed $z0 +; CHECK-NEXT: ret + %op = load <8 x float>, ptr %a + %res = call float @llvm.vector.reduce.fmaximum.v8f32(<8 x float> %op) + ret float %res +} + +define float @fmaximumv_v16f32(ptr %a) #0 { +; VBITS_GE_256-LABEL: fmaximumv_v16f32: +; VBITS_GE_256: // %bb.0: +; VBITS_GE_256-NEXT: mov x8, #8 // =0x8 +; VBITS_GE_256-NEXT: ptrue p0.s, vl8 +; VBITS_GE_256-NEXT: ld1w { z0.s }, p0/z, [x0, x8, lsl #2] +; VBITS_GE_256-NEXT: ld1w { z1.s }, p0/z, [x0] +; VBITS_GE_256-NEXT: fmax z0.s, p0/m, z0.s, z1.s +; VBITS_GE_256-NEXT: fmaxv s0, p0, z0.s +; VBITS_GE_256-NEXT: // kill: def $s0 killed $s0 killed $z0 +; VBITS_GE_256-NEXT: ret +; +; VBITS_GE_512-LABEL: fmaximumv_v16f32: +; VBITS_GE_512: // %bb.0: +; VBITS_GE_512-NEXT: ptrue p0.s, vl16 +; VBITS_GE_512-NEXT: ld1w { z0.s }, p0/z, [x0] +; VBITS_GE_512-NEXT: fmaxv s0, p0, z0.s +; VBITS_GE_512-NEXT: // kill: def $s0 killed $s0 killed $z0 +; VBITS_GE_512-NEXT: ret + %op = load <16 x float>, ptr %a + %res = call float @llvm.vector.reduce.fmaximum.v16f32(<16 x float> %op) + ret float %res +} + +define float @fmaximumv_v32f32(ptr %a) vscale_range(8,0) #0 { +; CHECK-LABEL: fmaximumv_v32f32: +; CHECK: // %bb.0: +; CHECK-NEXT: ptrue p0.s, vl32 +; CHECK-NEXT: ld1w { z0.s }, p0/z, [x0] +; CHECK-NEXT: fmaxv s0, p0, z0.s +; CHECK-NEXT: // kill: def $s0 killed $s0 killed $z0 +; CHECK-NEXT: ret + %op = load <32 x float>, ptr %a + %res = call float @llvm.vector.reduce.fmaximum.v32f32(<32 x float> %op) + ret float %res +} + +define float @fmaximumv_v64f32(ptr %a) vscale_range(16,0) #0 { +; CHECK-LABEL: fmaximumv_v64f32: +; CHECK: // %bb.0: +; CHECK-NEXT: ptrue p0.s, vl64 +; CHECK-NEXT: ld1w { z0.s }, p0/z, [x0] +; CHECK-NEXT: fmaxv s0, p0, z0.s +; CHECK-NEXT: // kill: def $s0 killed $s0 killed $z0 +; CHECK-NEXT: ret + %op = load <64 x float>, ptr %a + %res = call float @llvm.vector.reduce.fmaximum.v64f32(<64 x float> %op) + ret float %res +} + +; Nothing to do for single element vectors. +define double @fmaximumv_v1f64(<1 x double> %a) vscale_range(2,0) #0 { +; CHECK-LABEL: fmaximumv_v1f64: +; CHECK: // %bb.0: +; CHECK-NEXT: ret + %res = call double @llvm.vector.reduce.fmaximum.v1f64(<1 x double> %a) + ret double %res +} + +; Don't use SVE for 128-bit f64 vectors. +define double @fmaximumv_v2f64(<2 x double> %a) vscale_range(2,0) #0 { +; CHECK-LABEL: fmaximumv_v2f64: +; CHECK: // %bb.0: +; CHECK-NEXT: fmaxp d0, v0.2d +; CHECK-NEXT: ret + %res = call double @llvm.vector.reduce.fmaximum.v2f64(<2 x double> %a) + ret double %res +} + +define double @fmaximumv_v4f64(ptr %a) vscale_range(2,0) #0 { +; CHECK-LABEL: fmaximumv_v4f64: +; CHECK: // %bb.0: +; CHECK-NEXT: ptrue p0.d, vl4 +; CHECK-NEXT: ld1d { z0.d }, p0/z, [x0] +; CHECK-NEXT: fmaxv d0, p0, z0.d +; CHECK-NEXT: // kill: def $d0 killed $d0 killed $z0 +; CHECK-NEXT: ret + %op = load <4 x double>, ptr %a + %res = call double @llvm.vector.reduce.fmaximum.v4f64(<4 x double> %op) + ret double %res +} + +define double @fmaximumv_v8f64(ptr %a) #0 { +; VBITS_GE_256-LABEL: fmaximumv_v8f64: +; VBITS_GE_256: // %bb.0: +; VBITS_GE_256-NEXT: mov x8, #4 // =0x4 +; VBITS_GE_256-NEXT: ptrue p0.d, vl4 +; VBITS_GE_256-NEXT: ld1d { z0.d }, p0/z, [x0, x8, lsl #3] +; VBITS_GE_256-NEXT: ld1d { z1.d }, p0/z, [x0] +; VBITS_GE_256-NEXT: fmax z0.d, p0/m, z0.d, z1.d +; VBITS_GE_256-NEXT: fmaxv d0, p0, z0.d +; VBITS_GE_256-NEXT: // kill: def $d0 killed $d0 killed $z0 +; VBITS_GE_256-NEXT: ret +; +; VBITS_GE_512-LABEL: fmaximumv_v8f64: +; VBITS_GE_512: // %bb.0: +; VBITS_GE_512-NEXT: ptrue p0.d, vl8 +; VBITS_GE_512-NEXT: ld1d { z0.d }, p0/z, [x0] +; VBITS_GE_512-NEXT: fmaxv d0, p0, z0.d +; VBITS_GE_512-NEXT: // kill: def $d0 killed $d0 killed $z0 +; VBITS_GE_512-NEXT: ret + %op = load <8 x double>, ptr %a + %res = call double @llvm.vector.reduce.fmaximum.v8f64(<8 x double> %op) + ret double %res +} + +define double @fmaximumv_v16f64(ptr %a) vscale_range(8,0) #0 { +; CHECK-LABEL: fmaximumv_v16f64: +; CHECK: // %bb.0: +; CHECK-NEXT: ptrue p0.d, vl16 +; CHECK-NEXT: ld1d { z0.d }, p0/z, [x0] +; CHECK-NEXT: fmaxv d0, p0, z0.d +; CHECK-NEXT: // kill: def $d0 killed $d0 killed $z0 +; CHECK-NEXT: ret + %op = load <16 x double>, ptr %a + %res = call double @llvm.vector.reduce.fmaximum.v16f64(<16 x double> %op) + ret double %res +} + +define double @fmaximumv_v32f64(ptr %a) vscale_range(16,0) #0 { +; CHECK-LABEL: fmaximumv_v32f64: +; CHECK: // %bb.0: +; CHECK-NEXT: ptrue p0.d, vl32 +; CHECK-NEXT: ld1d { z0.d }, p0/z, [x0] +; CHECK-NEXT: fmaxv d0, p0, z0.d +; CHECK-NEXT: // kill: def $d0 killed $d0 killed $z0 +; CHECK-NEXT: ret + %op = load <32 x double>, ptr %a + %res = call double @llvm.vector.reduce.fmaximum.v32f64(<32 x double> %op) + ret double %res +} + +; +; FMINV +; + +define half @fminimumv_v4f16(<4 x half> %a) vscale_range(2,0) #0 { +; CHECK-LABEL: fminimumv_v4f16: +; CHECK: // %bb.0: +; CHECK-NEXT: fminv h0, v0.4h +; CHECK-NEXT: ret + %res = call half @llvm.vector.reduce.fminimum.v4f16(<4 x half> %a) + ret half %res +} + +define half @fminimumv_v8f16(<8 x half> %a) vscale_range(2,0) #0 { +; CHECK-LABEL: fminimumv_v8f16: +; CHECK: // %bb.0: +; CHECK-NEXT: fminv h0, v0.8h +; CHECK-NEXT: ret + %res = call half @llvm.vector.reduce.fminimum.v8f16(<8 x half> %a) + ret half %res +} + +define half @fminimumv_v16f16(ptr %a) vscale_range(2,0) #0 { +; CHECK-LABEL: fminimumv_v16f16: +; CHECK: // %bb.0: +; CHECK-NEXT: ptrue p0.h, vl16 +; CHECK-NEXT: ld1h { z0.h }, p0/z, [x0] +; CHECK-NEXT: fminv h0, p0, z0.h +; CHECK-NEXT: // kill: def $h0 killed $h0 killed $z0 +; CHECK-NEXT: ret + %op = load <16 x half>, ptr %a + %res = call half @llvm.vector.reduce.fminimum.v16f16(<16 x half> %op) + ret half %res +} + +define half @fminimumv_v32f16(ptr %a) #0 { +; VBITS_GE_256-LABEL: fminimumv_v32f16: +; VBITS_GE_256: // %bb.0: +; VBITS_GE_256-NEXT: mov x8, #16 // =0x10 +; VBITS_GE_256-NEXT: ptrue p0.h, vl16 +; VBITS_GE_256-NEXT: ld1h { z0.h }, p0/z, [x0, x8, lsl #1] +; VBITS_GE_256-NEXT: ld1h { z1.h }, p0/z, [x0] +; VBITS_GE_256-NEXT: fmin z0.h, p0/m, z0.h, z1.h +; VBITS_GE_256-NEXT: fminv h0, p0, z0.h +; VBITS_GE_256-NEXT: // kill: def $h0 killed $h0 killed $z0 +; VBITS_GE_256-NEXT: ret +; +; VBITS_GE_512-LABEL: fminimumv_v32f16: +; VBITS_GE_512: // %bb.0: +; VBITS_GE_512-NEXT: ptrue p0.h, vl32 +; VBITS_GE_512-NEXT: ld1h { z0.h }, p0/z, [x0] +; VBITS_GE_512-NEXT: fminv h0, p0, z0.h +; VBITS_GE_512-NEXT: // kill: def $h0 killed $h0 killed $z0 +; VBITS_GE_512-NEXT: ret + %op = load <32 x half>, ptr %a + %res = call half @llvm.vector.reduce.fminimum.v32f16(<32 x half> %op) + ret half %res +} + +define half @fminimumv_v64f16(ptr %a) vscale_range(8,0) #0 { +; CHECK-LABEL: fminimumv_v64f16: +; CHECK: // %bb.0: +; CHECK-NEXT: ptrue p0.h, vl64 +; CHECK-NEXT: ld1h { z0.h }, p0/z, [x0] +; CHECK-NEXT: fminv h0, p0, z0.h +; CHECK-NEXT: // kill: def $h0 killed $h0 killed $z0 +; CHECK-NEXT: ret + %op = load <64 x half>, ptr %a + %res = call half @llvm.vector.reduce.fminimum.v64f16(<64 x half> %op) + ret half %res +} + +define half @fminimumv_v128f16(ptr %a) vscale_range(16,0) #0 { +; CHECK-LABEL: fminimumv_v128f16: +; CHECK: // %bb.0: +; CHECK-NEXT: ptrue p0.h, vl128 +; CHECK-NEXT: ld1h { z0.h }, p0/z, [x0] +; CHECK-NEXT: fminv h0, p0, z0.h +; CHECK-NEXT: // kill: def $h0 killed $h0 killed $z0 +; CHECK-NEXT: ret + %op = load <128 x half>, ptr %a + %res = call half @llvm.vector.reduce.fminimum.v128f16(<128 x half> %op) + ret half %res +} + +; Don't use SVE for 64-bit f32 vectors. +define float @fminimumv_v2f32(<2 x float> %a) vscale_range(2,0) #0 { +; CHECK-LABEL: fminimumv_v2f32: +; CHECK: // %bb.0: +; CHECK-NEXT: fminp s0, v0.2s +; CHECK-NEXT: ret + %res = call float @llvm.vector.reduce.fminimum.v2f32(<2 x float> %a) + ret float %res +} + +; Don't use SVE for 128-bit f32 vectors. +define float @fminimumv_v4f32(<4 x float> %a) vscale_range(2,0) #0 { +; CHECK-LABEL: fminimumv_v4f32: +; CHECK: // %bb.0: +; CHECK-NEXT: fminv s0, v0.4s +; CHECK-NEXT: ret + %res = call float @llvm.vector.reduce.fminimum.v4f32(<4 x float> %a) + ret float %res +} + +define float @fminimumv_v8f32(ptr %a) vscale_range(2,0) #0 { +; CHECK-LABEL: fminimumv_v8f32: +; CHECK: // %bb.0: +; CHECK-NEXT: ptrue p0.s, vl8 +; CHECK-NEXT: ld1w { z0.s }, p0/z, [x0] +; CHECK-NEXT: fminv s0, p0, z0.s +; CHECK-NEXT: // kill: def $s0 killed $s0 killed $z0 +; CHECK-NEXT: ret + %op = load <8 x float>, ptr %a + %res = call float @llvm.vector.reduce.fminimum.v8f32(<8 x float> %op) + ret float %res +} + +define float @fminimumv_v16f32(ptr %a) #0 { +; VBITS_GE_256-LABEL: fminimumv_v16f32: +; VBITS_GE_256: // %bb.0: +; VBITS_GE_256-NEXT: mov x8, #8 // =0x8 +; VBITS_GE_256-NEXT: ptrue p0.s, vl8 +; VBITS_GE_256-NEXT: ld1w { z0.s }, p0/z, [x0, x8, lsl #2] +; VBITS_GE_256-NEXT: ld1w { z1.s }, p0/z, [x0] +; VBITS_GE_256-NEXT: fmin z0.s, p0/m, z0.s, z1.s +; VBITS_GE_256-NEXT: fminv s0, p0, z0.s +; VBITS_GE_256-NEXT: // kill: def $s0 killed $s0 killed $z0 +; VBITS_GE_256-NEXT: ret +; +; VBITS_GE_512-LABEL: fminimumv_v16f32: +; VBITS_GE_512: // %bb.0: +; VBITS_GE_512-NEXT: ptrue p0.s, vl16 +; VBITS_GE_512-NEXT: ld1w { z0.s }, p0/z, [x0] +; VBITS_GE_512-NEXT: fminv s0, p0, z0.s +; VBITS_GE_512-NEXT: // kill: def $s0 killed $s0 killed $z0 +; VBITS_GE_512-NEXT: ret + %op = load <16 x float>, ptr %a + %res = call float @llvm.vector.reduce.fminimum.v16f32(<16 x float> %op) + ret float %res +} + +define float @fminimumv_v32f32(ptr %a) vscale_range(8,0) #0 { +; CHECK-LABEL: fminimumv_v32f32: +; CHECK: // %bb.0: +; CHECK-NEXT: ptrue p0.s, vl32 +; CHECK-NEXT: ld1w { z0.s }, p0/z, [x0] +; CHECK-NEXT: fminv s0, p0, z0.s +; CHECK-NEXT: // kill: def $s0 killed $s0 killed $z0 +; CHECK-NEXT: ret + %op = load <32 x float>, ptr %a + %res = call float @llvm.vector.reduce.fminimum.v32f32(<32 x float> %op) + ret float %res +} + +define float @fminimumv_v64f32(ptr %a) vscale_range(16,0) #0 { +; CHECK-LABEL: fminimumv_v64f32: +; CHECK: // %bb.0: +; CHECK-NEXT: ptrue p0.s, vl64 +; CHECK-NEXT: ld1w { z0.s }, p0/z, [x0] +; CHECK-NEXT: fminv s0, p0, z0.s +; CHECK-NEXT: // kill: def $s0 killed $s0 killed $z0 +; CHECK-NEXT: ret + %op = load <64 x float>, ptr %a + %res = call float @llvm.vector.reduce.fminimum.v64f32(<64 x float> %op) + ret float %res +} + +; Nothing to do for single element vectors. +define double @fminimumv_v1f64(<1 x double> %a) vscale_range(2,0) #0 { +; CHECK-LABEL: fminimumv_v1f64: +; CHECK: // %bb.0: +; CHECK-NEXT: ret + %res = call double @llvm.vector.reduce.fminimum.v1f64(<1 x double> %a) + ret double %res +} + +; Don't use SVE for 128-bit f64 vectors. +define double @fminimumv_v2f64(<2 x double> %a) vscale_range(2,0) #0 { +; CHECK-LABEL: fminimumv_v2f64: +; CHECK: // %bb.0: +; CHECK-NEXT: fminp d0, v0.2d +; CHECK-NEXT: ret + %res = call double @llvm.vector.reduce.fminimum.v2f64(<2 x double> %a) + ret double %res +} + +define double @fminimumv_v4f64(ptr %a) vscale_range(2,0) #0 { +; CHECK-LABEL: fminimumv_v4f64: +; CHECK: // %bb.0: +; CHECK-NEXT: ptrue p0.d, vl4 +; CHECK-NEXT: ld1d { z0.d }, p0/z, [x0] +; CHECK-NEXT: fminv d0, p0, z0.d +; CHECK-NEXT: // kill: def $d0 killed $d0 killed $z0 +; CHECK-NEXT: ret + %op = load <4 x double>, ptr %a + %res = call double @llvm.vector.reduce.fminimum.v4f64(<4 x double> %op) + ret double %res +} + +define double @fminimumv_v8f64(ptr %a) #0 { +; VBITS_GE_256-LABEL: fminimumv_v8f64: +; VBITS_GE_256: // %bb.0: +; VBITS_GE_256-NEXT: mov x8, #4 // =0x4 +; VBITS_GE_256-NEXT: ptrue p0.d, vl4 +; VBITS_GE_256-NEXT: ld1d { z0.d }, p0/z, [x0, x8, lsl #3] +; VBITS_GE_256-NEXT: ld1d { z1.d }, p0/z, [x0] +; VBITS_GE_256-NEXT: fmin z0.d, p0/m, z0.d, z1.d +; VBITS_GE_256-NEXT: fminv d0, p0, z0.d +; VBITS_GE_256-NEXT: // kill: def $d0 killed $d0 killed $z0 +; VBITS_GE_256-NEXT: ret +; +; VBITS_GE_512-LABEL: fminimumv_v8f64: +; VBITS_GE_512: // %bb.0: +; VBITS_GE_512-NEXT: ptrue p0.d, vl8 +; VBITS_GE_512-NEXT: ld1d { z0.d }, p0/z, [x0] +; VBITS_GE_512-NEXT: fminv d0, p0, z0.d +; VBITS_GE_512-NEXT: // kill: def $d0 killed $d0 killed $z0 +; VBITS_GE_512-NEXT: ret + %op = load <8 x double>, ptr %a + %res = call double @llvm.vector.reduce.fminimum.v8f64(<8 x double> %op) + ret double %res +} + +define double @fminimumv_v16f64(ptr %a) vscale_range(8,0) #0 { +; CHECK-LABEL: fminimumv_v16f64: +; CHECK: // %bb.0: +; CHECK-NEXT: ptrue p0.d, vl16 +; CHECK-NEXT: ld1d { z0.d }, p0/z, [x0] +; CHECK-NEXT: fminv d0, p0, z0.d +; CHECK-NEXT: // kill: def $d0 killed $d0 killed $z0 +; CHECK-NEXT: ret + %op = load <16 x double>, ptr %a + %res = call double @llvm.vector.reduce.fminimum.v16f64(<16 x double> %op) + ret double %res +} + +define double @fminimumv_v32f64(ptr %a) vscale_range(16,0) #0 { +; CHECK-LABEL: fminimumv_v32f64: +; CHECK: // %bb.0: +; CHECK-NEXT: ptrue p0.d, vl32 +; CHECK-NEXT: ld1d { z0.d }, p0/z, [x0] +; CHECK-NEXT: fminv d0, p0, z0.d +; CHECK-NEXT: // kill: def $d0 killed $d0 killed $z0 +; CHECK-NEXT: ret + %op = load <32 x double>, ptr %a + %res = call double @llvm.vector.reduce.fminimum.v32f64(<32 x double> %op) + ret double %res +} + attributes #0 = { "target-features"="+sve" } declare half @llvm.vector.reduce.fadd.v4f16(half, <4 x half>) @@ -1125,3 +1625,45 @@ declare double @llvm.vector.reduce.fmin.v8f64(<8 x double>) declare double @llvm.vector.reduce.fmin.v16f64(<16 x double>) declare double @llvm.vector.reduce.fmin.v32f64(<32 x double>) + +declare half @llvm.vector.reduce.fmaximum.v4f16(<4 x half>) +declare half @llvm.vector.reduce.fmaximum.v8f16(<8 x half>) +declare half @llvm.vector.reduce.fmaximum.v16f16(<16 x half>) +declare half @llvm.vector.reduce.fmaximum.v32f16(<32 x half>) +declare half @llvm.vector.reduce.fmaximum.v64f16(<64 x half>) +declare half @llvm.vector.reduce.fmaximum.v128f16(<128 x half>) + +declare float @llvm.vector.reduce.fmaximum.v2f32(<2 x float>) +declare float @llvm.vector.reduce.fmaximum.v4f32(<4 x float>) +declare float @llvm.vector.reduce.fmaximum.v8f32(<8 x float>) +declare float @llvm.vector.reduce.fmaximum.v16f32(<16 x float>) +declare float @llvm.vector.reduce.fmaximum.v32f32(<32 x float>) +declare float @llvm.vector.reduce.fmaximum.v64f32(<64 x float>) + +declare double @llvm.vector.reduce.fmaximum.v1f64(<1 x double>) +declare double @llvm.vector.reduce.fmaximum.v2f64(<2 x double>) +declare double @llvm.vector.reduce.fmaximum.v4f64(<4 x double>) +declare double @llvm.vector.reduce.fmaximum.v8f64(<8 x double>) +declare double @llvm.vector.reduce.fmaximum.v16f64(<16 x double>) +declare double @llvm.vector.reduce.fmaximum.v32f64(<32 x double>) + +declare half @llvm.vector.reduce.fminimum.v4f16(<4 x half>) +declare half @llvm.vector.reduce.fminimum.v8f16(<8 x half>) +declare half @llvm.vector.reduce.fminimum.v16f16(<16 x half>) +declare half @llvm.vector.reduce.fminimum.v32f16(<32 x half>) +declare half @llvm.vector.reduce.fminimum.v64f16(<64 x half>) +declare half @llvm.vector.reduce.fminimum.v128f16(<128 x half>) + +declare float @llvm.vector.reduce.fminimum.v2f32(<2 x float>) +declare float @llvm.vector.reduce.fminimum.v4f32(<4 x float>) +declare float @llvm.vector.reduce.fminimum.v8f32(<8 x float>) +declare float @llvm.vector.reduce.fminimum.v16f32(<16 x float>) +declare float @llvm.vector.reduce.fminimum.v32f32(<32 x float>) +declare float @llvm.vector.reduce.fminimum.v64f32(<64 x float>) + +declare double @llvm.vector.reduce.fminimum.v1f64(<1 x double>) +declare double @llvm.vector.reduce.fminimum.v2f64(<2 x double>) +declare double @llvm.vector.reduce.fminimum.v4f64(<4 x double>) +declare double @llvm.vector.reduce.fminimum.v8f64(<8 x double>) +declare double @llvm.vector.reduce.fminimum.v16f64(<16 x double>) +declare double @llvm.vector.reduce.fminimum.v32f64(<32 x double>) diff --git a/llvm/test/CodeGen/AArch64/sve-fp-reduce.ll b/llvm/test/CodeGen/AArch64/sve-fp-reduce.ll --- a/llvm/test/CodeGen/AArch64/sve-fp-reduce.ll +++ b/llvm/test/CodeGen/AArch64/sve-fp-reduce.ll @@ -47,7 +47,7 @@ ; CHECK-NEXT: .cfi_offset w29, -16 ; CHECK-NEXT: addvl sp, sp, #-1 ; CHECK-NEXT: .cfi_escape 0x0f, 0x0c, 0x8f, 0x00, 0x11, 0x10, 0x22, 0x11, 0x08, 0x92, 0x2e, 0x00, 0x1e, 0x22 // sp + 16 + 8 * VG -; CHECK-NEXT: mov w8, #32768 +; CHECK-NEXT: mov w8, #32768 // =0x8000 ; CHECK-NEXT: ptrue p0.h ; CHECK-NEXT: ptrue p1.d ; CHECK-NEXT: st1h { z0.h }, p0, [sp] @@ -72,7 +72,7 @@ ; CHECK-NEXT: .cfi_offset w29, -16 ; CHECK-NEXT: addvl sp, sp, #-3 ; CHECK-NEXT: .cfi_escape 0x0f, 0x0c, 0x8f, 0x00, 0x11, 0x10, 0x22, 0x11, 0x18, 0x92, 0x2e, 0x00, 0x1e, 0x22 // sp + 16 + 24 * VG -; CHECK-NEXT: mov w8, #32768 +; CHECK-NEXT: mov w8, #32768 // =0x8000 ; CHECK-NEXT: ptrue p0.h ; CHECK-NEXT: ptrue p1.d ; CHECK-NEXT: st1h { z1.h }, p0, [sp] @@ -100,7 +100,7 @@ define half @fadda_nxv12f16( %v, half %s) { ; CHECK-LABEL: fadda_nxv12f16: ; CHECK: // %bb.0: -; CHECK-NEXT: mov w8, #32768 +; CHECK-NEXT: mov w8, #32768 // =0x8000 ; CHECK-NEXT: // kill: def $h2 killed $h2 def $z2 ; CHECK-NEXT: uunpklo z1.s, z1.h ; CHECK-NEXT: ptrue p0.h @@ -218,7 +218,7 @@ ret double %res } -; FMAXV +; FMAXNMV define half @fmaxv_nxv2f16( %a) { ; CHECK-LABEL: fmaxv_nxv2f16: @@ -286,7 +286,7 @@ ret double %res } -; FMINV +; FMINNMV define half @fminv_nxv2f16( %a) { ; CHECK-LABEL: fminv_nxv2f16: @@ -354,6 +354,145 @@ ret double %res } + + + +; FMAXV + +define half @fmaximumv_nxv2f16( %a) { +; CHECK-LABEL: fmaximumv_nxv2f16: +; CHECK: // %bb.0: +; CHECK-NEXT: ptrue p0.d +; CHECK-NEXT: fmaxv h0, p0, z0.h +; CHECK-NEXT: // kill: def $h0 killed $h0 killed $z0 +; CHECK-NEXT: ret + %res = call half @llvm.vector.reduce.fmaximum.nxv2f16( %a) + ret half %res +} + +define half @fmaximumv_nxv4f16( %a) { +; CHECK-LABEL: fmaximumv_nxv4f16: +; CHECK: // %bb.0: +; CHECK-NEXT: ptrue p0.s +; CHECK-NEXT: fmaxv h0, p0, z0.h +; CHECK-NEXT: // kill: def $h0 killed $h0 killed $z0 +; CHECK-NEXT: ret + %res = call half @llvm.vector.reduce.fmaximum.nxv4f16( %a) + ret half %res +} + +define half @fmaximumv_nxv8f16( %a) { +; CHECK-LABEL: fmaximumv_nxv8f16: +; CHECK: // %bb.0: +; CHECK-NEXT: ptrue p0.h +; CHECK-NEXT: fmaxv h0, p0, z0.h +; CHECK-NEXT: // kill: def $h0 killed $h0 killed $z0 +; CHECK-NEXT: ret + %res = call half @llvm.vector.reduce.fmaximum.nxv8f16( %a) + ret half %res +} + +define float @fmaximumv_nxv2f32( %a) { +; CHECK-LABEL: fmaximumv_nxv2f32: +; CHECK: // %bb.0: +; CHECK-NEXT: ptrue p0.d +; CHECK-NEXT: fmaxv s0, p0, z0.s +; CHECK-NEXT: // kill: def $s0 killed $s0 killed $z0 +; CHECK-NEXT: ret + %res = call float @llvm.vector.reduce.fmaximum.nxv2f32( %a) + ret float %res +} + +define float @fmaximumv_nxv4f32( %a) { +; CHECK-LABEL: fmaximumv_nxv4f32: +; CHECK: // %bb.0: +; CHECK-NEXT: ptrue p0.s +; CHECK-NEXT: fmaxv s0, p0, z0.s +; CHECK-NEXT: // kill: def $s0 killed $s0 killed $z0 +; CHECK-NEXT: ret + %res = call float @llvm.vector.reduce.fmaximum.nxv4f32( %a) + ret float %res +} + +define double @fmaximumv_nxv2f64( %a) { +; CHECK-LABEL: fmaximumv_nxv2f64: +; CHECK: // %bb.0: +; CHECK-NEXT: ptrue p0.d +; CHECK-NEXT: fmaxv d0, p0, z0.d +; CHECK-NEXT: // kill: def $d0 killed $d0 killed $z0 +; CHECK-NEXT: ret + %res = call double @llvm.vector.reduce.fmaximum.nxv2f64( %a) + ret double %res +} + +; FMINV + +define half @fminimumv_nxv2f16( %a) { +; CHECK-LABEL: fminimumv_nxv2f16: +; CHECK: // %bb.0: +; CHECK-NEXT: ptrue p0.d +; CHECK-NEXT: fminv h0, p0, z0.h +; CHECK-NEXT: // kill: def $h0 killed $h0 killed $z0 +; CHECK-NEXT: ret + %res = call half @llvm.vector.reduce.fminimum.nxv2f16( %a) + ret half %res +} + +define half @fminimumv_nxv4f16( %a) { +; CHECK-LABEL: fminimumv_nxv4f16: +; CHECK: // %bb.0: +; CHECK-NEXT: ptrue p0.s +; CHECK-NEXT: fminv h0, p0, z0.h +; CHECK-NEXT: // kill: def $h0 killed $h0 killed $z0 +; CHECK-NEXT: ret + %res = call half @llvm.vector.reduce.fminimum.nxv4f16( %a) + ret half %res +} + +define half @fminimumv_nxv8f16( %a) { +; CHECK-LABEL: fminimumv_nxv8f16: +; CHECK: // %bb.0: +; CHECK-NEXT: ptrue p0.h +; CHECK-NEXT: fminv h0, p0, z0.h +; CHECK-NEXT: // kill: def $h0 killed $h0 killed $z0 +; CHECK-NEXT: ret + %res = call half @llvm.vector.reduce.fminimum.nxv8f16( %a) + ret half %res +} + +define float @fminimumv_nxv2f32( %a) { +; CHECK-LABEL: fminimumv_nxv2f32: +; CHECK: // %bb.0: +; CHECK-NEXT: ptrue p0.d +; CHECK-NEXT: fminv s0, p0, z0.s +; CHECK-NEXT: // kill: def $s0 killed $s0 killed $z0 +; CHECK-NEXT: ret + %res = call float @llvm.vector.reduce.fminimum.nxv2f32( %a) + ret float %res +} + +define float @fminimumv_nxv4f32( %a) { +; CHECK-LABEL: fminimumv_nxv4f32: +; CHECK: // %bb.0: +; CHECK-NEXT: ptrue p0.s +; CHECK-NEXT: fminv s0, p0, z0.s +; CHECK-NEXT: // kill: def $s0 killed $s0 killed $z0 +; CHECK-NEXT: ret + %res = call float @llvm.vector.reduce.fminimum.nxv4f32( %a) + ret float %res +} + +define double @fminimumv_nxv2f64( %a) { +; CHECK-LABEL: fminimumv_nxv2f64: +; CHECK: // %bb.0: +; CHECK-NEXT: ptrue p0.d +; CHECK-NEXT: fminv d0, p0, z0.d +; CHECK-NEXT: // kill: def $d0 killed $d0 killed $z0 +; CHECK-NEXT: ret + %res = call double @llvm.vector.reduce.fminimum.nxv2f64( %a) + ret double %res +} + define float @fadd_reduct_reassoc_v4v8f32( %a, %b) { ; CHECK-LABEL: fadd_reduct_reassoc_v4v8f32: ; CHECK: // %bb.0: @@ -393,3 +532,17 @@ declare float @llvm.vector.reduce.fmin.nxv2f32() declare float @llvm.vector.reduce.fmin.nxv4f32() declare double @llvm.vector.reduce.fmin.nxv2f64() + +declare half @llvm.vector.reduce.fmaximum.nxv2f16() +declare half @llvm.vector.reduce.fmaximum.nxv4f16() +declare half @llvm.vector.reduce.fmaximum.nxv8f16() +declare float @llvm.vector.reduce.fmaximum.nxv2f32() +declare float @llvm.vector.reduce.fmaximum.nxv4f32() +declare double @llvm.vector.reduce.fmaximum.nxv2f64() + +declare half @llvm.vector.reduce.fminimum.nxv2f16() +declare half @llvm.vector.reduce.fminimum.nxv4f16() +declare half @llvm.vector.reduce.fminimum.nxv8f16() +declare float @llvm.vector.reduce.fminimum.nxv2f32() +declare float @llvm.vector.reduce.fminimum.nxv4f32() +declare double @llvm.vector.reduce.fminimum.nxv2f64() diff --git a/llvm/test/CodeGen/AArch64/sve-split-fp-reduce.ll b/llvm/test/CodeGen/AArch64/sve-split-fp-reduce.ll --- a/llvm/test/CodeGen/AArch64/sve-split-fp-reduce.ll +++ b/llvm/test/CodeGen/AArch64/sve-split-fp-reduce.ll @@ -32,7 +32,7 @@ ret float %res } -; FMAXV +; FMAXNMV define double @fmaxv_nxv8f64( %a) { ; CHECK-LABEL: fmaxv_nxv8f64: @@ -48,7 +48,7 @@ ret double %res } -; FMINV +; FMINNMV define half @fminv_nxv16f16( %a) { ; CHECK-LABEL: fminv_nxv16f16: @@ -62,9 +62,40 @@ ret half %res } +; FMAXV + +define double @fmaximumv_nxv8f64( %a) { +; CHECK-LABEL: fmaximumv_nxv8f64: +; CHECK: // %bb.0: +; CHECK-NEXT: ptrue p0.d +; CHECK-NEXT: fmax z1.d, p0/m, z1.d, z3.d +; CHECK-NEXT: fmax z0.d, p0/m, z0.d, z2.d +; CHECK-NEXT: fmax z0.d, p0/m, z0.d, z1.d +; CHECK-NEXT: fmaxv d0, p0, z0.d +; CHECK-NEXT: // kill: def $d0 killed $d0 killed $z0 +; CHECK-NEXT: ret + %res = call double @llvm.vector.reduce.fmaximum.nxv8f64( %a) + ret double %res +} + +; FMINV + +define half @fminimumv_nxv16f16( %a) { +; CHECK-LABEL: fminimumv_nxv16f16: +; CHECK: // %bb.0: +; CHECK-NEXT: ptrue p0.h +; CHECK-NEXT: fmin z0.h, p0/m, z0.h, z1.h +; CHECK-NEXT: fminv h0, p0, z0.h +; CHECK-NEXT: // kill: def $h0 killed $h0 killed $z0 +; CHECK-NEXT: ret + %res = call half @llvm.vector.reduce.fminimum.nxv16f16( %a) + ret half %res +} + declare double @llvm.vector.reduce.fadd.nxv8f64(double, ) declare float @llvm.vector.reduce.fadd.nxv8f32(float, ) declare double @llvm.vector.reduce.fmax.nxv8f64() - declare half @llvm.vector.reduce.fmin.nxv16f16() +declare double @llvm.vector.reduce.fmaximum.nxv8f64() +declare half @llvm.vector.reduce.fminimum.nxv16f16() diff --git a/llvm/test/CodeGen/AArch64/sve-streaming-mode-fixed-length-fp-reduce.ll b/llvm/test/CodeGen/AArch64/sve-streaming-mode-fixed-length-fp-reduce.ll --- a/llvm/test/CodeGen/AArch64/sve-streaming-mode-fixed-length-fp-reduce.ll +++ b/llvm/test/CodeGen/AArch64/sve-streaming-mode-fixed-length-fp-reduce.ll @@ -244,7 +244,7 @@ } ; -; FMAXV +; FMAXNMV ; define half @fmaxv_v4f16(<4 x half> %a) #0 { @@ -360,7 +360,7 @@ } ; -; FMINV +; FMINNMV ; define half @fminv_v4f16(<4 x half> %a) #0 { @@ -475,6 +475,238 @@ ret double %res } +; +; FMAXV +; + +define half @fmaximumv_v4f16(<4 x half> %a) #0 { +; CHECK-LABEL: fmaximumv_v4f16: +; CHECK: // %bb.0: +; CHECK-NEXT: // kill: def $d0 killed $d0 def $z0 +; CHECK-NEXT: ptrue p0.h, vl4 +; CHECK-NEXT: fmaxv h0, p0, z0.h +; CHECK-NEXT: // kill: def $h0 killed $h0 killed $z0 +; CHECK-NEXT: ret + %res = call half @llvm.vector.reduce.fmaximum.v4f16(<4 x half> %a) + ret half %res +} + +define half @fmaximumv_v8f16(<8 x half> %a) #0 { +; CHECK-LABEL: fmaximumv_v8f16: +; CHECK: // %bb.0: +; CHECK-NEXT: // kill: def $q0 killed $q0 def $z0 +; CHECK-NEXT: ptrue p0.h, vl8 +; CHECK-NEXT: fmaxv h0, p0, z0.h +; CHECK-NEXT: // kill: def $h0 killed $h0 killed $z0 +; CHECK-NEXT: ret + %res = call half @llvm.vector.reduce.fmaximum.v8f16(<8 x half> %a) + ret half %res +} + +define half @fmaximumv_v16f16(ptr %a) #0 { +; CHECK-LABEL: fmaximumv_v16f16: +; CHECK: // %bb.0: +; CHECK-NEXT: ldp q1, q0, [x0] +; CHECK-NEXT: ptrue p0.h, vl8 +; CHECK-NEXT: fmax z0.h, p0/m, z0.h, z1.h +; CHECK-NEXT: fmaxv h0, p0, z0.h +; CHECK-NEXT: // kill: def $h0 killed $h0 killed $z0 +; CHECK-NEXT: ret + %op = load <16 x half>, ptr %a + %res = call half @llvm.vector.reduce.fmaximum.v16f16(<16 x half> %op) + ret half %res +} + +define float @fmaximumv_v2f32(<2 x float> %a) #0 { +; CHECK-LABEL: fmaximumv_v2f32: +; CHECK: // %bb.0: +; CHECK-NEXT: // kill: def $d0 killed $d0 def $z0 +; CHECK-NEXT: ptrue p0.s, vl2 +; CHECK-NEXT: fmaxv s0, p0, z0.s +; CHECK-NEXT: // kill: def $s0 killed $s0 killed $z0 +; CHECK-NEXT: ret + %res = call float @llvm.vector.reduce.fmaximum.v2f32(<2 x float> %a) + ret float %res +} + +define float @fmaximumv_v4f32(<4 x float> %a) #0 { +; CHECK-LABEL: fmaximumv_v4f32: +; CHECK: // %bb.0: +; CHECK-NEXT: // kill: def $q0 killed $q0 def $z0 +; CHECK-NEXT: ptrue p0.s, vl4 +; CHECK-NEXT: fmaxv s0, p0, z0.s +; CHECK-NEXT: // kill: def $s0 killed $s0 killed $z0 +; CHECK-NEXT: ret + %res = call float @llvm.vector.reduce.fmaximum.v4f32(<4 x float> %a) + ret float %res +} + +define float @fmaximumv_v8f32(ptr %a) #0 { +; CHECK-LABEL: fmaximumv_v8f32: +; CHECK: // %bb.0: +; CHECK-NEXT: ldp q1, q0, [x0] +; CHECK-NEXT: ptrue p0.s, vl4 +; CHECK-NEXT: fmax z0.s, p0/m, z0.s, z1.s +; CHECK-NEXT: fmaxv s0, p0, z0.s +; CHECK-NEXT: // kill: def $s0 killed $s0 killed $z0 +; CHECK-NEXT: ret + %op = load <8 x float>, ptr %a + %res = call float @llvm.vector.reduce.fmaximum.v8f32(<8 x float> %op) + ret float %res +} + +define double @fmaximumv_v1f64(<1 x double> %a) #0 { +; CHECK-LABEL: fmaximumv_v1f64: +; CHECK: // %bb.0: +; CHECK-NEXT: // kill: def $d0 killed $d0 def $z0 +; CHECK-NEXT: // kill: def $d0 killed $d0 killed $z0 +; CHECK-NEXT: ret + %res = call double @llvm.vector.reduce.fmaximum.v1f64(<1 x double> %a) + ret double %res +} + +define double @fmaximumv_v2f64(<2 x double> %a) #0 { +; CHECK-LABEL: fmaximumv_v2f64: +; CHECK: // %bb.0: +; CHECK-NEXT: // kill: def $q0 killed $q0 def $z0 +; CHECK-NEXT: ptrue p0.d, vl2 +; CHECK-NEXT: fmaxv d0, p0, z0.d +; CHECK-NEXT: // kill: def $d0 killed $d0 killed $z0 +; CHECK-NEXT: ret + %res = call double @llvm.vector.reduce.fmaximum.v2f64(<2 x double> %a) + ret double %res +} + +define double @fmaximumv_v4f64(ptr %a) #0 { +; CHECK-LABEL: fmaximumv_v4f64: +; CHECK: // %bb.0: +; CHECK-NEXT: ldp q1, q0, [x0] +; CHECK-NEXT: ptrue p0.d, vl2 +; CHECK-NEXT: fmax z0.d, p0/m, z0.d, z1.d +; CHECK-NEXT: fmaxv d0, p0, z0.d +; CHECK-NEXT: // kill: def $d0 killed $d0 killed $z0 +; CHECK-NEXT: ret + %op = load <4 x double>, ptr %a + %res = call double @llvm.vector.reduce.fmaximum.v4f64(<4 x double> %op) + ret double %res +} + +; +; FMINV +; + +define half @fminimumv_v4f16(<4 x half> %a) #0 { +; CHECK-LABEL: fminimumv_v4f16: +; CHECK: // %bb.0: +; CHECK-NEXT: // kill: def $d0 killed $d0 def $z0 +; CHECK-NEXT: ptrue p0.h, vl4 +; CHECK-NEXT: fminv h0, p0, z0.h +; CHECK-NEXT: // kill: def $h0 killed $h0 killed $z0 +; CHECK-NEXT: ret + %res = call half @llvm.vector.reduce.fminimum.v4f16(<4 x half> %a) + ret half %res +} + +define half @fminimumv_v8f16(<8 x half> %a) #0 { +; CHECK-LABEL: fminimumv_v8f16: +; CHECK: // %bb.0: +; CHECK-NEXT: // kill: def $q0 killed $q0 def $z0 +; CHECK-NEXT: ptrue p0.h, vl8 +; CHECK-NEXT: fminv h0, p0, z0.h +; CHECK-NEXT: // kill: def $h0 killed $h0 killed $z0 +; CHECK-NEXT: ret + %res = call half @llvm.vector.reduce.fminimum.v8f16(<8 x half> %a) + ret half %res +} + +define half @fminimumv_v16f16(ptr %a) #0 { +; CHECK-LABEL: fminimumv_v16f16: +; CHECK: // %bb.0: +; CHECK-NEXT: ldp q1, q0, [x0] +; CHECK-NEXT: ptrue p0.h, vl8 +; CHECK-NEXT: fmin z0.h, p0/m, z0.h, z1.h +; CHECK-NEXT: fminv h0, p0, z0.h +; CHECK-NEXT: // kill: def $h0 killed $h0 killed $z0 +; CHECK-NEXT: ret + %op = load <16 x half>, ptr %a + %res = call half @llvm.vector.reduce.fminimum.v16f16(<16 x half> %op) + ret half %res +} + +define float @fminimumv_v2f32(<2 x float> %a) #0 { +; CHECK-LABEL: fminimumv_v2f32: +; CHECK: // %bb.0: +; CHECK-NEXT: // kill: def $d0 killed $d0 def $z0 +; CHECK-NEXT: ptrue p0.s, vl2 +; CHECK-NEXT: fminv s0, p0, z0.s +; CHECK-NEXT: // kill: def $s0 killed $s0 killed $z0 +; CHECK-NEXT: ret + %res = call float @llvm.vector.reduce.fminimum.v2f32(<2 x float> %a) + ret float %res +} + +define float @fminimumv_v4f32(<4 x float> %a) #0 { +; CHECK-LABEL: fminimumv_v4f32: +; CHECK: // %bb.0: +; CHECK-NEXT: // kill: def $q0 killed $q0 def $z0 +; CHECK-NEXT: ptrue p0.s, vl4 +; CHECK-NEXT: fminv s0, p0, z0.s +; CHECK-NEXT: // kill: def $s0 killed $s0 killed $z0 +; CHECK-NEXT: ret + %res = call float @llvm.vector.reduce.fminimum.v4f32(<4 x float> %a) + ret float %res +} + +define float @fminimumv_v8f32(ptr %a) #0 { +; CHECK-LABEL: fminimumv_v8f32: +; CHECK: // %bb.0: +; CHECK-NEXT: ldp q1, q0, [x0] +; CHECK-NEXT: ptrue p0.s, vl4 +; CHECK-NEXT: fmin z0.s, p0/m, z0.s, z1.s +; CHECK-NEXT: fminv s0, p0, z0.s +; CHECK-NEXT: // kill: def $s0 killed $s0 killed $z0 +; CHECK-NEXT: ret + %op = load <8 x float>, ptr %a + %res = call float @llvm.vector.reduce.fminimum.v8f32(<8 x float> %op) + ret float %res +} + +define double @fminimumv_v1f64(<1 x double> %a) #0 { +; CHECK-LABEL: fminimumv_v1f64: +; CHECK: // %bb.0: +; CHECK-NEXT: // kill: def $d0 killed $d0 def $z0 +; CHECK-NEXT: // kill: def $d0 killed $d0 killed $z0 +; CHECK-NEXT: ret + %res = call double @llvm.vector.reduce.fminimum.v1f64(<1 x double> %a) + ret double %res +} + +define double @fminimumv_v2f64(<2 x double> %a) #0 { +; CHECK-LABEL: fminimumv_v2f64: +; CHECK: // %bb.0: +; CHECK-NEXT: // kill: def $q0 killed $q0 def $z0 +; CHECK-NEXT: ptrue p0.d, vl2 +; CHECK-NEXT: fminv d0, p0, z0.d +; CHECK-NEXT: // kill: def $d0 killed $d0 killed $z0 +; CHECK-NEXT: ret + %res = call double @llvm.vector.reduce.fminimum.v2f64(<2 x double> %a) + ret double %res +} + +define double @fminimumv_v4f64(ptr %a) #0 { +; CHECK-LABEL: fminimumv_v4f64: +; CHECK: // %bb.0: +; CHECK-NEXT: ldp q1, q0, [x0] +; CHECK-NEXT: ptrue p0.d, vl2 +; CHECK-NEXT: fmin z0.d, p0/m, z0.d, z1.d +; CHECK-NEXT: fminv d0, p0, z0.d +; CHECK-NEXT: // kill: def $d0 killed $d0 killed $z0 +; CHECK-NEXT: ret + %op = load <4 x double>, ptr %a + %res = call double @llvm.vector.reduce.fminimum.v4f64(<4 x double> %op) + ret double %res +} + attributes #0 = { "target-features"="+sve" } declare half @llvm.vector.reduce.fadd.v4f16(half, <4 x half>) @@ -512,3 +744,27 @@ declare double @llvm.vector.reduce.fmin.v1f64(<1 x double>) declare double @llvm.vector.reduce.fmin.v2f64(<2 x double>) declare double @llvm.vector.reduce.fmin.v4f64(<4 x double>) + +declare half @llvm.vector.reduce.fmaximum.v4f16(<4 x half>) +declare half @llvm.vector.reduce.fmaximum.v8f16(<8 x half>) +declare half @llvm.vector.reduce.fmaximum.v16f16(<16 x half>) + +declare float @llvm.vector.reduce.fmaximum.v2f32(<2 x float>) +declare float @llvm.vector.reduce.fmaximum.v4f32(<4 x float>) +declare float @llvm.vector.reduce.fmaximum.v8f32(<8 x float>) + +declare double @llvm.vector.reduce.fmaximum.v1f64(<1 x double>) +declare double @llvm.vector.reduce.fmaximum.v2f64(<2 x double>) +declare double @llvm.vector.reduce.fmaximum.v4f64(<4 x double>) + +declare half @llvm.vector.reduce.fminimum.v4f16(<4 x half>) +declare half @llvm.vector.reduce.fminimum.v8f16(<8 x half>) +declare half @llvm.vector.reduce.fminimum.v16f16(<16 x half>) + +declare float @llvm.vector.reduce.fminimum.v2f32(<2 x float>) +declare float @llvm.vector.reduce.fminimum.v4f32(<4 x float>) +declare float @llvm.vector.reduce.fminimum.v8f32(<8 x float>) + +declare double @llvm.vector.reduce.fminimum.v1f64(<1 x double>) +declare double @llvm.vector.reduce.fminimum.v2f64(<2 x double>) +declare double @llvm.vector.reduce.fminimum.v4f64(<4 x double>)