diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.h b/llvm/lib/Target/AArch64/AArch64ISelLowering.h --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.h +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.h @@ -892,6 +892,7 @@ bool isExtFreeImpl(const Instruction *Ext) const override; void addTypeForNEON(MVT VT); + void addTypeForStreamingSVE(MVT VT); void addTypeForFixedLengthSVE(MVT VT); void addDRTypeForNEON(MVT VT); void addQRTypeForNEON(MVT VT); 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 @@ -1394,6 +1394,16 @@ for (auto VT : {MVT::v4f16, MVT::v8f16, MVT::v2f32, MVT::v4f32, MVT::v2f64}) setOperationAction(ISD::VECREDUCE_SEQ_FADD, VT, Custom); + if (Subtarget->forceStreamingCompatibleMode()) { + for (MVT VT : MVT::integer_fixedlen_vector_valuetypes()) + if (useSVEForFixedLengthVectorVT(VT, true)) + addTypeForStreamingSVE(VT); + + for (MVT VT : MVT::fp_fixedlen_vector_valuetypes()) + if (useSVEForFixedLengthVectorVT(VT, true)) + addTypeForStreamingSVE(VT); + } + // NOTE: Currently this has to happen after computeRegisterProperties rather // than the preferred option of combining it with the addRegisterClass call. if (Subtarget->useSVEForFixedLengthVectors()) { @@ -1600,6 +1610,14 @@ return false; } +void AArch64TargetLowering::addTypeForStreamingSVE(MVT VT) { + // setOperationAction(ISD::ANY_EXTEND, VT, Custom); + // setOperationAction(ISD::ZERO_EXTEND, VT, Custom); + // setOperationAction(ISD::SIGN_EXTEND, VT, Custom); + setOperationAction(ISD::LOAD, VT, Custom); + // setOperationAction(ISD::CONCAT_VECTORS, VT, Custom); +} + void AArch64TargetLowering::addTypeForFixedLengthSVE(MVT VT) { assert(VT.isFixedLengthVector() && "Expected fixed length vector type!"); @@ -5760,7 +5778,8 @@ case ISD::MLOAD: return LowerMLOAD(Op, DAG); case ISD::LOAD: - if (useSVEForFixedLengthVectorVT(Op.getValueType())) + if (useSVEForFixedLengthVectorVT(Op.getValueType(), + Subtarget->forceStreamingCompatibleMode())) return LowerFixedLengthVectorLoadToSVE(Op, DAG); return LowerLOAD(Op, DAG); case ISD::ADD: @@ -11571,7 +11590,9 @@ SelectionDAG &DAG) const { EVT VT = Op.getValueType(); - if (useSVEForFixedLengthVectorVT(VT)) { + // override NEON if possible. + if (useSVEForFixedLengthVectorVT(VT, + Subtarget->forceStreamingCompatibleMode())) { if (auto SeqInfo = cast(Op)->isConstantSequence()) { SDLoc DL(Op); EVT ContainerVT = getContainerForFixedLengthVector(DAG, VT); @@ -12007,6 +12028,7 @@ return DAG.getAnyExtOrTrunc(Extract, DL, Op.getValueType()); } + // try overriding NEON if possible. if (useSVEForFixedLengthVectorVT(VT)) return LowerFixedLengthExtractVectorElt(Op, DAG); @@ -12370,6 +12392,7 @@ switch (Op.getOpcode()) { case ISD::SHL: + // override NEON if possible. if (VT.isScalableVector() || useSVEForFixedLengthVectorVT(VT)) return LowerToPredicatedOp(Op, DAG, AArch64ISD::SHL_PRED); @@ -12382,6 +12405,7 @@ Op.getOperand(0), Op.getOperand(1)); case ISD::SRA: case ISD::SRL: + // override NEON if possible. if (VT.isScalableVector() || useSVEForFixedLengthVectorVT(VT)) { unsigned Opc = Op.getOpcode() == ISD::SRA ? AArch64ISD::SRA_PRED : AArch64ISD::SRL_PRED; diff --git a/llvm/lib/Target/AArch64/AArch64Subtarget.h b/llvm/lib/Target/AArch64/AArch64Subtarget.h --- a/llvm/lib/Target/AArch64/AArch64Subtarget.h +++ b/llvm/lib/Target/AArch64/AArch64Subtarget.h @@ -359,10 +359,9 @@ return MinSVEVectorSizeInBits; } - bool useSVEForFixedLengthVectors() const { - // Prefer NEON unless larger SVE registers are available. - return hasSVE() && getMinSVEVectorSizeInBits() >= 256; - } + bool useSVEForFixedLengthVectors() const; + + bool forceStreamingCompatibleMode() const; unsigned getVScaleForTuning() const { return VScaleForTuning; } diff --git a/llvm/lib/Target/AArch64/AArch64Subtarget.cpp b/llvm/lib/Target/AArch64/AArch64Subtarget.cpp --- a/llvm/lib/Target/AArch64/AArch64Subtarget.cpp +++ b/llvm/lib/Target/AArch64/AArch64Subtarget.cpp @@ -65,6 +65,10 @@ "Should only be used for testing register allocator."), cl::CommaSeparated, cl::Hidden); +static cl::opt + ForceStreamingCompatibleMode("force-streaming-compatible-mode", + cl::init(false), cl::Hidden); + unsigned AArch64Subtarget::getVectorInsertExtractBaseCost() const { if (OverrideVectorInsertExtractBaseCost.getNumOccurrences() > 0) return OverrideVectorInsertExtractBaseCost; @@ -431,3 +435,17 @@ } bool AArch64Subtarget::useAA() const { return UseAA; } + +bool AArch64Subtarget::useSVEForFixedLengthVectors() const { + if (ForceStreamingCompatibleMode) + return hasSVE(); + + // Prefer NEON unless larger SVE registers are available. + return hasSVE() && getMinSVEVectorSizeInBits() >= 256; +} + +bool AArch64Subtarget::forceStreamingCompatibleMode() const { + if (ForceStreamingCompatibleMode) + return hasSVE(); + return false; +} diff --git a/llvm/test/CodeGen/AArch64/sve-streaming-mode-fixed-length-loads.ll b/llvm/test/CodeGen/AArch64/sve-streaming-mode-fixed-length-loads.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/sve-streaming-mode-fixed-length-loads.ll @@ -0,0 +1,102 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -aarch64-sve-vector-bits-min=128 -force-streaming-compatible-mode < %s | FileCheck %s +; RUN: llc -aarch64-sve-vector-bits-min=256 -force-streaming-compatible-mode < %s | FileCheck %s +; RUN: llc -aarch64-sve-vector-bits-min=384 -force-streaming-compatible-mode < %s | FileCheck %s +; RUN: llc -aarch64-sve-vector-bits-min=512 -force-streaming-compatible-mode < %s | FileCheck %s +; RUN: llc -aarch64-sve-vector-bits-min=640 -force-streaming-compatible-mode < %s | FileCheck %s +; RUN: llc -aarch64-sve-vector-bits-min=768 -force-streaming-compatible-mode < %s | FileCheck %s +; RUN: llc -aarch64-sve-vector-bits-min=896 -force-streaming-compatible-mode < %s | FileCheck %s +; RUN: llc -aarch64-sve-vector-bits-min=1024 -force-streaming-compatible-mode < %s | FileCheck %s +; RUN: llc -aarch64-sve-vector-bits-min=1152 -force-streaming-compatible-mode < %s | FileCheck %s +; RUN: llc -aarch64-sve-vector-bits-min=1280 -force-streaming-compatible-mode < %s | FileCheck %s +; RUN: llc -aarch64-sve-vector-bits-min=1408 -force-streaming-compatible-mode < %s | FileCheck %s +; RUN: llc -aarch64-sve-vector-bits-min=1536 -force-streaming-compatible-mode < %s | FileCheck %s +; RUN: llc -aarch64-sve-vector-bits-min=1664 -force-streaming-compatible-mode < %s | FileCheck %s +; RUN: llc -aarch64-sve-vector-bits-min=1792 -force-streaming-compatible-mode < %s | FileCheck %s +; RUN: llc -aarch64-sve-vector-bits-min=1920 -force-streaming-compatible-mode < %s | FileCheck %s +; RUN: llc -aarch64-sve-vector-bits-min=2048 -force-streaming-compatible-mode < %s | FileCheck %s + +target triple = "aarch64-unknown-linux-gnu" + +define <4 x i8> @load_v4i8(<4 x i8>* %a) #0 { +; CHECK-LABEL: load_v4i8: +; CHECK: // %bb.0: +; CHECK-NEXT: ptrue p0.h, vl4 +; CHECK-NEXT: ld1b { z0.h }, p0/z, [x0] +; CHECK-NEXT: // kill: def $d0 killed $d0 killed $z0 +; CHECK-NEXT: ret + %load = load <4 x i8>, <4 x i8>* %a + ret <4 x i8> %load +} + +define <16 x i8> @load_v16i8(<16 x i8>* %a) #0 { +; CHECK-LABEL: load_v16i8: +; CHECK: // %bb.0: +; CHECK-NEXT: ptrue p0.b, vl16 +; CHECK-NEXT: ld1b { z0.b }, p0/z, [x0] +; CHECK-NEXT: // kill: def $q0 killed $q0 killed $z0 +; CHECK-NEXT: ret + %load = load <16 x i8>, <16 x i8>* %a + ret <16 x i8> %load +} + +define <2 x half> @load_v2f16(<2 x half>* %a) #0 { +; CHECK-LABEL: load_v2f16: +; CHECK: // %bb.0: +; CHECK-NEXT: ldr s0, [x0] +; CHECK-NEXT: ret + %load = load <2 x half>, <2 x half>* %a + ret <2 x half> %load +} + +define <8 x half> @load_v8f16(<8 x half>* %a) #0 { +; CHECK-LABEL: load_v8f16: +; CHECK: // %bb.0: +; CHECK-NEXT: ptrue p0.h, vl8 +; CHECK-NEXT: ld1h { z0.h }, p0/z, [x0] +; CHECK-NEXT: // kill: def $q0 killed $q0 killed $z0 +; CHECK-NEXT: ret + %load = load <8 x half>, <8 x half>* %a + ret <8 x half> %load +} + +define <2 x float> @load_v2f32(<2 x float>* %a) #0 { +; CHECK-LABEL: load_v2f32: +; CHECK: // %bb.0: +; CHECK-NEXT: ptrue p0.s, vl2 +; CHECK-NEXT: ld1w { z0.s }, p0/z, [x0] +; CHECK-NEXT: // kill: def $d0 killed $d0 killed $z0 +; CHECK-NEXT: ret + %load = load <2 x float>, <2 x float>* %a + ret <2 x float> %load +} + +define <4 x float> @load_v4f32(<4 x float>* %a) #0 { +; CHECK-LABEL: load_v4f32: +; CHECK: // %bb.0: +; CHECK-NEXT: ptrue p0.d, vl2 +; CHECK-NEXT: ld1d { z0.d }, p0/z, [x0] +; CHECK-NEXT: // kill: def $q0 killed $q0 killed $z0 +; CHECK-NEXT: ret + %load = load <4 x float>, <4 x float>* %a + ret <4 x float> %load +} + +define <32 x float> @load_v32f32(<32 x float>* %a) #0 { + %load = load <32 x float>, <32 x float>* %a + ret <32 x float> %load +} + +define <2 x double> @load_v2f64(<2 x double>* %a) #0 { +; CHECK-LABEL: load_v2f64: +; CHECK: // %bb.0: +; CHECK-NEXT: ptrue p0.d, vl2 +; CHECK-NEXT: ld1d { z0.d }, p0/z, [x0] +; CHECK-NEXT: // kill: def $q0 killed $q0 killed $z0 +; CHECK-NEXT: ret + %load = load <2 x double>, <2 x double>* %a + ret <2 x double> %load +} + + +attributes #0 = { "target-features"="+sve" } diff --git a/llvm/test/CodeGen/AArch64/sve-streaming-mode-fixed-length-stores.ll b/llvm/test/CodeGen/AArch64/sve-streaming-mode-fixed-length-stores.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/sve-streaming-mode-fixed-length-stores.ll @@ -0,0 +1,101 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -aarch64-sve-vector-bits-min=128 -force-streaming-compatible-mode < %s | FileCheck %s +; RUN: llc -aarch64-sve-vector-bits-min=256 -force-streaming-compatible-mode < %s | FileCheck %s +; RUN: llc -aarch64-sve-vector-bits-min=384 -force-streaming-compatible-mode < %s | FileCheck %s +; RUN: llc -aarch64-sve-vector-bits-min=512 -force-streaming-compatible-mode < %s | FileCheck %s +; RUN: llc -aarch64-sve-vector-bits-min=640 -force-streaming-compatible-mode < %s | FileCheck %s +; RUN: llc -aarch64-sve-vector-bits-min=768 -force-streaming-compatible-mode < %s | FileCheck %s +; RUN: llc -aarch64-sve-vector-bits-min=896 -force-streaming-compatible-mode < %s | FileCheck %s +; RUN: llc -aarch64-sve-vector-bits-min=1024 -force-streaming-compatible-mode < %s | FileCheck %s +; RUN: llc -aarch64-sve-vector-bits-min=1152 -force-streaming-compatible-mode < %s | FileCheck %s +; RUN: llc -aarch64-sve-vector-bits-min=1280 -force-streaming-compatible-mode < %s | FileCheck %s +; RUN: llc -aarch64-sve-vector-bits-min=1408 -force-streaming-compatible-mode < %s | FileCheck %s +; RUN: llc -aarch64-sve-vector-bits-min=1536 -force-streaming-compatible-mode < %s | FileCheck %s +; RUN: llc -aarch64-sve-vector-bits-min=1664 -force-streaming-compatible-mode < %s | FileCheck %s +; RUN: llc -aarch64-sve-vector-bits-min=1792 -force-streaming-compatible-mode < %s | FileCheck %s +; RUN: llc -aarch64-sve-vector-bits-min=1920 -force-streaming-compatible-mode < %s | FileCheck %s +; RUN: llc -aarch64-sve-vector-bits-min=2048 -force-streaming-compatible-mode < %s | FileCheck %s + +target triple = "aarch64-unknown-linux-gnu" + +define void @store_v4i8(<4 x i8>* %a) #0 { +; CHECK-LABEL: store_v4i8: +; CHECK: // %bb.0: +; CHECK-NEXT: adrp x8, .LCPI0_0 +; CHECK-NEXT: add x8, x8, :lo12:.LCPI0_0 +; CHECK-NEXT: ptrue p0.h, vl4 +; CHECK-NEXT: ld1h { z0.h }, p0/z, [x8] +; CHECK-NEXT: st1b { z0.h }, p0, [x0] +; CHECK-NEXT: ret + store <4 x i8> zeroinitializer, <4 x i8>* %a + ret void +} + +define void @store_v16i8(<16 x i8>* %a) #0 { +; CHECK-LABEL: store_v16i8: +; CHECK: // %bb.0: +; CHECK-NEXT: adrp x8, .LCPI1_0 +; CHECK-NEXT: add x8, x8, :lo12:.LCPI1_0 +; CHECK-NEXT: ptrue p0.b, vl16 +; CHECK-NEXT: ld1b { z0.b }, p0/z, [x8] +; CHECK-NEXT: str q0, [x0] +; CHECK-NEXT: ret + store <16 x i8> zeroinitializer, <16 x i8>* %a + ret void +} + +define void @store_v2f16(<2 x half>* %a) #0 { +; CHECK-LABEL: store_v2f16: +; CHECK: // %bb.0: +; CHECK-NEXT: adrp x8, .LCPI2_0 +; CHECK-NEXT: add x8, x8, :lo12:.LCPI2_0 +; CHECK-NEXT: ptrue p0.h, vl4 +; CHECK-NEXT: ld1h { z0.h }, p0/z, [x8] +; CHECK-NEXT: str s0, [x0] +; CHECK-NEXT: ret + store <2 x half> zeroinitializer, <2 x half>* %a + ret void +} + +define void @store_v8f16(<8 x half>* %a) #0 { +; CHECK-LABEL: store_v8f16: +; CHECK: // %bb.0: +; CHECK-NEXT: adrp x8, .LCPI3_0 +; CHECK-NEXT: add x8, x8, :lo12:.LCPI3_0 +; CHECK-NEXT: ptrue p0.h, vl8 +; CHECK-NEXT: ld1h { z0.h }, p0/z, [x8] +; CHECK-NEXT: str q0, [x0] +; CHECK-NEXT: ret + store <8 x half> zeroinitializer, <8 x half>* %a + ret void +} + +define void @store_v2f32(<2 x float>* %a) #0 { +; CHECK-LABEL: store_v2f32: +; CHECK: // %bb.0: +; CHECK-NEXT: str xzr, [x0] +; CHECK-NEXT: ret + store <2 x float> zeroinitializer, <2 x float>* %a + ret void +} + +define void @store_v4f32(<4 x float>* %a) #0 { +; CHECK-LABEL: store_v4f32: +; CHECK: // %bb.0: +; CHECK-NEXT: stp xzr, xzr, [x0] +; CHECK-NEXT: ret + store <4 x float> zeroinitializer, <4 x float>* %a + ret void +} + +define void @store_v2f64(<2 x double>* %a) #0 { +; CHECK-LABEL: store_v2f64: +; CHECK: // %bb.0: +; CHECK-NEXT: stp xzr, xzr, [x0] +; CHECK-NEXT: ret + store <2 x double> zeroinitializer, <2 x double>* %a + ret void +} + + +attributes #0 = { "target-features"="+sve" }