Index: include/llvm/CodeGen/GlobalISel/LegalizerHelper.h =================================================================== --- include/llvm/CodeGen/GlobalISel/LegalizerHelper.h +++ include/llvm/CodeGen/GlobalISel/LegalizerHelper.h @@ -85,6 +85,11 @@ LegalizeResult moreElementsVector(MachineInstr &MI, unsigned TypeIdx, LLT WideTy); + /// Legalize a vector instruction by splitting in to multiple scalar + /// components, each acting on the same scalar type as the original but + /// as scalar operations. + LegalizeResult scalarElementsVector(MachineInstr &MI, unsigned TypeIdx); + /// Expose MIRBuilder so clients can set their own RecordInsertInstruction /// functions MachineIRBuilder MIRBuilder; Index: include/llvm/CodeGen/GlobalISel/LegalizerInfo.h =================================================================== --- include/llvm/CodeGen/GlobalISel/LegalizerInfo.h +++ include/llvm/CodeGen/GlobalISel/LegalizerInfo.h @@ -69,6 +69,11 @@ /// this target. E.g. a SREM replaced by an SDIV and subtraction. Lower, + /// The (vector) operation should be implemented by splitting it in to + /// scalar operations. For example a <8 x s64> add will be implemented as + /// 8 separate s64 adds. + LowerScalar, + /// The operation should be implemented as a call to some kind of runtime /// support library. For example this usually happens on machines that don't /// support floating-point operations natively. @@ -362,6 +367,11 @@ return actionIf(LegalizeAction::FewerElements, Predicate, Mutation); } + /// Lower the element to scalar operations of the same element type + LegalizeRuleSet &lowerScalarFor(std::initializer_list Types) { + return actionFor(LegalizeAction::LowerScalar, Types); + } + /// The instruction is unsupported. LegalizeRuleSet &unsupported() { return actionIf(LegalizeAction::Unsupported, always); Index: lib/CodeGen/GlobalISel/LegalizerHelper.cpp =================================================================== --- lib/CodeGen/GlobalISel/LegalizerHelper.cpp +++ lib/CodeGen/GlobalISel/LegalizerHelper.cpp @@ -57,6 +57,9 @@ case FewerElements: DEBUG(dbgs() << ".. Reduce number of elements\n"); return fewerElementsVector(MI, Step.TypeIdx, Step.NewType); + case LowerScalar: + DEBUG(dbgs() << ".. Reduce vector to scalar\n"); + return scalarElementsVector(MI, Step.TypeIdx); case Custom: DEBUG(dbgs() << ".. Custom legalization\n"); return LI.legalizeCustom(MI, MRI, MIRBuilder) ? Legalized @@ -1044,3 +1047,51 @@ } } } +LegalizerHelper::LegalizeResult +LegalizerHelper::scalarElementsVector(MachineInstr &MI, unsigned TypeIdx) { + assert(TypeIdx == 0 && "Don't know how to handle secondary types yet"); + switch (MI.getOpcode()) { + default: + return UnableToLegalize; + case TargetOpcode::G_ADD: + case TargetOpcode::G_AND: + case TargetOpcode::G_MUL: + case TargetOpcode::G_OR: + case TargetOpcode::G_XOR: + case TargetOpcode::G_SUB: + case TargetOpcode::G_FADD: + case TargetOpcode::G_FSUB: + case TargetOpcode::G_FMUL: + case TargetOpcode::G_FDIV: + case TargetOpcode::G_FMA: + case TargetOpcode::G_FPOW: + case TargetOpcode::G_FREM: { + unsigned DstReg = MI.getOperand(0).getReg(); + LLT Type = MRI.getType(DstReg); + LLT ElementTy = Type.getElementType(); + unsigned ElementSize = ElementTy.getSizeInBits(); + unsigned Size = Type.getSizeInBits(); + int NumElements = Size / ElementSize; + assert(Size % ElementSize == 0 && "Don't know how to handle situation where vector isn't the same size"); + + MIRBuilder.setInstr(MI); + + SmallVector Src1Regs, Src2Regs, DstRegs; + extractParts(MI.getOperand(1).getReg(), ElementTy, NumElements, Src1Regs); + extractParts(MI.getOperand(2).getReg(), ElementTy, NumElements, Src2Regs); + + for (int i = 0; i < NumElements; ++i) { + unsigned DstReg = MRI.createGenericVirtualRegister(ElementTy); + MIRBuilder.buildInstr(MI.getOpcode()) + .addDef(DstReg) + .addUse(Src1Regs[i]) + .addUse(Src2Regs[i]); + DstRegs.push_back(DstReg); + } + + MIRBuilder.buildMerge(DstReg, DstRegs); + MI.eraseFromParent(); + return Legalized; + } + } +} Index: lib/CodeGen/GlobalISel/LegalizerInfo.cpp =================================================================== --- lib/CodeGen/GlobalISel/LegalizerInfo.cpp +++ lib/CodeGen/GlobalISel/LegalizerInfo.cpp @@ -399,6 +399,8 @@ case Libcall: case Custom: return {Size, Action}; + case LowerScalar: + return {1, LowerScalar}; case FewerElements: // FIXME: is this special case still needed and correct? // Special case for scalarization: @@ -496,6 +498,12 @@ const SizeAndActionsVec &NumElementsVec = (*i).second[TypeIdx]; auto NumElementsAndAction = findAction(NumElementsVec, IntermediateType.getNumElements()); + + // Vector op decomposed in to scalar + if (NumElementsAndAction.second == LowerScalar) { + return {NumElementsAndAction.second, + LLT::scalar(IntermediateType.getScalarSizeInBits())}; + } return {NumElementsAndAction.second, LLT::vector(NumElementsAndAction.first, IntermediateType.getScalarSizeInBits())}; Index: unittests/CodeGen/GlobalISel/LegalizerInfoTest.cpp =================================================================== --- unittests/CodeGen/GlobalISel/LegalizerInfoTest.cpp +++ unittests/CodeGen/GlobalISel/LegalizerInfoTest.cpp @@ -25,6 +25,7 @@ case WidenScalar: OS << "WidenScalar"; break; case FewerElements: OS << "FewerElements"; break; case MoreElements: OS << "MoreElements"; break; + case LowerScalar: OS << "LowerScalar"; break; case Libcall: OS << "Libcall"; break; case Custom: OS << "Custom"; break; case Unsupported: OS << "Unsupported"; break; @@ -198,4 +199,27 @@ ASSERT_EQ(L.getAction({G_UREM, {LLT::scalar(33)}}), LegalizeActionStep(Unsupported, 0, LLT::scalar(33))); } + +TEST(LegallizerInfoTest, ScalarDecomposeStrategy) { + using namespace TargetOpcode; + LegalizerInfo L; + for (unsigned Elements = 2; Elements < 16; ++Elements) { + for (unsigned Size : {8, 16, 32, 64}) { + L.setAction({G_FADD, 0, LLT::vector(Elements, Size)}, LowerScalar); + } + } + + L.computeTables(); + + // Check we infer the correct types and actually do what we're told. + for (unsigned Elements = 2; Elements < 16; ++Elements) { + for (unsigned Size : {8, 16, 32, 64}) { + + auto returnedAction = L.getAction({G_FADD, {LLT::vector(Elements, Size)}}); + auto generatedAction = LegalizeActionStep(LowerScalar, 0, LLT::scalar(Size)); + ASSERT_EQ(L.getAction({G_FADD, {LLT::vector(Elements, Size)}}), + LegalizeActionStep(LowerScalar, 0, LLT::scalar(Size))); + } + } +} }