Add initial support to lower ISD::SELECT into branch instructions in divergent execution path.
This commit is contained in:
parent
b9da010dd5
commit
cb6f30fbd7
|
@ -4771,6 +4771,7 @@ static bool isSelectPseudo(MachineInstr &MI) {
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
case RISCV::Select_GPR_Using_CC_GPR:
|
case RISCV::Select_GPR_Using_CC_GPR:
|
||||||
|
case RISCV::Select_VGPR_Using_CC_VGPR:
|
||||||
case RISCV::Select_FPR16_Using_CC_GPR:
|
case RISCV::Select_FPR16_Using_CC_GPR:
|
||||||
case RISCV::Select_FPR32_Using_CC_GPR:
|
case RISCV::Select_FPR32_Using_CC_GPR:
|
||||||
case RISCV::Select_FPR64_Using_CC_GPR:
|
case RISCV::Select_FPR64_Using_CC_GPR:
|
||||||
|
@ -5050,6 +5051,120 @@ static MachineBasicBlock *emitSelectPseudo(MachineInstr &MI,
|
||||||
return TailMBB;
|
return TailMBB;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static MachineBasicBlock *emitVSelectPseudo(MachineInstr &MI,
|
||||||
|
MachineBasicBlock *BB,
|
||||||
|
const RISCVSubtarget &Subtarget) {
|
||||||
|
// vALU version of emitSelectPseudo, explicit join instruction should be
|
||||||
|
// generated for each branch.
|
||||||
|
//
|
||||||
|
// We produce the following control flow:
|
||||||
|
// HeadMBB
|
||||||
|
// / \
|
||||||
|
// TrueMBB FalseMBB
|
||||||
|
// \ /
|
||||||
|
// JoinMBB
|
||||||
|
Register LHS = MI.getOperand(1).getReg();
|
||||||
|
Register RHS = MI.getOperand(2).getReg();
|
||||||
|
auto CC = static_cast<RISCVCC::CondCode>(MI.getOperand(3).getImm());
|
||||||
|
|
||||||
|
SmallVector<MachineInstr *, 4> SelectDebugValues;
|
||||||
|
SmallSet<Register, 4> SelectDests;
|
||||||
|
SelectDests.insert(MI.getOperand(0).getReg());
|
||||||
|
|
||||||
|
MachineInstr *LastSelectPseudo = &MI;
|
||||||
|
|
||||||
|
for (auto E = BB->end(), SequenceMBBI = MachineBasicBlock::iterator(MI);
|
||||||
|
SequenceMBBI != E; ++SequenceMBBI) {
|
||||||
|
if (SequenceMBBI->isDebugInstr())
|
||||||
|
continue;
|
||||||
|
if (isSelectPseudo(*SequenceMBBI)) {
|
||||||
|
if (SequenceMBBI->getOperand(1).getReg() != LHS ||
|
||||||
|
SequenceMBBI->getOperand(2).getReg() != RHS ||
|
||||||
|
SequenceMBBI->getOperand(3).getImm() != CC ||
|
||||||
|
SelectDests.count(SequenceMBBI->getOperand(4).getReg()) ||
|
||||||
|
SelectDests.count(SequenceMBBI->getOperand(5).getReg()))
|
||||||
|
break;
|
||||||
|
LastSelectPseudo = &*SequenceMBBI;
|
||||||
|
SequenceMBBI->collectDebugValues(SelectDebugValues);
|
||||||
|
SelectDests.insert(SequenceMBBI->getOperand(0).getReg());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (SequenceMBBI->hasUnmodeledSideEffects() ||
|
||||||
|
SequenceMBBI->mayLoadOrStore())
|
||||||
|
break;
|
||||||
|
if (llvm::any_of(SequenceMBBI->operands(), [&](MachineOperand &MO) {
|
||||||
|
return MO.isReg() && MO.isUse() && SelectDests.count(MO.getReg());
|
||||||
|
}))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const RISCVInstrInfo &TII = *Subtarget.getInstrInfo();
|
||||||
|
const BasicBlock *LLVM_BB = BB->getBasicBlock();
|
||||||
|
DebugLoc DL = MI.getDebugLoc();
|
||||||
|
MachineFunction::iterator I = ++BB->getIterator();
|
||||||
|
|
||||||
|
MachineBasicBlock *HeadMBB = BB;
|
||||||
|
MachineFunction *F = BB->getParent();
|
||||||
|
MachineBasicBlock *JoinMBB = F->CreateMachineBasicBlock(LLVM_BB);
|
||||||
|
MachineBasicBlock *IfTrueMBB = F->CreateMachineBasicBlock(LLVM_BB);
|
||||||
|
MachineBasicBlock *IfFalseMBB = F->CreateMachineBasicBlock(LLVM_BB);
|
||||||
|
|
||||||
|
F->insert(I, IfTrueMBB);
|
||||||
|
F->insert(I, IfFalseMBB);
|
||||||
|
F->insert(I, JoinMBB);
|
||||||
|
|
||||||
|
// Transfer debug instructions associated with the selects to JoinMBB.
|
||||||
|
for (MachineInstr *DebugInstr : SelectDebugValues) {
|
||||||
|
JoinMBB->push_back(DebugInstr->removeFromParent());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move all instructions after the sequence to JoinMBB.
|
||||||
|
JoinMBB->splice(JoinMBB->end(), HeadMBB,
|
||||||
|
std::next(LastSelectPseudo->getIterator()), HeadMBB->end());
|
||||||
|
// Update machine-CFG edges by transferring all successors of the current
|
||||||
|
// block to the new block which will contain the Phi nodes for the selects.
|
||||||
|
JoinMBB->transferSuccessorsAndUpdatePHIs(HeadMBB);
|
||||||
|
// Set the successors for HeadMBB.
|
||||||
|
HeadMBB->addSuccessor(IfTrueMBB);
|
||||||
|
HeadMBB->addSuccessor(IfFalseMBB);
|
||||||
|
|
||||||
|
// Insert appropriate branch.
|
||||||
|
BuildMI(HeadMBB, DL, TII.getVBrCond(CC))
|
||||||
|
.addReg(LHS)
|
||||||
|
.addReg(RHS)
|
||||||
|
.addMBB(IfTrueMBB);
|
||||||
|
|
||||||
|
// Insert appropriate join
|
||||||
|
BuildMI(IfTrueMBB, DL, TII.get(RISCV::JOIN)).addMBB(JoinMBB);
|
||||||
|
BuildMI(IfFalseMBB, DL, TII.get(RISCV::JOIN)).addMBB(JoinMBB);
|
||||||
|
|
||||||
|
IfTrueMBB->addSuccessor(JoinMBB);
|
||||||
|
IfFalseMBB->addSuccessor(JoinMBB);
|
||||||
|
|
||||||
|
// Create PHIs for all of the select pseudo-instructions.
|
||||||
|
auto SelectMBBI = MI.getIterator();
|
||||||
|
auto SelectEnd = std::next(LastSelectPseudo->getIterator());
|
||||||
|
auto InsertionPoint = JoinMBB->begin();
|
||||||
|
while (SelectMBBI != SelectEnd) {
|
||||||
|
auto Next = std::next(SelectMBBI);
|
||||||
|
if (isSelectPseudo(*SelectMBBI)) {
|
||||||
|
// %Result = phi [ %TrueValue, IfTrueMBB ], [ %FalseValue, IfFalseMBB ]
|
||||||
|
BuildMI(*JoinMBB, InsertionPoint, SelectMBBI->getDebugLoc(),
|
||||||
|
TII.get(RISCV::PHI), SelectMBBI->getOperand(0).getReg())
|
||||||
|
.addReg(SelectMBBI->getOperand(4).getReg())
|
||||||
|
.addMBB(IfTrueMBB)
|
||||||
|
.addReg(SelectMBBI->getOperand(5).getReg())
|
||||||
|
.addMBB(IfFalseMBB);
|
||||||
|
SelectMBBI->eraseFromParent();
|
||||||
|
}
|
||||||
|
SelectMBBI = Next;
|
||||||
|
}
|
||||||
|
|
||||||
|
F->getProperties().reset(MachineFunctionProperties::Property::NoPHIs);
|
||||||
|
return JoinMBB;
|
||||||
|
}
|
||||||
|
|
||||||
static MachineBasicBlock *emitFROUND(MachineInstr &MI, MachineBasicBlock *MBB,
|
static MachineBasicBlock *emitFROUND(MachineInstr &MI, MachineBasicBlock *MBB,
|
||||||
const RISCVSubtarget &Subtarget) {
|
const RISCVSubtarget &Subtarget) {
|
||||||
unsigned CmpOpc, F2IOpc, I2FOpc, FSGNJOpc, FSGNJXOpc;
|
unsigned CmpOpc, F2IOpc, I2FOpc, FSGNJOpc, FSGNJXOpc;
|
||||||
|
@ -5172,6 +5287,8 @@ RISCVTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
|
||||||
case RISCV::Select_FPR32_Using_CC_GPR:
|
case RISCV::Select_FPR32_Using_CC_GPR:
|
||||||
case RISCV::Select_FPR64_Using_CC_GPR:
|
case RISCV::Select_FPR64_Using_CC_GPR:
|
||||||
return emitSelectPseudo(MI, BB, Subtarget);
|
return emitSelectPseudo(MI, BB, Subtarget);
|
||||||
|
case RISCV::Select_VGPR_Using_CC_VGPR:
|
||||||
|
return emitVSelectPseudo(MI, BB, Subtarget);
|
||||||
case RISCV::BuildPairF64Pseudo:
|
case RISCV::BuildPairF64Pseudo:
|
||||||
return emitBuildPairF64Pseudo(MI, BB);
|
return emitBuildPairF64Pseudo(MI, BB);
|
||||||
case RISCV::SplitF64Pseudo:
|
case RISCV::SplitF64Pseudo:
|
||||||
|
|
|
@ -385,20 +385,41 @@ static RISCVCC::CondCode getCondFromBranchOpc(unsigned Opc) {
|
||||||
default:
|
default:
|
||||||
return RISCVCC::COND_INVALID;
|
return RISCVCC::COND_INVALID;
|
||||||
case RISCV::BEQ:
|
case RISCV::BEQ:
|
||||||
|
case RISCV::VBEQ:
|
||||||
return RISCVCC::COND_EQ;
|
return RISCVCC::COND_EQ;
|
||||||
case RISCV::BNE:
|
case RISCV::BNE:
|
||||||
|
case RISCV::VBNE:
|
||||||
return RISCVCC::COND_NE;
|
return RISCVCC::COND_NE;
|
||||||
case RISCV::BLT:
|
case RISCV::BLT:
|
||||||
|
case RISCV::VBLT:
|
||||||
return RISCVCC::COND_LT;
|
return RISCVCC::COND_LT;
|
||||||
case RISCV::BGE:
|
case RISCV::BGE:
|
||||||
|
case RISCV::VBGE:
|
||||||
return RISCVCC::COND_GE;
|
return RISCVCC::COND_GE;
|
||||||
case RISCV::BLTU:
|
case RISCV::BLTU:
|
||||||
|
case RISCV::VBLTU:
|
||||||
return RISCVCC::COND_LTU;
|
return RISCVCC::COND_LTU;
|
||||||
case RISCV::BGEU:
|
case RISCV::BGEU:
|
||||||
|
case RISCV::VBGEU:
|
||||||
return RISCVCC::COND_GEU;
|
return RISCVCC::COND_GEU;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool isDivergentBranch(MachineInstr &I) {
|
||||||
|
switch (I.getOpcode()) {
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
case RISCV::VBEQ:
|
||||||
|
case RISCV::VBNE:
|
||||||
|
case RISCV::VBLT:
|
||||||
|
case RISCV::VBGE:
|
||||||
|
case RISCV::VBLTU:
|
||||||
|
case RISCV::VBGEU:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// The contents of values added to Cond are not examined outside of
|
// The contents of values added to Cond are not examined outside of
|
||||||
// RISCVInstrInfo, giving us flexibility in what to push to it. For RISCV, we
|
// RISCVInstrInfo, giving us flexibility in what to push to it. For RISCV, we
|
||||||
// push BranchOpcode, Reg1, Reg2.
|
// push BranchOpcode, Reg1, Reg2.
|
||||||
|
@ -433,6 +454,25 @@ const MCInstrDesc &RISCVInstrInfo::getBrCond(RISCVCC::CondCode CC) const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MCInstrDesc &RISCVInstrInfo::getVBrCond(RISCVCC::CondCode CC) const {
|
||||||
|
switch (CC) {
|
||||||
|
default:
|
||||||
|
llvm_unreachable("Unknown condition code!");
|
||||||
|
case RISCVCC::COND_EQ:
|
||||||
|
return get(RISCV::VBEQ);
|
||||||
|
case RISCVCC::COND_NE:
|
||||||
|
return get(RISCV::VBNE);
|
||||||
|
case RISCVCC::COND_LT:
|
||||||
|
return get(RISCV::VBLT);
|
||||||
|
case RISCVCC::COND_GE:
|
||||||
|
return get(RISCV::VBGE);
|
||||||
|
case RISCVCC::COND_LTU:
|
||||||
|
return get(RISCV::VBLTU);
|
||||||
|
case RISCVCC::COND_GEU:
|
||||||
|
return get(RISCV::VBGEU);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RISCVCC::CondCode RISCVCC::getOppositeBranchCondition(RISCVCC::CondCode CC) {
|
RISCVCC::CondCode RISCVCC::getOppositeBranchCondition(RISCVCC::CondCode CC) {
|
||||||
switch (CC) {
|
switch (CC) {
|
||||||
default:
|
default:
|
||||||
|
@ -535,6 +575,7 @@ unsigned RISCVInstrInfo::removeBranch(MachineBasicBlock &MBB,
|
||||||
// Remove the branch.
|
// Remove the branch.
|
||||||
if (BytesRemoved)
|
if (BytesRemoved)
|
||||||
*BytesRemoved += getInstSizeInBytes(*I);
|
*BytesRemoved += getInstSizeInBytes(*I);
|
||||||
|
IsDivergentBranch = isDivergentBranch(*I);
|
||||||
I->eraseFromParent();
|
I->eraseFromParent();
|
||||||
|
|
||||||
I = MBB.end();
|
I = MBB.end();
|
||||||
|
@ -548,6 +589,7 @@ unsigned RISCVInstrInfo::removeBranch(MachineBasicBlock &MBB,
|
||||||
// Remove the branch.
|
// Remove the branch.
|
||||||
if (BytesRemoved)
|
if (BytesRemoved)
|
||||||
*BytesRemoved += getInstSizeInBytes(*I);
|
*BytesRemoved += getInstSizeInBytes(*I);
|
||||||
|
IsDivergentBranch = isDivergentBranch(*I);
|
||||||
I->eraseFromParent();
|
I->eraseFromParent();
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
@ -565,9 +607,11 @@ unsigned RISCVInstrInfo::insertBranch(
|
||||||
assert((Cond.size() == 3 || Cond.size() == 0) &&
|
assert((Cond.size() == 3 || Cond.size() == 0) &&
|
||||||
"RISCV branch conditions have two components!");
|
"RISCV branch conditions have two components!");
|
||||||
|
|
||||||
|
unsigned UncondBr = IsDivergentBranch ? RISCV::JOIN : RISCV::PseudoBR;
|
||||||
|
|
||||||
// Unconditional branch.
|
// Unconditional branch.
|
||||||
if (Cond.empty()) {
|
if (Cond.empty()) {
|
||||||
MachineInstr &MI = *BuildMI(&MBB, DL, get(RISCV::PseudoBR)).addMBB(TBB);
|
MachineInstr &MI = *BuildMI(&MBB, DL, get(UncondBr)).addMBB(TBB);
|
||||||
if (BytesAdded)
|
if (BytesAdded)
|
||||||
*BytesAdded += getInstSizeInBytes(MI);
|
*BytesAdded += getInstSizeInBytes(MI);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -575,8 +619,9 @@ unsigned RISCVInstrInfo::insertBranch(
|
||||||
|
|
||||||
// Either a one or two-way conditional branch.
|
// Either a one or two-way conditional branch.
|
||||||
auto CC = static_cast<RISCVCC::CondCode>(Cond[0].getImm());
|
auto CC = static_cast<RISCVCC::CondCode>(Cond[0].getImm());
|
||||||
|
const MCInstrDesc& CondBr = IsDivergentBranch ? getVBrCond(CC) : getBrCond(CC);
|
||||||
MachineInstr &CondMI =
|
MachineInstr &CondMI =
|
||||||
*BuildMI(&MBB, DL, getBrCond(CC)).add(Cond[1]).add(Cond[2]).addMBB(TBB);
|
*BuildMI(&MBB, DL, CondBr).add(Cond[1]).add(Cond[2]).addMBB(TBB);
|
||||||
if (BytesAdded)
|
if (BytesAdded)
|
||||||
*BytesAdded += getInstSizeInBytes(CondMI);
|
*BytesAdded += getInstSizeInBytes(CondMI);
|
||||||
|
|
||||||
|
@ -585,7 +630,7 @@ unsigned RISCVInstrInfo::insertBranch(
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
// Two-way conditional branch.
|
// Two-way conditional branch.
|
||||||
MachineInstr &MI = *BuildMI(&MBB, DL, get(RISCV::PseudoBR)).addMBB(FBB);
|
MachineInstr &MI = *BuildMI(&MBB, DL, get(UncondBr)).addMBB(FBB);
|
||||||
if (BytesAdded)
|
if (BytesAdded)
|
||||||
*BytesAdded += getInstSizeInBytes(MI);
|
*BytesAdded += getInstSizeInBytes(MI);
|
||||||
return 2;
|
return 2;
|
||||||
|
@ -596,6 +641,7 @@ void RISCVInstrInfo::insertIndirectBranch(MachineBasicBlock &MBB,
|
||||||
MachineBasicBlock &RestoreBB,
|
MachineBasicBlock &RestoreBB,
|
||||||
const DebugLoc &DL, int64_t BrOffset,
|
const DebugLoc &DL, int64_t BrOffset,
|
||||||
RegScavenger *RS) const {
|
RegScavenger *RS) const {
|
||||||
|
assert(0 && "Add vALU support!");
|
||||||
assert(RS && "RegScavenger required for long branching");
|
assert(RS && "RegScavenger required for long branching");
|
||||||
assert(MBB.empty() &&
|
assert(MBB.empty() &&
|
||||||
"new block should be inserted for expanding unconditional branch");
|
"new block should be inserted for expanding unconditional branch");
|
||||||
|
@ -682,11 +728,18 @@ bool RISCVInstrInfo::isBranchOffsetInRange(unsigned BranchOp,
|
||||||
default:
|
default:
|
||||||
llvm_unreachable("Unexpected opcode!");
|
llvm_unreachable("Unexpected opcode!");
|
||||||
case RISCV::BEQ:
|
case RISCV::BEQ:
|
||||||
|
case RISCV::VBEQ:
|
||||||
case RISCV::BNE:
|
case RISCV::BNE:
|
||||||
|
case RISCV::VBNE:
|
||||||
case RISCV::BLT:
|
case RISCV::BLT:
|
||||||
|
case RISCV::VBLT:
|
||||||
case RISCV::BGE:
|
case RISCV::BGE:
|
||||||
|
case RISCV::VBGE:
|
||||||
case RISCV::BLTU:
|
case RISCV::BLTU:
|
||||||
|
case RISCV::VBLTU:
|
||||||
case RISCV::BGEU:
|
case RISCV::BGEU:
|
||||||
|
case RISCV::VBGEU:
|
||||||
|
case RISCV::JOIN:
|
||||||
return isIntN(13, BrOffset);
|
return isIntN(13, BrOffset);
|
||||||
case RISCV::JAL:
|
case RISCV::JAL:
|
||||||
case RISCV::PseudoBR:
|
case RISCV::PseudoBR:
|
||||||
|
|
|
@ -42,12 +42,16 @@ CondCode getOppositeBranchCondition(CondCode);
|
||||||
} // end of namespace RISCVCC
|
} // end of namespace RISCVCC
|
||||||
|
|
||||||
class RISCVInstrInfo : public RISCVGenInstrInfo {
|
class RISCVInstrInfo : public RISCVGenInstrInfo {
|
||||||
|
// WORKAROUND: Indicate the branch remove is in a divergent execution env.
|
||||||
|
// so that a newly inserted branch should be it as well.
|
||||||
|
mutable bool IsDivergentBranch;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit RISCVInstrInfo(RISCVSubtarget &STI);
|
explicit RISCVInstrInfo(RISCVSubtarget &STI);
|
||||||
|
|
||||||
MCInst getNop() const override;
|
MCInst getNop() const override;
|
||||||
const MCInstrDesc &getBrCond(RISCVCC::CondCode CC) const;
|
const MCInstrDesc &getBrCond(RISCVCC::CondCode CC) const;
|
||||||
|
const MCInstrDesc &getVBrCond(RISCVCC::CondCode CC) const;
|
||||||
|
|
||||||
unsigned isLoadFromStackSlot(const MachineInstr &MI,
|
unsigned isLoadFromStackSlot(const MachineInstr &MI,
|
||||||
int &FrameIndex) const override;
|
int &FrameIndex) const override;
|
||||||
|
|
|
@ -1386,11 +1386,12 @@ def IntCCtoRISCVCC : SDNodeXForm<riscv_selectcc, [{
|
||||||
return CurDAG->getTargetConstant(BrCC, SDLoc(N), Subtarget->getXLenVT());
|
return CurDAG->getTargetConstant(BrCC, SDLoc(N), Subtarget->getXLenVT());
|
||||||
}]>;
|
}]>;
|
||||||
|
|
||||||
def riscv_selectcc_frag : PatFrag<(ops node:$lhs, node:$rhs, node:$cc,
|
def UniformSelectCCFrag : PatFrag<(ops node:$lhs, node:$rhs, node:$cc,
|
||||||
node:$truev, node:$falsev),
|
node:$truev, node:$falsev),
|
||||||
(riscv_selectcc node:$lhs, node:$rhs,
|
(riscv_selectcc node:$lhs, node:$rhs,
|
||||||
node:$cc, node:$truev,
|
node:$cc, node:$truev,
|
||||||
node:$falsev), [{}],
|
node:$falsev),
|
||||||
|
[{ return !N->isDivergent(); }],
|
||||||
IntCCtoRISCVCC>;
|
IntCCtoRISCVCC>;
|
||||||
|
|
||||||
let Predicates = [HasShortForwardBranchOpt],
|
let Predicates = [HasShortForwardBranchOpt],
|
||||||
|
@ -1401,7 +1402,7 @@ def PseudoCCMOVGPR : Pseudo<(outs GPR:$dst),
|
||||||
(ins GPR:$lhs, GPR:$rhs, ixlenimm:$cc,
|
(ins GPR:$lhs, GPR:$rhs, ixlenimm:$cc,
|
||||||
GPR:$falsev, GPR:$truev),
|
GPR:$falsev, GPR:$truev),
|
||||||
[(set GPR:$dst,
|
[(set GPR:$dst,
|
||||||
(riscv_selectcc_frag:$cc GPR:$lhs, GPR:$rhs,
|
(UniformSelectCCFrag:$cc GPR:$lhs, GPR:$rhs,
|
||||||
cond, GPR:$truev,
|
cond, GPR:$truev,
|
||||||
GPR:$falsev))]>,
|
GPR:$falsev))]>,
|
||||||
Sched<[WriteSFB, ReadSFB, ReadSFB, ReadSFB, ReadSFB]>;
|
Sched<[WriteSFB, ReadSFB, ReadSFB, ReadSFB, ReadSFB]>;
|
||||||
|
@ -1413,11 +1414,11 @@ multiclass SelectCC_GPR_rrirr<RegisterClass valty> {
|
||||||
(ins GPR:$lhs, GPR:$rhs, ixlenimm:$cc,
|
(ins GPR:$lhs, GPR:$rhs, ixlenimm:$cc,
|
||||||
valty:$truev, valty:$falsev),
|
valty:$truev, valty:$falsev),
|
||||||
[(set valty:$dst,
|
[(set valty:$dst,
|
||||||
(riscv_selectcc_frag:$cc GPR:$lhs, GPR:$rhs, cond,
|
(UniformSelectCCFrag:$cc GPR:$lhs, GPR:$rhs, cond,
|
||||||
valty:$truev, valty:$falsev))]>;
|
valty:$truev, valty:$falsev))]>;
|
||||||
// Explicitly select 0 in the condition to X0. The register coalescer doesn't
|
// Explicitly select 0 in the condition to X0. The register coalescer doesn't
|
||||||
// always do it.
|
// always do it.
|
||||||
def : Pat<(riscv_selectcc_frag:$cc GPR:$lhs, 0, cond, valty:$truev,
|
def : Pat<(UniformSelectCCFrag:$cc GPR:$lhs, 0, cond, valty:$truev,
|
||||||
valty:$falsev),
|
valty:$falsev),
|
||||||
(!cast<Instruction>(NAME#"_Using_CC_GPR") GPR:$lhs, X0,
|
(!cast<Instruction>(NAME#"_Using_CC_GPR") GPR:$lhs, X0,
|
||||||
(IntCCtoRISCVCC $cc), valty:$truev, valty:$falsev)>;
|
(IntCCtoRISCVCC $cc), valty:$truev, valty:$falsev)>;
|
||||||
|
|
|
@ -753,7 +753,7 @@ def : InstAlias<"c.fsdsp $rs2, (${rs1})", (C_FSDSP FPR64C:$rs2, SPMem:$rs1, 0)>;
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
class SelectCompressOpt<CondCode Cond>: Pat<
|
class SelectCompressOpt<CondCode Cond>: Pat<
|
||||||
(riscv_selectcc_frag:$select GPR:$lhs, simm12_no6:$Constant, Cond,
|
(UniformSelectCCFrag:$select GPR:$lhs, simm12_no6:$Constant, Cond,
|
||||||
GPR:$truev, GPR:$falsev),
|
GPR:$truev, GPR:$falsev),
|
||||||
(Select_GPR_Using_CC_GPR (ADDI GPR:$lhs, (NegImm simm12:$Constant)), X0,
|
(Select_GPR_Using_CC_GPR (ADDI GPR:$lhs, (NegImm simm12:$Constant)), X0,
|
||||||
(IntCCtoRISCVCC $select), GPR:$truev, GPR:$falsev)>;
|
(IntCCtoRISCVCC $select), GPR:$truev, GPR:$falsev)>;
|
||||||
|
|
|
@ -628,6 +628,15 @@ class BranchCC_vvi<bits<3> funct3, string opcodestr>
|
||||||
: RVInstVB<funct3, (outs), (ins VGPR:$vs1, VGPR:$vs2, simm13_lsb0:$imm12),
|
: RVInstVB<funct3, (outs), (ins VGPR:$vs1, VGPR:$vs2, simm13_lsb0:$imm12),
|
||||||
opcodestr, "$vs1, $vs2, $imm12">, Sched<[]>;
|
opcodestr, "$vs1, $vs2, $imm12">, Sched<[]>;
|
||||||
|
|
||||||
|
let hasSideEffects = 0, mayLoad = 0, mayStore = 0,
|
||||||
|
isBarrier = 1, isBranch = 1, isTerminator = 1 in
|
||||||
|
class Branch_i<bits<3> funct3, string opcodestr>
|
||||||
|
: RVInstVB<funct3, (outs), (ins simm13_lsb0:$imm12),
|
||||||
|
opcodestr, "$imm12">, Sched<[]> {
|
||||||
|
let vs1 = 0;
|
||||||
|
let vs2 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Instructions
|
// Instructions
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -638,7 +647,7 @@ def VBLT : BranchCC_vvi<0b100, "vblt">;
|
||||||
def VBGE : BranchCC_vvi<0b101, "vbge">;
|
def VBGE : BranchCC_vvi<0b101, "vbge">;
|
||||||
def VBLTU : BranchCC_vvi<0b110, "vbltu">;
|
def VBLTU : BranchCC_vvi<0b110, "vbltu">;
|
||||||
def VBGEU : BranchCC_vvi<0b111, "vbgeu">;
|
def VBGEU : BranchCC_vvi<0b111, "vbgeu">;
|
||||||
def JOIN : BranchCC_vvi<0b011, "join">;
|
def JOIN : Branch_i<0b011, "join">;
|
||||||
|
|
||||||
def VLUXEI8 : VectorLoad<LSWidth8, "vluxei8.v">;
|
def VLUXEI8 : VectorLoad<LSWidth8, "vluxei8.v">;
|
||||||
def VLUXEI16 : VectorLoad<LSWidth16, "vluxei16.v">;
|
def VLUXEI16 : VectorLoad<LSWidth16, "vluxei16.v">;
|
||||||
|
@ -1068,6 +1077,48 @@ defm : DivergentStPat<truncstorei8, VSUXEI8>;
|
||||||
defm : DivergentStPat<truncstorei16, VSUXEI16>;
|
defm : DivergentStPat<truncstorei16, VSUXEI16>;
|
||||||
defm : DivergentStPat<store, VSUXEI32>;
|
defm : DivergentStPat<store, VSUXEI32>;
|
||||||
|
|
||||||
|
|
||||||
|
def DivergentSelectCCFrag : PatFrag<(ops node:$lhs, node:$rhs, node:$cc,
|
||||||
|
node:$truev, node:$falsev),
|
||||||
|
(riscv_selectcc node:$lhs, node:$rhs,
|
||||||
|
node:$cc, node:$truev,
|
||||||
|
node:$falsev),
|
||||||
|
[{ return N->isDivergent(); }],
|
||||||
|
IntCCtoRISCVCC>;
|
||||||
|
|
||||||
|
let Predicates = [HasShortForwardBranchOpt],
|
||||||
|
Constraints = "$dst = $falsev", isCommutable = 1, Size = 8 in {
|
||||||
|
// This instruction moves $truev to $dst when the condition is true. It will
|
||||||
|
// be expanded to control flow in RISCVExpandPseudoInsts.
|
||||||
|
def PseudoCCMOVVGPR : Pseudo<(outs VGPR:$dst),
|
||||||
|
(ins VGPR:$lhs, VGPR:$rhs, ixlenimm:$cc,
|
||||||
|
VGPR:$falsev, VGPR:$truev),
|
||||||
|
[(set VGPR:$dst,
|
||||||
|
(DivergentSelectCCFrag:$cc VGPR:$lhs, VGPR:$rhs,
|
||||||
|
cond, VGPR:$truev,
|
||||||
|
VGPR:$falsev))]>,
|
||||||
|
Sched<[WriteSFB, ReadSFB, ReadSFB, ReadSFB, ReadSFB]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
multiclass SelectCC_VGPR_rrirr<RegisterClass valty> {
|
||||||
|
let usesCustomInserter = 1 in
|
||||||
|
def _Using_CC_VGPR : Pseudo<(outs valty:$dst),
|
||||||
|
(ins VGPR:$lhs, VGPR:$rhs, ixlenimm:$cc,
|
||||||
|
valty:$truev, valty:$falsev),
|
||||||
|
[(set valty:$dst,
|
||||||
|
(DivergentSelectCCFrag:$cc VGPR:$lhs, VGPR:$rhs, cond,
|
||||||
|
valty:$truev, valty:$falsev))]>;
|
||||||
|
// Explicitly select 0 in the condition to X0. The register coalescer doesn't
|
||||||
|
// always do it.
|
||||||
|
def : Pat<(DivergentSelectCCFrag:$cc VGPR:$lhs, 0, cond, valty:$truev,
|
||||||
|
valty:$falsev),
|
||||||
|
(!cast<Instruction>(NAME#"_Using_CC_VGPR") VGPR:$lhs, X0,
|
||||||
|
(IntCCtoRISCVCC $cc), valty:$truev, valty:$falsev)>;
|
||||||
|
}
|
||||||
|
|
||||||
|
let Predicates = [NoShortForwardBranchOpt] in
|
||||||
|
defm Select_VGPR : SelectCC_VGPR_rrirr<VGPR>;
|
||||||
|
|
||||||
// Match `riscv_brcc` and lower to the appropriate RISC-V branch instruction.
|
// Match `riscv_brcc` and lower to the appropriate RISC-V branch instruction.
|
||||||
class DivergentBccPat<CondCode Cond, RVInstVB Inst>
|
class DivergentBccPat<CondCode Cond, RVInstVB Inst>
|
||||||
: Pat<(DivergentTetradFrag<riscv_brcc> VGPR:$vs1, VGPR:$vs2, Cond, bb:$imm12),
|
: Pat<(DivergentTetradFrag<riscv_brcc> VGPR:$vs1, VGPR:$vs2, Cond, bb:$imm12),
|
||||||
|
|
Loading…
Reference in New Issue