diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.h b/llvm/lib/Target/PowerPC/PPCISelLowering.h --- a/llvm/lib/Target/PowerPC/PPCISelLowering.h +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.h @@ -1139,6 +1139,10 @@ PPC::AddrMode SelectForceXFormMode(SDValue N, SDValue &Disp, SDValue &Base, SelectionDAG &DAG) const; + bool + splitValueIntoRegisterParts(SelectionDAG &DAG, const SDLoc &DL, SDValue Val, + SDValue *Parts, unsigned NumParts, MVT PartVT, + Optional CC) const override; /// Structure that collects some common arguments that get passed around /// between the functions for call lowering. struct CallFlags { diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp --- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp @@ -15966,8 +15966,11 @@ } break; case 'v': - if (Subtarget.hasAltivec()) + if (Subtarget.hasAltivec() && VT.isVector()) return std::make_pair(0U, &PPC::VRRCRegClass); + else if (Subtarget.hasVSX()) + // Scalars in Altivec registers only make sense with VSX. + return std::make_pair(0U, &PPC::VFRCRegClass); break; case 'y': // crrc return std::make_pair(0U, &PPC::CRRCRegClass); @@ -17664,6 +17667,24 @@ return Mode; } +bool PPCTargetLowering::splitValueIntoRegisterParts( + SelectionDAG &DAG, const SDLoc &DL, SDValue Val, SDValue *Parts, + unsigned NumParts, MVT PartVT, Optional CC) const { + EVT ValVT = Val.getValueType(); + // If we are splitting a scalar integer into f64 parts (i.e. so they + // can be placed into VFRC registers), we need to zero extend and + // bitcast the values. This will ensure the value is placed into a + // VSR using direct moves or stack operations as needed. + if (PartVT == MVT::f64 && + (ValVT == MVT::i32 || ValVT == MVT::i16 || ValVT == MVT::i8)) { + Val = DAG.getNode(ISD::ZERO_EXTEND, DL, MVT::i64, Val); + Val = DAG.getNode(ISD::BITCAST, DL, MVT::f64, Val); + Parts[0] = Val; + return true; + } + return false; +} + // If we happen to match to an aligned D-Form, check if the Frame Index is // adequately aligned. If it is not, reset the mode to match to X-Form. static void setXFormForUnalignedFI(SDValue N, unsigned Flags, diff --git a/llvm/test/CodeGen/PowerPC/scalars-in-altivec-regs.ll b/llvm/test/CodeGen/PowerPC/scalars-in-altivec-regs.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/scalars-in-altivec-regs.ll @@ -0,0 +1,249 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=powerpc64-unknown-aix-xcoff -verify-machineinstrs \ +; RUN: -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck \ +; RUN: --check-prefix=AIX64 %s +; RUN: llc -mtriple=powerpc-unknown-aix-xcoff -verify-machineinstrs \ +; RUN: -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck \ +; RUN: --check-prefix=AIX32 %s +; RUN: llc -mtriple=powerpc64le-- -verify-machineinstrs \ +; RUN: -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck --check-prefix=LE %s + +define dso_local void @test1(<2 x double>* %v, i64 %a) local_unnamed_addr #0 { +; AIX64-LABEL: test1: +; AIX64: # %bb.0: # %entry +; AIX64-NEXT: mtvsrd vs34, r4 +; AIX64-NEXT: #APP +; AIX64-NEXT: stvx v2, 0, r3 +; AIX64-NEXT: #NO_APP +; AIX64-NEXT: blr +; +; AIX32-LABEL: test1: +; AIX32: # %bb.0: # %entry +; AIX32-NEXT: stw r5, -4(r1) +; AIX32-NEXT: stw r4, -8(r1) +; AIX32-NEXT: lfd f0, -8(r1) +; AIX32-NEXT: xxlor vs34, f0, f0 +; AIX32-NEXT: #APP +; AIX32-NEXT: stvx v2, 0, r3 +; AIX32-NEXT: #NO_APP +; AIX32-NEXT: blr +; +; LE-LABEL: test1: +; LE: # %bb.0: # %entry +; LE-NEXT: mtvsrd vs34, r4 +; LE-NEXT: #APP +; LE-NEXT: stvx v2, 0, r3 +; LE-NEXT: #NO_APP +; LE-NEXT: blr +entry: + tail call void asm sideeffect "stvx $0,0,$1", "v,r,~{memory}"(i64 %a, <2 x double>* %v) + ret void +} + +define dso_local void @test2(<2 x double>* %v, i32 signext %a) local_unnamed_addr #0 { +; AIX64-LABEL: test2: +; AIX64: # %bb.0: # %entry +; AIX64-NEXT: clrldi r4, r4, 32 +; AIX64-NEXT: mtvsrd vs34, r4 +; AIX64-NEXT: #APP +; AIX64-NEXT: stvx v2, 0, r3 +; AIX64-NEXT: #NO_APP +; AIX64-NEXT: blr +; +; AIX32-LABEL: test2: +; AIX32: # %bb.0: # %entry +; AIX32-NEXT: li r5, 0 +; AIX32-NEXT: stw r4, -4(r1) +; AIX32-NEXT: stw r5, -8(r1) +; AIX32-NEXT: lfd f0, -8(r1) +; AIX32-NEXT: xxlor vs34, f0, f0 +; AIX32-NEXT: #APP +; AIX32-NEXT: stvx v2, 0, r3 +; AIX32-NEXT: #NO_APP +; AIX32-NEXT: blr +; +; LE-LABEL: test2: +; LE: # %bb.0: # %entry +; LE-NEXT: clrldi r4, r4, 32 +; LE-NEXT: mtvsrd vs34, r4 +; LE-NEXT: #APP +; LE-NEXT: stvx v2, 0, r3 +; LE-NEXT: #NO_APP +; LE-NEXT: blr +entry: + tail call void asm sideeffect "stvx $0,0,$1", "v,r,~{memory}"(i32 %a, <2 x double>* %v) + ret void +} + +define dso_local void @test3(<2 x double>* %v, i16 signext %a) local_unnamed_addr #0 { +; AIX64-LABEL: test3: +; AIX64: # %bb.0: # %entry +; AIX64-NEXT: clrldi r4, r4, 48 +; AIX64-NEXT: mtvsrd vs34, r4 +; AIX64-NEXT: #APP +; AIX64-NEXT: stvx v2, 0, r3 +; AIX64-NEXT: #NO_APP +; AIX64-NEXT: blr +; +; AIX32-LABEL: test3: +; AIX32: # %bb.0: # %entry +; AIX32-NEXT: li r5, 0 +; AIX32-NEXT: clrlwi r4, r4, 16 +; AIX32-NEXT: stw r5, -8(r1) +; AIX32-NEXT: stw r4, -4(r1) +; AIX32-NEXT: lfd f0, -8(r1) +; AIX32-NEXT: xxlor vs34, f0, f0 +; AIX32-NEXT: #APP +; AIX32-NEXT: stvx v2, 0, r3 +; AIX32-NEXT: #NO_APP +; AIX32-NEXT: blr +; +; LE-LABEL: test3: +; LE: # %bb.0: # %entry +; LE-NEXT: clrldi r4, r4, 48 +; LE-NEXT: mtvsrd vs34, r4 +; LE-NEXT: #APP +; LE-NEXT: stvx v2, 0, r3 +; LE-NEXT: #NO_APP +; LE-NEXT: blr +entry: + tail call void asm sideeffect "stvx $0,0,$1", "v,r,~{memory}"(i16 %a, <2 x double>* %v) + ret void +} + +define dso_local void @test4(<2 x double>* %v, i8 signext %a) local_unnamed_addr #0 { +; AIX64-LABEL: test4: +; AIX64: # %bb.0: # %entry +; AIX64-NEXT: clrldi r4, r4, 56 +; AIX64-NEXT: mtvsrd vs34, r4 +; AIX64-NEXT: #APP +; AIX64-NEXT: stvx v2, 0, r3 +; AIX64-NEXT: #NO_APP +; AIX64-NEXT: blr +; +; AIX32-LABEL: test4: +; AIX32: # %bb.0: # %entry +; AIX32-NEXT: li r5, 0 +; AIX32-NEXT: clrlwi r4, r4, 24 +; AIX32-NEXT: stw r5, -8(r1) +; AIX32-NEXT: stw r4, -4(r1) +; AIX32-NEXT: lfd f0, -8(r1) +; AIX32-NEXT: xxlor vs34, f0, f0 +; AIX32-NEXT: #APP +; AIX32-NEXT: stvx v2, 0, r3 +; AIX32-NEXT: #NO_APP +; AIX32-NEXT: blr +; +; LE-LABEL: test4: +; LE: # %bb.0: # %entry +; LE-NEXT: clrldi r4, r4, 56 +; LE-NEXT: mtvsrd vs34, r4 +; LE-NEXT: #APP +; LE-NEXT: stvx v2, 0, r3 +; LE-NEXT: #NO_APP +; LE-NEXT: blr +entry: + tail call void asm sideeffect "stvx $0,0,$1", "v,r,~{memory}"(i8 %a, <2 x double>* %v) + ret void +} + +define dso_local void @test6(<2 x double>* %v, i32 zeroext %a) local_unnamed_addr #0 { +; AIX64-LABEL: test6: +; AIX64: # %bb.0: # %entry +; AIX64-NEXT: mtvsrd vs34, r4 +; AIX64-NEXT: #APP +; AIX64-NEXT: stvx v2, 0, r3 +; AIX64-NEXT: #NO_APP +; AIX64-NEXT: blr +; +; AIX32-LABEL: test6: +; AIX32: # %bb.0: # %entry +; AIX32-NEXT: li r5, 0 +; AIX32-NEXT: stw r4, -4(r1) +; AIX32-NEXT: stw r5, -8(r1) +; AIX32-NEXT: lfd f0, -8(r1) +; AIX32-NEXT: xxlor vs34, f0, f0 +; AIX32-NEXT: #APP +; AIX32-NEXT: stvx v2, 0, r3 +; AIX32-NEXT: #NO_APP +; AIX32-NEXT: blr +; +; LE-LABEL: test6: +; LE: # %bb.0: # %entry +; LE-NEXT: mtvsrd vs34, r4 +; LE-NEXT: #APP +; LE-NEXT: stvx v2, 0, r3 +; LE-NEXT: #NO_APP +; LE-NEXT: blr +entry: + tail call void asm sideeffect "stvx $0,0,$1", "v,r,~{memory}"(i32 %a, <2 x double>* %v) + ret void +} + +define dso_local void @test7(<2 x double>* %v, i16 zeroext %a) local_unnamed_addr #0 { +; AIX64-LABEL: test7: +; AIX64: # %bb.0: # %entry +; AIX64-NEXT: mtvsrd vs34, r4 +; AIX64-NEXT: #APP +; AIX64-NEXT: stvx v2, 0, r3 +; AIX64-NEXT: #NO_APP +; AIX64-NEXT: blr +; +; AIX32-LABEL: test7: +; AIX32: # %bb.0: # %entry +; AIX32-NEXT: li r5, 0 +; AIX32-NEXT: stw r4, -4(r1) +; AIX32-NEXT: stw r5, -8(r1) +; AIX32-NEXT: lfd f0, -8(r1) +; AIX32-NEXT: xxlor vs34, f0, f0 +; AIX32-NEXT: #APP +; AIX32-NEXT: stvx v2, 0, r3 +; AIX32-NEXT: #NO_APP +; AIX32-NEXT: blr +; +; LE-LABEL: test7: +; LE: # %bb.0: # %entry +; LE-NEXT: mtvsrd vs34, r4 +; LE-NEXT: #APP +; LE-NEXT: stvx v2, 0, r3 +; LE-NEXT: #NO_APP +; LE-NEXT: blr +entry: + tail call void asm sideeffect "stvx $0,0,$1", "v,r,~{memory}"(i16 %a, <2 x double>* %v) + ret void +} + +define dso_local void @test8(<2 x double>* %v, i8 zeroext %a) local_unnamed_addr #0 { +; AIX64-LABEL: test8: +; AIX64: # %bb.0: # %entry +; AIX64-NEXT: mtvsrd vs34, r4 +; AIX64-NEXT: #APP +; AIX64-NEXT: stvx v2, 0, r3 +; AIX64-NEXT: #NO_APP +; AIX64-NEXT: blr +; +; AIX32-LABEL: test8: +; AIX32: # %bb.0: # %entry +; AIX32-NEXT: li r5, 0 +; AIX32-NEXT: stw r4, -4(r1) +; AIX32-NEXT: stw r5, -8(r1) +; AIX32-NEXT: lfd f0, -8(r1) +; AIX32-NEXT: xxlor vs34, f0, f0 +; AIX32-NEXT: #APP +; AIX32-NEXT: stvx v2, 0, r3 +; AIX32-NEXT: #NO_APP +; AIX32-NEXT: blr +; +; LE-LABEL: test8: +; LE: # %bb.0: # %entry +; LE-NEXT: mtvsrd vs34, r4 +; LE-NEXT: #APP +; LE-NEXT: stvx v2, 0, r3 +; LE-NEXT: #NO_APP +; LE-NEXT: blr +entry: + tail call void asm sideeffect "stvx $0,0,$1", "v,r,~{memory}"(i8 %a, <2 x double>* %v) + ret void +} + +attributes #0 = { nounwind }