mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-10-25 10:27:04 +00:00
[mips][msa] Fix vector insertions where the index is variable
Summary: This isn't supported directly so we rotate the vector by the desired number of elements, insert to element zero, then rotate back. The i64 case generates rather poor code on MIPS32. There is an obvious optimisation to be made in future (do both insert.w's inside a shared rotate/unrotate sequence) but for now it's sufficient to select valid code instead of aborting. Depends on D3536 Reviewers: matheusalmeida Reviewed By: matheusalmeida Differential Revision: http://reviews.llvm.org/D3537 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@207640 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -1054,6 +1054,18 @@ MipsSETargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI,
|
||||
return emitINSERT_FW(MI, BB);
|
||||
case Mips::INSERT_FD_PSEUDO:
|
||||
return emitINSERT_FD(MI, BB);
|
||||
case Mips::INSERT_B_VIDX_PSEUDO:
|
||||
return emitINSERT_DF_VIDX(MI, BB, 1, false);
|
||||
case Mips::INSERT_H_VIDX_PSEUDO:
|
||||
return emitINSERT_DF_VIDX(MI, BB, 2, false);
|
||||
case Mips::INSERT_W_VIDX_PSEUDO:
|
||||
return emitINSERT_DF_VIDX(MI, BB, 4, false);
|
||||
case Mips::INSERT_D_VIDX_PSEUDO:
|
||||
return emitINSERT_DF_VIDX(MI, BB, 8, false);
|
||||
case Mips::INSERT_FW_VIDX_PSEUDO:
|
||||
return emitINSERT_DF_VIDX(MI, BB, 4, true);
|
||||
case Mips::INSERT_FD_VIDX_PSEUDO:
|
||||
return emitINSERT_DF_VIDX(MI, BB, 8, true);
|
||||
case Mips::FILL_FW_PSEUDO:
|
||||
return emitFILL_FW(MI, BB);
|
||||
case Mips::FILL_FD_PSEUDO:
|
||||
@@ -2887,6 +2899,131 @@ MipsSETargetLowering::emitINSERT_FD(MachineInstr *MI,
|
||||
return BB;
|
||||
}
|
||||
|
||||
// Emit the INSERT_([BHWD]|F[WD])_VIDX pseudo instruction.
|
||||
//
|
||||
// For integer:
|
||||
// (INSERT_([BHWD]|F[WD])_PSEUDO $wd, $wd_in, $n, $rs)
|
||||
// =>
|
||||
// (SLL $lanetmp1, $lane, <log2size)
|
||||
// (SLD_B $wdtmp1, $wd_in, $wd_in, $lanetmp1)
|
||||
// (INSERT_[BHWD], $wdtmp2, $wdtmp1, 0, $rs)
|
||||
// (NEG $lanetmp2, $lanetmp1)
|
||||
// (SLD_B $wd, $wdtmp2, $wdtmp2, $lanetmp2)
|
||||
//
|
||||
// For floating point:
|
||||
// (INSERT_([BHWD]|F[WD])_PSEUDO $wd, $wd_in, $n, $fs)
|
||||
// =>
|
||||
// (SUBREG_TO_REG $wt, $fs, <subreg>)
|
||||
// (SLL $lanetmp1, $lane, <log2size)
|
||||
// (SLD_B $wdtmp1, $wd_in, $wd_in, $lanetmp1)
|
||||
// (INSVE_[WD], $wdtmp2, 0, $wdtmp1, 0)
|
||||
// (NEG $lanetmp2, $lanetmp1)
|
||||
// (SLD_B $wd, $wdtmp2, $wdtmp2, $lanetmp2)
|
||||
MachineBasicBlock *
|
||||
MipsSETargetLowering::emitINSERT_DF_VIDX(MachineInstr *MI,
|
||||
MachineBasicBlock *BB,
|
||||
unsigned EltSizeInBytes,
|
||||
bool IsFP) const {
|
||||
const TargetInstrInfo *TII = getTargetMachine().getInstrInfo();
|
||||
MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo();
|
||||
DebugLoc DL = MI->getDebugLoc();
|
||||
unsigned Wd = MI->getOperand(0).getReg();
|
||||
unsigned SrcVecReg = MI->getOperand(1).getReg();
|
||||
unsigned LaneReg = MI->getOperand(2).getReg();
|
||||
unsigned SrcValReg = MI->getOperand(3).getReg();
|
||||
|
||||
const TargetRegisterClass *VecRC = nullptr;
|
||||
const TargetRegisterClass *GPRRC = isGP64bit() ? &Mips::GPR64RegClass
|
||||
: &Mips::GPR32RegClass;
|
||||
unsigned EltLog2Size;
|
||||
unsigned InsertOp = 0;
|
||||
unsigned InsveOp = 0;
|
||||
switch (EltSizeInBytes) {
|
||||
default:
|
||||
llvm_unreachable("Unexpected size");
|
||||
case 1:
|
||||
EltLog2Size = 0;
|
||||
InsertOp = Mips::INSERT_B;
|
||||
InsveOp = Mips::INSVE_B;
|
||||
VecRC = &Mips::MSA128BRegClass;
|
||||
break;
|
||||
case 2:
|
||||
EltLog2Size = 1;
|
||||
InsertOp = Mips::INSERT_H;
|
||||
InsveOp = Mips::INSVE_H;
|
||||
VecRC = &Mips::MSA128HRegClass;
|
||||
break;
|
||||
case 4:
|
||||
EltLog2Size = 2;
|
||||
InsertOp = Mips::INSERT_W;
|
||||
InsveOp = Mips::INSVE_W;
|
||||
VecRC = &Mips::MSA128WRegClass;
|
||||
break;
|
||||
case 8:
|
||||
EltLog2Size = 3;
|
||||
InsertOp = Mips::INSERT_D;
|
||||
InsveOp = Mips::INSVE_D;
|
||||
VecRC = &Mips::MSA128DRegClass;
|
||||
break;
|
||||
}
|
||||
|
||||
if (IsFP) {
|
||||
unsigned Wt = RegInfo.createVirtualRegister(VecRC);
|
||||
BuildMI(*BB, MI, DL, TII->get(Mips::SUBREG_TO_REG), Wt)
|
||||
.addImm(0)
|
||||
.addReg(SrcValReg)
|
||||
.addImm(EltSizeInBytes == 8 ? Mips::sub_64 : Mips::sub_lo);
|
||||
SrcValReg = Wt;
|
||||
}
|
||||
|
||||
// Convert the lane index into a byte index
|
||||
if (EltSizeInBytes != 1) {
|
||||
unsigned LaneTmp1 = RegInfo.createVirtualRegister(GPRRC);
|
||||
BuildMI(*BB, MI, DL, TII->get(Mips::SLL), LaneTmp1)
|
||||
.addReg(LaneReg)
|
||||
.addImm(EltLog2Size);
|
||||
LaneReg = LaneTmp1;
|
||||
}
|
||||
|
||||
// Rotate bytes around so that the desired lane is element zero
|
||||
unsigned WdTmp1 = RegInfo.createVirtualRegister(VecRC);
|
||||
BuildMI(*BB, MI, DL, TII->get(Mips::SLD_B), WdTmp1)
|
||||
.addReg(SrcVecReg)
|
||||
.addReg(SrcVecReg)
|
||||
.addReg(LaneReg);
|
||||
|
||||
unsigned WdTmp2 = RegInfo.createVirtualRegister(VecRC);
|
||||
if (IsFP) {
|
||||
// Use insve.df to insert to element zero
|
||||
BuildMI(*BB, MI, DL, TII->get(InsveOp), WdTmp2)
|
||||
.addReg(WdTmp1)
|
||||
.addImm(0)
|
||||
.addReg(SrcValReg)
|
||||
.addImm(0);
|
||||
} else {
|
||||
// Use insert.df to insert to element zero
|
||||
BuildMI(*BB, MI, DL, TII->get(InsertOp), WdTmp2)
|
||||
.addReg(WdTmp1)
|
||||
.addReg(SrcValReg)
|
||||
.addImm(0);
|
||||
}
|
||||
|
||||
// Rotate elements the rest of the way for a full rotation.
|
||||
// sld.df inteprets $rt modulo the number of columns so we only need to negate
|
||||
// the lane index to do this.
|
||||
unsigned LaneTmp2 = RegInfo.createVirtualRegister(GPRRC);
|
||||
BuildMI(*BB, MI, DL, TII->get(Mips::SUB), LaneTmp2)
|
||||
.addReg(Mips::ZERO)
|
||||
.addReg(LaneReg);
|
||||
BuildMI(*BB, MI, DL, TII->get(Mips::SLD_B), Wd)
|
||||
.addReg(WdTmp2)
|
||||
.addReg(WdTmp2)
|
||||
.addReg(LaneTmp2);
|
||||
|
||||
MI->eraseFromParent(); // The pseudo instruction is gone now.
|
||||
return BB;
|
||||
}
|
||||
|
||||
// Emit the FILL_FW pseudo instruction.
|
||||
//
|
||||
// fill_fw_pseudo $wd, $fs
|
||||
|
||||
Reference in New Issue
Block a user