Index: llvm/lib/Target/AArch64/AArch64ISelLowering.h =================================================================== --- llvm/lib/Target/AArch64/AArch64ISelLowering.h +++ llvm/lib/Target/AArch64/AArch64ISelLowering.h @@ -909,6 +909,7 @@ SDValue LowerFixedLengthVectorIntExtendToSVE(SDValue Op, SelectionDAG &DAG) const; SDValue LowerFixedLengthVectorLoadToSVE(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerFixedLengthVectorSelectToSVE(SDValue Op, SelectionDAG &DAG) const; SDValue LowerFixedLengthVectorSetccToSVE(SDValue Op, SelectionDAG &DAG) const; SDValue LowerFixedLengthVectorStoreToSVE(SDValue Op, SelectionDAG &DAG) const; SDValue LowerFixedLengthVectorTruncateToSVE(SDValue Op, Index: llvm/lib/Target/AArch64/AArch64ISelLowering.cpp =================================================================== --- llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -1131,6 +1131,7 @@ setOperationAction(ISD::MUL, VT, Custom); setOperationAction(ISD::OR, VT, Custom); setOperationAction(ISD::SDIV, VT, Custom); + setOperationAction(ISD::VSELECT, VT, Custom); setOperationAction(ISD::SETCC, VT, Custom); setOperationAction(ISD::SHL, VT, Custom); setOperationAction(ISD::SIGN_EXTEND, VT, Custom); @@ -3745,6 +3746,8 @@ return LowerToPredicatedOp(Op, DAG, AArch64ISD::FMAXNM_PRED); case ISD::FMINNUM: return LowerToPredicatedOp(Op, DAG, AArch64ISD::FMINNM_PRED); + case ISD::VSELECT: + return LowerFixedLengthVectorSelectToSVE(Op, DAG); } } @@ -15569,6 +15572,30 @@ return convertFromScalableVector(DAG, VT, ScalableRes); } +SDValue +AArch64TargetLowering::LowerFixedLengthVectorSelectToSVE(SDValue Op, + SelectionDAG &DAG) const { + EVT VT = Op.getValueType(); + SDLoc DL(Op); + + EVT InVT = Op.getOperand(1).getValueType(); + EVT ContainerVT = getContainerForFixedLengthVector(DAG, InVT); + SDValue Op1 = convertToScalableVector(DAG, ContainerVT, Op->getOperand(1)); + SDValue Op2 = convertToScalableVector(DAG, ContainerVT, Op->getOperand(2)); + + // Convert the mask to a predicated (NOTE: We don't need to worry about + // inactive lanes since VSELECT is safe when given undefined elements). + EVT MaskVT = Op.getOperand(0).getValueType(); + EVT MaskContainerVT = getContainerForFixedLengthVector(DAG, MaskVT); + auto Mask = convertToScalableVector(DAG, MaskContainerVT, Op.getOperand(0)); + Mask = DAG.getNode(ISD::TRUNCATE, DL, + MaskContainerVT.changeVectorElementType(MVT::i1), Mask); + + auto ScalableRes = DAG.getNode(ISD::VSELECT, DL, ContainerVT, + Mask, Op1, Op2); + return convertFromScalableVector(DAG, VT, ScalableRes); +} + SDValue AArch64TargetLowering::LowerFixedLengthVectorSetccToSVE( SDValue Op, SelectionDAG &DAG) const { SDLoc DL(Op); Index: llvm/test/CodeGen/AArch64/sve-fixed-length-fp-select.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/AArch64/sve-fixed-length-fp-select.ll @@ -0,0 +1,318 @@ +; RUN: llc -aarch64-sve-vector-bits-min=128 -asm-verbose=0 < %s | FileCheck %s -D#VBYTES=16 -check-prefix=NO_SVE +; RUN: llc -aarch64-sve-vector-bits-min=256 -asm-verbose=0 < %s | FileCheck %s -D#VBYTES=32 -check-prefixes=CHECK,VBITS_EQ_256 +; RUN: llc -aarch64-sve-vector-bits-min=384 -asm-verbose=0 < %s | FileCheck %s -D#VBYTES=32 -check-prefixes=CHECK +; RUN: llc -aarch64-sve-vector-bits-min=512 -asm-verbose=0 < %s | FileCheck %s -D#VBYTES=64 -check-prefixes=CHECK,VBITS_GE_512 +; RUN: llc -aarch64-sve-vector-bits-min=640 -asm-verbose=0 < %s | FileCheck %s -D#VBYTES=64 -check-prefixes=CHECK,VBITS_GE_512 +; RUN: llc -aarch64-sve-vector-bits-min=768 -asm-verbose=0 < %s | FileCheck %s -D#VBYTES=64 -check-prefixes=CHECK,VBITS_GE_512 +; RUN: llc -aarch64-sve-vector-bits-min=896 -asm-verbose=0 < %s | FileCheck %s -D#VBYTES=64 -check-prefixes=CHECK,VBITS_GE_512 +; RUN: llc -aarch64-sve-vector-bits-min=1024 -asm-verbose=0 < %s | FileCheck %s -D#VBYTES=128 -check-prefixes=CHECK,VBITS_GE_512,VBITS_GE_1024 +; RUN: llc -aarch64-sve-vector-bits-min=1152 -asm-verbose=0 < %s | FileCheck %s -D#VBYTES=128 -check-prefixes=CHECK,VBITS_GE_512,VBITS_GE_1024 +; RUN: llc -aarch64-sve-vector-bits-min=1280 -asm-verbose=0 < %s | FileCheck %s -D#VBYTES=128 -check-prefixes=CHECK,VBITS_GE_512,VBITS_GE_1024 +; RUN: llc -aarch64-sve-vector-bits-min=1408 -asm-verbose=0 < %s | FileCheck %s -D#VBYTES=128 -check-prefixes=CHECK,VBITS_GE_512,VBITS_GE_1024 +; RUN: llc -aarch64-sve-vector-bits-min=1536 -asm-verbose=0 < %s | FileCheck %s -D#VBYTES=128 -check-prefixes=CHECK,VBITS_GE_512,VBITS_GE_1024 +; RUN: llc -aarch64-sve-vector-bits-min=1664 -asm-verbose=0 < %s | FileCheck %s -D#VBYTES=128 -check-prefixes=CHECK,VBITS_GE_512,VBITS_GE_1024 +; RUN: llc -aarch64-sve-vector-bits-min=1792 -asm-verbose=0 < %s | FileCheck %s -D#VBYTES=128 -check-prefixes=CHECK,VBITS_GE_512,VBITS_GE_1024 +; RUN: llc -aarch64-sve-vector-bits-min=1920 -asm-verbose=0 < %s | FileCheck %s -D#VBYTES=128 -check-prefixes=CHECK,VBITS_GE_512,VBITS_GE_1024 +; RUN: llc -aarch64-sve-vector-bits-min=2048 -asm-verbose=0 < %s | FileCheck %s -D#VBYTES=256 -check-prefixes=CHECK,VBITS_GE_512,VBITS_GE_1024,VBITS_GE_2048 + +target triple = "aarch64-unknown-linux-gnu" + +; Don't use SVE when its registers are no bigger than NEON. +; NO_SVE-NOT: ptrue + +; Don't use SVE for 64-bit vectors. +define void @select_v4f16(<4 x half>* %a, <4 x half>* %b, <4 x i1>* %c) #0 { +; CHECK-LABEL: select_v4f16: +; CHECK: bif v0.8b, v1.8b, v2.8b +; CHECK: ret + %mask = load <4 x i1>, <4 x i1>* %c + %op1 = load <4 x half>, <4 x half>* %a + %op2 = load <4 x half>, <4 x half>* %b + %sel = select <4 x i1> %mask, <4 x half> %op1, <4 x half> %op2 + store <4 x half> %sel, <4 x half>* %a + ret void +} + +; Don't use SVE for 128-bit vectors. +define void @select_v8f16(<8 x half>* %a, <8 x half>* %b, <8 x i1>* %c) #0 { +; CHECK-LABEL: select_v8f16: +; CHECK: bif v0.16b, v1.16b, v2.16b +; CHECK: ret + %mask = load <8 x i1>, <8 x i1>* %c + %op1 = load <8 x half>, <8 x half>* %a + %op2 = load <8 x half>, <8 x half>* %b + %sel = select <8 x i1> %mask, <8 x half> %op1, <8 x half> %op2 + store <8 x half> %sel, <8 x half>* %a + ret void +} + +define void @select_v16f16(<16 x half>* %a, <16 x half>* %b, <16 x i1>* %c) #0 { +; CHECK-LABEL: select_v16f16: +; VBITS_GE_256: ld1h { z0.h }, p0/z, [x9] +; VBITS_GE_256-NEXT: ld1h { z1.h }, p0/z, [x0] +; VBITS_GE_256-NEXT: ld1h { z2.h }, p0/z, [x1] +; VBITS_GE_256-NEXT: and z0.h, z0.h, #0x1 +; VBITS_GE_256-NEXT: cmpne p1.h, p1/z, z0.h, #0 +; VBITS_GE_256-NEXT: sel z0.h, p1, z1.h, z2.h +; VBITS_GE_256-NEXT: st1h { z0.h }, p0, [x0] +; VBITS_GE_256: ret + %mask = load <16 x i1>, <16 x i1>* %c + %op1 = load <16 x half>, <16 x half>* %a + %op2 = load <16 x half>, <16 x half>* %b + %sel = select <16 x i1> %mask, <16 x half> %op1, <16 x half> %op2 + store <16 x half> %sel, <16 x half>* %a + ret void +} + +define void @select_v32f16(<32 x half>* %a, <32 x half>* %b, <32 x i1>* %c) #0 { +; CHECK-LABEL: select_v32f16: +; VBITS_GE_512: ld1h { z0.h }, p0/z, [x9] +; VBITS_GE_512-NEXT: ld1h { z1.h }, p0/z, [x0] +; VBITS_GE_512-NEXT: ld1h { z2.h }, p0/z, [x1] +; VBITS_GE_512-NEXT: and z0.h, z0.h, #0x1 +; VBITS_GE_512-NEXT: cmpne p1.h, p1/z, z0.h, #0 +; VBITS_GE_512-NEXT: sel z0.h, p1, z1.h, z2.h +; VBITS_GE_512-NEXT: st1h { z0.h }, p0, [x0] +; VBITS_GE_512: ret + %mask = load <32 x i1>, <32 x i1>* %c + %op1 = load <32 x half>, <32 x half>* %a + %op2 = load <32 x half>, <32 x half>* %b + %sel = select <32 x i1> %mask, <32 x half> %op1, <32 x half> %op2 + store <32 x half> %sel, <32 x half>* %a + ret void +} + +define void @select_v64f16(<64 x half>* %a, <64 x half>* %b, <64 x i1>* %c) #0 { +; CHECK-LABEL: select_v64f16: +; VBITS_GE_1024: ld1h { z0.h }, p0/z, [x9] +; VBITS_GE_1024-NEXT: ld1h { z1.h }, p0/z, [x0] +; VBITS_GE_1024-NEXT: ld1h { z2.h }, p0/z, [x1] +; VBITS_GE_1024-NEXT: and z0.h, z0.h, #0x1 +; VBITS_GE_1024-NEXT: cmpne p1.h, p1/z, z0.h, #0 +; VBITS_GE_1024-NEXT: sel z0.h, p1, z1.h, z2.h +; VBITS_GE_1024-NEXT: st1h { z0.h }, p0, [x0] +; VBITS_GE_1024: ret + %mask = load <64 x i1>, <64 x i1>* %c + %op1 = load <64 x half>, <64 x half>* %a + %op2 = load <64 x half>, <64 x half>* %b + %sel = select <64 x i1> %mask, <64 x half> %op1, <64 x half> %op2 + store <64 x half> %sel, <64 x half>* %a + ret void +} + +define void @select_v128f16(<128 x half>* %a, <128 x half>* %b, <128 x i1>* %c) #0 { +; CHECK-LABEL: select_v128f16: +; VBITS_GE_2048: ld1h { z0.h }, p0/z, [x9] +; VBITS_GE_2048-NEXT: ld1h { z1.h }, p0/z, [x0] +; VBITS_GE_2048-NEXT: ld1h { z2.h }, p0/z, [x1] +; VBITS_GE_2048-NEXT: and z0.h, z0.h, #0x1 +; VBITS_GE_2048-NEXT: cmpne p1.h, p1/z, z0.h, #0 +; VBITS_GE_2048-NEXT: sel z0.h, p1, z1.h, z2.h +; VBITS_GE_2048-NEXT: st1h { z0.h }, p0, [x0] +; VBITS_GE_2048: ret + %mask = load <128 x i1>, <128 x i1>* %c + %op1 = load <128 x half>, <128 x half>* %a + %op2 = load <128 x half>, <128 x half>* %b + %sel = select <128 x i1> %mask, <128 x half> %op1, <128 x half> %op2 + store <128 x half> %sel, <128 x half>* %a + ret void +} + +; Don't use SVE for 64-bit vectors. +define void @select_v2f32(<2 x float>* %a, <2 x float>* %b, <2 x i1>* %c) #0 { +; CHECK-LABEL: select_v2f32: +; CHECK: bif v0.8b, v1.8b, v2.8b +; CHECK: ret + %mask = load <2 x i1>, <2 x i1>* %c + %op1 = load <2 x float>, <2 x float>* %a + %op2 = load <2 x float>, <2 x float>* %b + %sel = select <2 x i1> %mask, <2 x float> %op1, <2 x float> %op2 + store <2 x float> %sel, <2 x float>* %a + ret void +} + +; Don't use SVE for 128-bit vectors. +define void @select_v4f32(<4 x float>* %a, <4 x float>* %b, <4 x i1>* %c) #0 { +; CHECK-LABEL: select_v4f32: +; CHECK: bif v0.16b, v1.16b, v2.16b +; CHECK: ret + %mask = load <4 x i1>, <4 x i1>* %c + %op1 = load <4 x float>, <4 x float>* %a + %op2 = load <4 x float>, <4 x float>* %b + %sel = select <4 x i1> %mask, <4 x float> %op1, <4 x float> %op2 + store <4 x float> %sel, <4 x float>* %a + ret void +} + +define void @select_v8f32(<8 x float>* %a, <8 x float>* %b, <8 x i1>* %c) #0 { +; CHECK-LABEL: select_v8f32: +; VBITS_GE_256: ld1w { z0.s }, p0/z, [x9] +; VBITS_GE_256-NEXT: ld1w { z1.s }, p0/z, [x0] +; VBITS_GE_256-NEXT: ld1w { z2.s }, p0/z, [x1] +; VBITS_GE_256-NEXT: and z0.s, z0.s, #0x1 +; VBITS_GE_256-NEXT: cmpne p1.s, p1/z, z0.s, #0 +; VBITS_GE_256-NEXT: sel z0.s, p1, z1.s, z2.s +; VBITS_GE_256-NEXT: st1w { z0.s }, p0, [x0] +; VBITS_GE_256: ret + %mask = load <8 x i1>, <8 x i1>* %c + %op1 = load <8 x float>, <8 x float>* %a + %op2 = load <8 x float>, <8 x float>* %b + %sel = select <8 x i1> %mask, <8 x float> %op1, <8 x float> %op2 + store <8 x float> %sel, <8 x float>* %a + ret void +} + +define void @select_v16f32(<16 x float>* %a, <16 x float>* %b, <16 x i1>* %c) #0 { +; CHECK-LABEL: select_v16f32: +; VBITS_GE_512: ld1w { z0.s }, p0/z, [x9] +; VBITS_GE_512-NEXT: ld1w { z1.s }, p0/z, [x0] +; VBITS_GE_512-NEXT: ld1w { z2.s }, p0/z, [x1] +; VBITS_GE_512-NEXT: and z0.s, z0.s, #0x1 +; VBITS_GE_512-NEXT: cmpne p1.s, p1/z, z0.s, #0 +; VBITS_GE_512-NEXT: sel z0.s, p1, z1.s, z2.s +; VBITS_GE_512-NEXT: st1w { z0.s }, p0, [x0] +; VBITS_GE_512: ret + %mask = load <16 x i1>, <16 x i1>* %c + %op1 = load <16 x float>, <16 x float>* %a + %op2 = load <16 x float>, <16 x float>* %b + %sel = select <16 x i1> %mask, <16 x float> %op1, <16 x float> %op2 + store <16 x float> %sel, <16 x float>* %a + ret void +} + +define void @select_v32f32(<32 x float>* %a, <32 x float>* %b, <32 x i1>* %c) #0 { +; CHECK-LABEL: select_v32f32: +; VBITS_GE_1024: ld1w { z0.s }, p0/z, [x9] +; VBITS_GE_1024-NEXT: ld1w { z1.s }, p0/z, [x0] +; VBITS_GE_1024-NEXT: ld1w { z2.s }, p0/z, [x1] +; VBITS_GE_1024-NEXT: and z0.s, z0.s, #0x1 +; VBITS_GE_1024-NEXT: cmpne p1.s, p1/z, z0.s, #0 +; VBITS_GE_1024-NEXT: sel z0.s, p1, z1.s, z2.s +; VBITS_GE_1024-NEXT: st1w { z0.s }, p0, [x0] +; VBITS_GE_1024: ret + %mask = load <32 x i1>, <32 x i1>* %c + %op1 = load <32 x float>, <32 x float>* %a + %op2 = load <32 x float>, <32 x float>* %b + %sel = select <32 x i1> %mask, <32 x float> %op1, <32 x float> %op2 + store <32 x float> %sel, <32 x float>* %a + ret void +} + +define void @select_v64f32(<64 x float>* %a, <64 x float>* %b, <64 x i1>* %c) #0 { +; CHECK-LABEL: select_v64f32: +; VBITS_GE_2048: ld1w { z0.s }, p0/z, [x9] +; VBITS_GE_2048-NEXT: ld1w { z1.s }, p0/z, [x0] +; VBITS_GE_2048-NEXT: ld1w { z2.s }, p0/z, [x1] +; VBITS_GE_2048-NEXT: and z0.s, z0.s, #0x1 +; VBITS_GE_2048-NEXT: cmpne p1.s, p1/z, z0.s, #0 +; VBITS_GE_2048-NEXT: sel z0.s, p1, z1.s, z2.s +; VBITS_GE_2048-NEXT: st1w { z0.s }, p0, [x0] +; VBITS_GE_2048: ret + %mask = load <64 x i1>, <64 x i1>* %c + %op1 = load <64 x float>, <64 x float>* %a + %op2 = load <64 x float>, <64 x float>* %b + %sel = select <64 x i1> %mask, <64 x float> %op1, <64 x float> %op2 + store <64 x float> %sel, <64 x float>* %a + ret void +} + +; Don't use SVE for 64-bit vectors. +define void @select_v1f64(<1 x double>* %a, <1 x double>* %b, <1 x i1>* %c) #0 { +; CHECK-LABEL: select_v1f64: +; CHECK: cmp w8, #0 +; CHECK: csel x8, x0, x1, ne +; CHECK: ret + %mask = load <1 x i1>, <1 x i1>* %c + %op1 = load <1 x double>, <1 x double>* %a + %op2 = load <1 x double>, <1 x double>* %b + %sel = select <1 x i1> %mask, <1 x double> %op1, <1 x double> %op2 + store <1 x double> %sel, <1 x double>* %a + ret void +} + +; Don't use SVE for 128-bit vectors. +define void @select_v2f64(<2 x double>* %a, <2 x double>* %b, <2 x i1>* %c) #0 { +; CHECK-LABEL: select_v2f64: +; CHECK: bif v0.16b, v1.16b, v2.16b +; CHECK: ret + %mask = load <2 x i1>, <2 x i1>* %c + %op1 = load <2 x double>, <2 x double>* %a + %op2 = load <2 x double>, <2 x double>* %b + %sel = select <2 x i1> %mask, <2 x double> %op1, <2 x double> %op2 + store <2 x double> %sel, <2 x double>* %a + ret void +} + +define void @select_v4f64(<4 x double>* %a, <4 x double>* %b, <4 x i1>* %c) #0 { +; CHECK-LABEL: select_v4f64: +; VBITS_GE_256: ld1d { z0.d }, p0/z, [x9] +; VBITS_GE_256-NEXT: ld1d { z1.d }, p0/z, [x0] +; VBITS_GE_256-NEXT: ld1d { z2.d }, p0/z, [x1] +; VBITS_GE_256-NEXT: and z0.d, z0.d, #0x1 +; VBITS_GE_256-NEXT: cmpne p1.d, p1/z, z0.d, #0 +; VBITS_GE_256-NEXT: sel z0.d, p1, z1.d, z2.d +; VBITS_GE_256-NEXT: st1d { z0.d }, p0, [x0] +; VBITS_GE_256: ret + %mask = load <4 x i1>, <4 x i1>* %c + %op1 = load <4 x double>, <4 x double>* %a + %op2 = load <4 x double>, <4 x double>* %b + %sel = select <4 x i1> %mask, <4 x double> %op1, <4 x double> %op2 + store <4 x double> %sel, <4 x double>* %a + ret void +} + +define void @select_v8f64(<8 x double>* %a, <8 x double>* %b, <8 x i1>* %c) #0 { +; CHECK-LABEL: select_v8f64: +; VBITS_GE_512: ld1d { z0.d }, p0/z, [x9] +; VBITS_GE_512-NEXT: ld1d { z1.d }, p0/z, [x0] +; VBITS_GE_512-NEXT: ld1d { z2.d }, p0/z, [x1] +; VBITS_GE_512-NEXT: and z0.d, z0.d, #0x1 +; VBITS_GE_512-NEXT: cmpne p1.d, p1/z, z0.d, #0 +; VBITS_GE_512-NEXT: sel z0.d, p1, z1.d, z2.d +; VBITS_GE_512-NEXT: st1d { z0.d }, p0, [x0] +; VBITS_GE_512: ret + %mask = load <8 x i1>, <8 x i1>* %c + %op1 = load <8 x double>, <8 x double>* %a + %op2 = load <8 x double>, <8 x double>* %b + %sel = select <8 x i1> %mask, <8 x double> %op1, <8 x double> %op2 + store <8 x double> %sel, <8 x double>* %a + ret void +} + +define void @select_v16f64(<16 x double>* %a, <16 x double>* %b, <16 x i1>* %c) #0 { +; CHECK-LABEL: select_v16f64: +; VBITS_GE_1024: ld1d { z0.d }, p0/z, [x9] +; VBITS_GE_1024-NEXT: ld1d { z1.d }, p0/z, [x0] +; VBITS_GE_1024-NEXT: ld1d { z2.d }, p0/z, [x1] +; VBITS_GE_1024-NEXT: and z0.d, z0.d, #0x1 +; VBITS_GE_1024-NEXT: cmpne p1.d, p1/z, z0.d, #0 +; VBITS_GE_1024-NEXT: sel z0.d, p1, z1.d, z2.d +; VBITS_GE_1024-NEXT: st1d { z0.d }, p0, [x0] +; VBITS_GE_1024: ret + %mask = load <16 x i1>, <16 x i1>* %c + %op1 = load <16 x double>, <16 x double>* %a + %op2 = load <16 x double>, <16 x double>* %b + %sel = select <16 x i1> %mask, <16 x double> %op1, <16 x double> %op2 + store <16 x double> %sel, <16 x double>* %a + ret void +} + +define void @select_v32f64(<32 x double>* %a, <32 x double>* %b, <32 x i1>* %c) #0 { +; CHECK-LABEL: select_v32f64: +; VBITS_GE_2048: ld1d { z0.d }, p0/z, [x9] +; VBITS_GE_2048-NEXT: ld1d { z1.d }, p0/z, [x0] +; VBITS_GE_2048-NEXT: ld1d { z2.d }, p0/z, [x1] +; VBITS_GE_2048-NEXT: and z0.d, z0.d, #0x1 +; VBITS_GE_2048-NEXT: cmpne p1.d, p1/z, z0.d, #0 +; VBITS_GE_2048-NEXT: sel z0.d, p1, z1.d, z2.d +; VBITS_GE_2048-NEXT: st1d { z0.d }, p0, [x0] +; VBITS_GE_2048: ret + %mask = load <32 x i1>, <32 x i1>* %c + %op1 = load <32 x double>, <32 x double>* %a + %op2 = load <32 x double>, <32 x double>* %b + %sel = select <32 x i1> %mask, <32 x double> %op1, <32 x double> %op2 + store <32 x double> %sel, <32 x double>* %a + ret void +} + +attributes #0 = { "target-features"="+sve" }