Index: include/llvm/CodeGen/GlobalISel/IRTranslator.h =================================================================== --- include/llvm/CodeGen/GlobalISel/IRTranslator.h +++ include/llvm/CodeGen/GlobalISel/IRTranslator.h @@ -302,6 +302,10 @@ bool translateVAArg(const User &U, MachineIRBuilder &MIRBuilder); + bool translateInsertElement(const User &U, MachineIRBuilder &MIRBuilder); + + bool translateExtractElement(const User &U, MachineIRBuilder &MIRBuilder); + // Stubs to keep the compiler happy while we implement the rest of the // translation. bool translateResume(const User &U, MachineIRBuilder &MIRBuilder) { @@ -340,12 +344,6 @@ bool translateUserOp2(const User &U, MachineIRBuilder &MIRBuilder) { return false; } - bool translateExtractElement(const User &U, MachineIRBuilder &MIRBuilder) { - return false; - } - bool translateInsertElement(const User &U, MachineIRBuilder &MIRBuilder) { - return false; - } bool translateShuffleVector(const User &U, MachineIRBuilder &MIRBuilder) { return false; } Index: include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h =================================================================== --- include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h +++ include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h @@ -594,6 +594,30 @@ /// \return a MachineInstrBuilder for the newly created instruction. MachineInstrBuilder buildSelect(unsigned Res, unsigned Tst, unsigned Op0, unsigned Op1); + + /// Build and insert \p Res = G_INSERT_VECTOR_ELT \p Val, + /// \p Elt, \p Idx + /// + /// \pre setBasicBlock or setMI must have been called. + /// \pre \p Res and \p Val must be a generic virtual register + // with the same vector type. + /// \pre \p Elt and \p Idx must be a generic virtual register + /// with scalar type. + /// + /// \return The newly created instruction. + MachineInstrBuilder buildInsertVectorElement(unsigned Res, unsigned Val, + unsigned Elt, unsigned Idx); + + /// Build and insert \p Res = G_EXTRACT_VECTOR_ELT \p Val, \p Idx + /// + /// \pre setBasicBlock or setMI must have been called. + /// \pre \p Res must be a generic virtual register with scalar type. + /// \pre \p Val must be a generic virtual register with vector type. + /// \pre \p Idx must be a generic virtual register with scalar type. + /// + /// \return The newly created instruction. + MachineInstrBuilder buildExtractVectorElement(unsigned Res, unsigned Val, + unsigned Idx); }; } // End namespace llvm. Index: include/llvm/Target/GenericOpcodes.td =================================================================== --- include/llvm/Target/GenericOpcodes.td +++ include/llvm/Target/GenericOpcodes.td @@ -519,4 +519,22 @@ let isTerminator = 1; } +//------------------------------------------------------------------------------ +// Vector ops +//------------------------------------------------------------------------------ + +// Generic insertelement. +def G_INSERT_VECTOR_ELT : Instruction { + let OutOperandList = (outs type0:$dst); + let InOperandList = (ins type0:$src, type1:$elt, type2:$idx); + let hasSideEffects = 0; +} + +// Generic extractelement. +def G_EXTRACT_VECTOR_ELT : Instruction { + let OutOperandList = (outs type0:$dst); + let InOperandList = (ins type1:$src, type2:$idx); + let hasSideEffects = 0; +} + // TODO: Add the other generic opcodes. Index: include/llvm/Target/TargetOpcodes.def =================================================================== --- include/llvm/Target/TargetOpcodes.def +++ include/llvm/Target/TargetOpcodes.def @@ -395,6 +395,12 @@ /// Generic BRANCH instruction. This is an unconditional branch. HANDLE_TARGET_OPCODE(G_BR) +/// Generic insertelement. +HANDLE_TARGET_OPCODE(G_INSERT_VECTOR_ELT) + +/// Generic extractelement. +HANDLE_TARGET_OPCODE(G_EXTRACT_VECTOR_ELT) + // TODO: Add more generic opcodes as we move along. /// Marker for the end of the generic opcode. Index: lib/CodeGen/GlobalISel/IRTranslator.cpp =================================================================== --- lib/CodeGen/GlobalISel/IRTranslator.cpp +++ lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -955,6 +955,36 @@ return true; } +bool IRTranslator::translateInsertElement(const User &U, + MachineIRBuilder &MIRBuilder) { + // If it is a <1 x Ty> vector, use the scalar as it is + // not a legal vector type in LLT. + if (U.getType()->getVectorNumElements() == 1) { + unsigned Elt = getOrCreateVReg(*U.getOperand(1)); + ValToVReg[&U] = Elt; + return true; + } + MIRBuilder.buildInsertVectorElement( + getOrCreateVReg(U), getOrCreateVReg(*U.getOperand(0)), + getOrCreateVReg(*U.getOperand(1)), getOrCreateVReg(*U.getOperand(2))); + return true; +} + +bool IRTranslator::translateExtractElement(const User &U, + MachineIRBuilder &MIRBuilder) { + // If it is a <1 x Ty> vector, use the scalar as it is + // not a legal vector type in LLT. + if (U.getOperand(0)->getType()->getVectorNumElements() == 1) { + unsigned Elt = getOrCreateVReg(*U.getOperand(0)); + ValToVReg[&U] = Elt; + return true; + } + MIRBuilder.buildExtractVectorElement(getOrCreateVReg(U), + getOrCreateVReg(*U.getOperand(0)), + getOrCreateVReg(*U.getOperand(1))); + return true; +} + bool IRTranslator::translatePHI(const User &U, MachineIRBuilder &MIRBuilder) { const PHINode &PI = cast(U); auto MIB = MIRBuilder.buildInstr(TargetOpcode::PHI); Index: lib/CodeGen/GlobalISel/MachineIRBuilder.cpp =================================================================== --- lib/CodeGen/GlobalISel/MachineIRBuilder.cpp +++ lib/CodeGen/GlobalISel/MachineIRBuilder.cpp @@ -582,6 +582,46 @@ .addUse(Op1); } +MachineInstrBuilder MachineIRBuilder::buildInsertVectorElement(unsigned Res, + unsigned Val, + unsigned Elt, + unsigned Idx) { +#ifndef NDEBUG + LLT ResTy = MRI->getType(Res); + LLT ValTy = MRI->getType(Val); + LLT EltTy = MRI->getType(Elt); + LLT IdxTy = MRI->getType(Idx); + assert(ResTy.isVector() && ValTy.isVector() && "invalid operand type"); + assert(EltTy.isScalar() && IdxTy.isScalar() && "invalid operand type"); + assert(ResTy.getNumElements() == ValTy.getNumElements() && "type mismatch"); + assert(ResTy.getElementType() == EltTy && "type mismatch"); +#endif + + return buildInstr(TargetOpcode::G_INSERT_VECTOR_ELT) + .addDef(Res) + .addUse(Val) + .addUse(Elt) + .addUse(Idx); +} + +MachineInstrBuilder MachineIRBuilder::buildExtractVectorElement(unsigned Res, + unsigned Val, + unsigned Idx) { +#ifndef NDEBUG + LLT ResTy = MRI->getType(Res); + LLT ValTy = MRI->getType(Val); + LLT IdxTy = MRI->getType(Idx); + assert(ValTy.isVector() && "invalid operand type"); + assert(ResTy.isScalar() && IdxTy.isScalar() && "invalid operand type"); + assert(ValTy.getElementType() == ResTy && "type mismatch"); +#endif + + return buildInstr(TargetOpcode::G_EXTRACT_VECTOR_ELT) + .addDef(Res) + .addUse(Val) + .addUse(Idx); +} + void MachineIRBuilder::validateTruncExt(unsigned Dst, unsigned Src, bool IsExtend) { #ifndef NDEBUG Index: test/CodeGen/AArch64/GlobalISel/arm64-irtranslator.ll =================================================================== --- test/CodeGen/AArch64/GlobalISel/arm64-irtranslator.ll +++ test/CodeGen/AArch64/GlobalISel/arm64-irtranslator.ll @@ -1262,3 +1262,35 @@ %neg = fsub double -0.000000e+00, %x ret double %neg } + +define <2 x i32> @test_insertelement(<2 x i32> %vec, i32 %elt, i32 %idx){ +; CHECK-LABEL: name: test_insertelement +; CHECK: [[VEC:%[0-9]+]](<2 x s32>) = COPY %d0 +; CHECK: [[ELT:%[0-9]+]](s32) = COPY %w0 +; CHECK: [[IDX:%[0-9]+]](s32) = COPY %w1 +; CHECK: [[RES:%[0-9]+]](<2 x s32>) = G_INSERT_VECTOR_ELT [[VEC]], [[ELT]](s32), [[IDX]](s32) +; CHECK: %d0 = COPY [[RES]](<2 x s32>) + %res = insertelement <2 x i32> %vec, i32 %elt, i32 %idx + ret <2 x i32> %res +} + +define i32 @test_extractelement(<2 x i32> %vec, i32 %idx) { +; CHECK-LABEL: name: test_extractelement +; CHECK: [[VEC:%[0-9]+]](<2 x s32>) = COPY %d0 +; CHECK: [[IDX:%[0-9]+]](s32) = COPY %w0 +; CHECK: [[RES:%[0-9]+]](s32) = G_EXTRACT_VECTOR_ELT [[VEC]](<2 x s32>), [[IDX]](s32) +; CHECK: %w0 = COPY [[RES]](s32) + %res = extractelement <2 x i32> %vec, i32 %idx + ret i32 %res +} + +define i32 @test_singleelementvector(i32 %elt){ +; CHECK-LABEL: name: test_singleelementvector +; CHECK: [[ELT:%[0-9]+]](s32) = COPY %w0 +; CHECK-NOT: G_INSERT_VECTOR_ELT +; CHECK-NOT: G_EXTRACT_VECTOR_ELT +; CHECK: %w0 = COPY [[ELT]](s32) + %vec = insertelement <1 x i32> undef, i32 %elt, i32 0 + %res = extractelement <1 x i32> %vec, i32 0 + ret i32 %res +}