[GlobalISel] Translate insertelement and extractelement

Reviewers: qcolombet, aditya_nandakumar, dsanders, ab, t.p.northover, javed.absar

Reviewed By: qcolombet

Subscribers: dberris, rovka, llvm-commits, kristof.beyls

Differential Revision: https://reviews.llvm.org/D30761

llvm-svn: 297495
This commit is contained in:
Volkan Keles 2017-03-10 19:08:28 +00:00
parent 5c338ff7a3
commit 04cb08cc83
7 changed files with 154 additions and 6 deletions

View File

@ -304,6 +304,10 @@ private:
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) {
@ -342,12 +346,6 @@ private:
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;
}

View File

@ -594,6 +594,30 @@ public:
/// \return a MachineInstrBuilder for the newly created instruction.
MachineInstrBuilder buildSelect(unsigned Res, unsigned Tst,
unsigned Op0, unsigned Op1);
/// Build and insert \p Res<def> = 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<def> = 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.

View File

@ -519,4 +519,22 @@ def G_BRINDIRECT : Instruction {
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.

View File

@ -395,6 +395,12 @@ HANDLE_TARGET_OPCODE(G_PTR_MASK)
/// 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.

View File

@ -976,6 +976,36 @@ bool IRTranslator::translateVAArg(const User &U, MachineIRBuilder &MIRBuilder) {
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<PHINode>(U);
auto MIB = MIRBuilder.buildInstr(TargetOpcode::PHI);

View File

@ -582,6 +582,46 @@ MachineInstrBuilder MachineIRBuilder::buildSelect(unsigned Res, unsigned Tst,
.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

View File

@ -1271,3 +1271,35 @@ define void @test_trivial_inlineasm() {
call void asm "wibble", ""()
ret void
}
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
}