LLVM 24.0.0git
RISCVVectorPeephole.cpp
Go to the documentation of this file.
1//===- RISCVVectorPeephole.cpp - MI Vector Pseudo Peepholes ---------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This pass performs various vector pseudo peephole optimisations after
10// instruction selection.
11//
12// Currently it converts vmerge.vvm to vmv.v.v
13// PseudoVMERGE_VVM %false, %false, %true, %allonesmask, %vl, %sew
14// ->
15// PseudoVMV_V_V %false, %true, %vl, %sew
16//
17// And masked pseudos to unmasked pseudos
18// PseudoVADD_V_V_MASK %passthru, %a, %b, %allonesmask, %vl, sew, policy
19// ->
20// PseudoVADD_V_V %passthru %a, %b, %vl, sew, policy
21//
22// It also converts AVLs to VLMAX where possible
23// %vl = VLENB * something
24// PseudoVADD_V_V %passthru, %a, %b, %vl, sew, policy
25// ->
26// PseudoVADD_V_V %passthru, %a, %b, -1, sew, policy
27//
28//===----------------------------------------------------------------------===//
29
30#include "RISCV.h"
31#include "RISCVSubtarget.h"
37
38using namespace llvm;
39
40#define DEBUG_TYPE "riscv-vector-peephole"
41
42namespace {
43
44class RISCVVectorPeephole : public MachineFunctionPass {
45public:
46 static char ID;
47 const TargetInstrInfo *TII;
50 const RISCVSubtarget *ST;
51 RISCVVectorPeephole() : MachineFunctionPass(ID) {}
52
53 bool runOnMachineFunction(MachineFunction &MF) override;
54 MachineFunctionProperties getRequiredProperties() const override {
55 return MachineFunctionProperties().setIsSSA();
56 }
57
58 StringRef getPassName() const override {
59 return "RISC-V Vector Peephole Optimization";
60 }
61
62 void getAnalysisUsage(AnalysisUsage &AU) const override {
63 AU.setPreservesCFG();
66 }
67
68private:
69 bool convertToVLMAX(MachineInstr &MI) const;
70 bool convertToWholeRegister(MachineInstr &MI) const;
71 bool convertToUnmasked(MachineInstr &MI) const;
72 bool convertAllOnesVMergeToVMv(MachineInstr &MI) const;
73 bool convertSameMaskVMergeToVMv(MachineInstr &MI);
74 bool foldUndefPassthruVMV_V_V(MachineInstr &MI);
75 bool foldVMV_V_V(MachineInstr &MI);
76 bool foldVMergeToMask(MachineInstr &MI) const;
77
78 bool hasSameEEW(const MachineInstr &User, const MachineInstr &Src) const;
79 bool isAllOnesMask(const MachineInstr *MaskDef) const;
80 std::optional<unsigned> getConstant(const MachineOperand &VL) const;
81 bool ensureDominates(ArrayRef<const MachineOperand *> Defs,
82 MachineInstr &Use) const;
84 lookThruCopies(Register Reg, bool OneUseOnly = false,
86};
87
88} // namespace
89
90char RISCVVectorPeephole::ID = 0;
91
92INITIALIZE_PASS(RISCVVectorPeephole, DEBUG_TYPE, "RISC-V Fold Masks", false,
93 false)
94
95/// Given \p User that has an input operand with EEW=SEW, which uses the dest
96/// operand of \p Src with an unknown EEW, return true if their EEWs match.
97bool RISCVVectorPeephole::hasSameEEW(const MachineInstr &User,
98 const MachineInstr &Src) const {
99 unsigned UserLog2SEW =
100 User.getOperand(RISCVII::getSEWOpNum(User.getDesc())).getImm();
101 unsigned SrcLog2SEW =
102 Src.getOperand(RISCVII::getSEWOpNum(Src.getDesc())).getImm();
103 unsigned SrcLog2EEW = RISCV::getDestLog2EEW(
104 TII->get(RISCV::getRVVMCOpcode(Src.getOpcode())), SrcLog2SEW);
105 return SrcLog2EEW == UserLog2SEW;
106}
107
108/// Check if an operand is an immediate or a materialized ADDI $x0, imm.
109std::optional<unsigned>
110RISCVVectorPeephole::getConstant(const MachineOperand &VL) const {
111 if (VL.isImm())
112 return VL.getImm();
113
114 MachineInstr *Def = MRI->getVRegDef(VL.getReg());
115 if (!Def || Def->getOpcode() != RISCV::ADDI || !Def->getOperand(1).isReg() ||
116 Def->getOperand(1).getReg() != RISCV::X0)
117 return std::nullopt;
118 return Def->getOperand(2).getImm();
119}
120
121/// Convert AVLs that are known to be VLMAX to the VLMAX sentinel.
122bool RISCVVectorPeephole::convertToVLMAX(MachineInstr &MI) const {
123 if (!RISCVII::hasVLOp(MI.getDesc().TSFlags) ||
124 !RISCVII::hasSEWOp(MI.getDesc().TSFlags))
125 return false;
126
127 auto LMUL = RISCVVType::decodeVLMUL(RISCVII::getLMul(MI.getDesc().TSFlags));
128 // Fixed-point value, denominator=8
129 unsigned LMULFixed = LMUL.second ? (8 / LMUL.first) : 8 * LMUL.first;
130 unsigned Log2SEW = MI.getOperand(RISCVII::getSEWOpNum(MI.getDesc())).getImm();
131 // A Log2SEW of 0 is an operation on mask registers only
132 unsigned SEW = Log2SEW ? 1 << Log2SEW : 8;
133 assert(RISCVVType::isValidSEW(SEW) && "Unexpected SEW");
134 assert(8 * LMULFixed / SEW > 0);
135
136 // If the exact VLEN is known then we know VLMAX, check if the AVL == VLMAX.
137 MachineOperand &VL = MI.getOperand(RISCVII::getVLOpNum(MI.getDesc()));
138 if (auto VLen = ST->getRealVLen(), AVL = getConstant(VL);
139 VLen && AVL && (*VLen * LMULFixed) / SEW == *AVL * 8) {
141 return true;
142 }
143
144 // If an AVL is a VLENB that's possibly scaled to be equal to VLMAX, convert
145 // it to the VLMAX sentinel value.
146 if (!VL.isReg())
147 return false;
148 MachineInstr *Def = MRI->getVRegDef(VL.getReg());
149 if (!Def)
150 return false;
151
152 // Fixed-point value, denominator=8
153 uint64_t ScaleFixed = 8;
154 // Check if the VLENB was potentially scaled with slli/srli
155 if (Def->getOpcode() == RISCV::SLLI) {
156 assert(Def->getOperand(2).getImm() < 64);
157 ScaleFixed <<= Def->getOperand(2).getImm();
158 Def = MRI->getVRegDef(Def->getOperand(1).getReg());
159 } else if (Def->getOpcode() == RISCV::SRLI) {
160 assert(Def->getOperand(2).getImm() < 64);
161 ScaleFixed >>= Def->getOperand(2).getImm();
162 Def = MRI->getVRegDef(Def->getOperand(1).getReg());
163 }
164
165 if (!Def || Def->getOpcode() != RISCV::PseudoReadVLENB)
166 return false;
167
168 // AVL = (VLENB * Scale)
169 //
170 // VLMAX = (VLENB * 8 * LMUL) / SEW
171 //
172 // AVL == VLMAX
173 // -> VLENB * Scale == (VLENB * 8 * LMUL) / SEW
174 // -> Scale == (8 * LMUL) / SEW
175 if (ScaleFixed != 8 * LMULFixed / SEW)
176 return false;
177
179
180 return true;
181}
182
183bool RISCVVectorPeephole::isAllOnesMask(const MachineInstr *MaskDef) const {
184 while (MaskDef->isCopy() && MaskDef->getOperand(1).getReg().isVirtual())
185 MaskDef = MRI->getVRegDef(MaskDef->getOperand(1).getReg());
186
187 // TODO: Check that the VMSET is the expected bitwidth? The pseudo has
188 // undefined behaviour if it's the wrong bitwidth, so we could choose to
189 // assume that it's all-ones? Same applies to its VL.
190 switch (MaskDef->getOpcode()) {
191 case RISCV::PseudoVMSET_M_B1:
192 case RISCV::PseudoVMSET_M_B2:
193 case RISCV::PseudoVMSET_M_B4:
194 case RISCV::PseudoVMSET_M_B8:
195 case RISCV::PseudoVMSET_M_B16:
196 case RISCV::PseudoVMSET_M_B32:
197 case RISCV::PseudoVMSET_M_B64:
198 return true;
199 default:
200 return false;
201 }
202}
203
204/// Convert unit strided unmasked loads and stores to whole-register equivalents
205/// to avoid the dependency on $vl and $vtype.
206///
207/// %x = PseudoVLE8_V_M1 %passthru, %ptr, %vlmax, policy
208/// PseudoVSE8_V_M1 %v, %ptr, %vlmax
209///
210/// ->
211///
212/// %x = VL1RE8_V %ptr
213/// VS1R_V %v, %ptr
214bool RISCVVectorPeephole::convertToWholeRegister(MachineInstr &MI) const {
215#define CASE_WHOLE_REGISTER_LMUL_SEW(lmul, sew) \
216 case RISCV::PseudoVLE##sew##_V_M##lmul: \
217 NewOpc = RISCV::VL##lmul##RE##sew##_V; \
218 break; \
219 case RISCV::PseudoVSE##sew##_V_M##lmul: \
220 NewOpc = RISCV::VS##lmul##R_V; \
221 break;
222#define CASE_WHOLE_REGISTER_LMUL(lmul) \
223 CASE_WHOLE_REGISTER_LMUL_SEW(lmul, 8) \
224 CASE_WHOLE_REGISTER_LMUL_SEW(lmul, 16) \
225 CASE_WHOLE_REGISTER_LMUL_SEW(lmul, 32) \
226 CASE_WHOLE_REGISTER_LMUL_SEW(lmul, 64)
227
228 unsigned NewOpc;
229 switch (MI.getOpcode()) {
234 default:
235 return false;
236 }
237
238 MachineOperand &VLOp = MI.getOperand(RISCVII::getVLOpNum(MI.getDesc()));
239 if (!VLOp.isImm() || VLOp.getImm() != RISCV::VLMaxSentinel)
240 return false;
241
242 // Whole register instructions aren't pseudos so they don't have
243 // policy/SEW/AVL ops, and they don't have passthrus.
244 if (RISCVII::hasVecPolicyOp(MI.getDesc().TSFlags))
245 MI.removeOperand(RISCVII::getVecPolicyOpNum(MI.getDesc()));
246 MI.removeOperand(RISCVII::getSEWOpNum(MI.getDesc()));
247 MI.removeOperand(RISCVII::getVLOpNum(MI.getDesc()));
248 if (RISCVII::isFirstDefTiedToFirstUse(MI.getDesc()))
249 MI.removeOperand(1);
250
251 MI.setDesc(TII->get(NewOpc));
252
253 return true;
254}
255
256static unsigned getVMV_V_VOpcodeForVMERGE_VVM(const MachineInstr &MI) {
257#define CASE_VMERGE_TO_VMV(lmul) \
258 case RISCV::PseudoVMERGE_VVM_##lmul: \
259 return RISCV::PseudoVMV_V_V_##lmul;
260 switch (MI.getOpcode()) {
261 default:
262 return 0;
263 CASE_VMERGE_TO_VMV(MF8)
264 CASE_VMERGE_TO_VMV(MF4)
265 CASE_VMERGE_TO_VMV(MF2)
266 CASE_VMERGE_TO_VMV(M1)
267 CASE_VMERGE_TO_VMV(M2)
268 CASE_VMERGE_TO_VMV(M4)
269 CASE_VMERGE_TO_VMV(M8)
270 }
271}
272
273/// Convert a PseudoVMERGE_VVM with an all ones mask to a PseudoVMV_V_V.
274///
275/// %x = PseudoVMERGE_VVM %passthru, %false, %true, %allones, sew, vl
276/// ->
277/// %x = PseudoVMV_V_V %passthru, %true, vl, sew, tu_mu
278bool RISCVVectorPeephole::convertAllOnesVMergeToVMv(MachineInstr &MI) const {
279 unsigned NewOpc = getVMV_V_VOpcodeForVMERGE_VVM(MI);
280 if (!NewOpc)
281 return false;
282 if (!isAllOnesMask(MRI->getVRegDef(MI.getOperand(4).getReg())))
283 return false;
284
285 MI.setDesc(TII->get(NewOpc));
286 MI.removeOperand(2); // False operand
287 MI.removeOperand(3); // Mask operand
288 MI.addOperand(
290
291 // vmv.v.v doesn't have a mask operand, so we may be able to inflate the
292 // register class for the destination and passthru operands e.g. VRNoV0 -> VR
293 MRI->recomputeRegClass(MI.getOperand(0).getReg());
294 if (MI.getOperand(1).getReg().isValid())
295 MRI->recomputeRegClass(MI.getOperand(1).getReg());
296 return true;
297}
298
299// If \p Reg is defined by one or more COPYs of virtual registers, traverses
300// the chain and returns the root non-COPY source.
301Register RISCVVectorPeephole::lookThruCopies(
302 Register Reg, bool OneUseOnly,
303 SmallVectorImpl<MachineInstr *> *Copies) const {
304 while (MachineInstr *Def = MRI->getUniqueVRegDef(Reg)) {
305 if (!Def->isFullCopy())
306 break;
307 Register Src = Def->getOperand(1).getReg();
308 if (!Src.isVirtual())
309 break;
310 if (OneUseOnly && !MRI->hasOneNonDBGUse(Reg))
311 break;
312 if (Copies)
313 Copies->push_back(Def);
314 Reg = Src;
315 }
316 return Reg;
317}
318
319/// If a PseudoVMERGE_VVM's true operand is a masked pseudo and both have the
320/// same mask, and the masked pseudo's passthru is the same as the false
321/// operand, we can convert the PseudoVMERGE_VVM to a PseudoVMV_V_V.
322///
323/// %true = PseudoVADD_VV_M1_MASK %false, %x, %y, %mask, vl1, sew, policy
324/// %x = PseudoVMERGE_VVM %passthru, %false, %true, %mask, vl2, sew
325/// ->
326/// %true = PseudoVADD_VV_M1_MASK %false, %x, %y, %mask, vl1, sew, policy
327/// %x = PseudoVMV_V_V %passthru, %true, vl2, sew, tu_mu
328bool RISCVVectorPeephole::convertSameMaskVMergeToVMv(MachineInstr &MI) {
329 unsigned NewOpc = getVMV_V_VOpcodeForVMERGE_VVM(MI);
330 if (!NewOpc)
331 return false;
332 MachineInstr *True = MRI->getVRegDef(MI.getOperand(3).getReg());
333
334 if (!True || True->getParent() != MI.getParent())
335 return false;
336
337 auto *TrueMaskedInfo = RISCV::getMaskedPseudoInfo(True->getOpcode());
338 if (!TrueMaskedInfo || !hasSameEEW(MI, *True))
339 return false;
340
341 Register TrueMaskReg = lookThruCopies(
342 True->getOperand(TrueMaskedInfo->MaskOpIdx + True->getNumExplicitDefs())
343 .getReg());
344 Register MIMaskReg = lookThruCopies(MI.getOperand(4).getReg());
345 if (!TrueMaskReg.isVirtual() || TrueMaskReg != MIMaskReg)
346 return false;
347
348 // Masked off lanes past TrueVL will come from False, and converting to vmv
349 // will lose these lanes unless MIVL <= TrueVL.
350 // We can relax this when False == Passthru and True's tail policy is TU,
351 // because True's tail lanes will preserve its passthru (= False = Passthru).
352 const MachineOperand &MIVL = MI.getOperand(RISCVII::getVLOpNum(MI.getDesc()));
353 const MachineOperand &TrueVL =
354 True->getOperand(RISCVII::getVLOpNum(True->getDesc()));
355 Register FalseReg = MI.getOperand(2).getReg();
356 if (!RISCV::isVLKnownLE(MIVL, TrueVL)) {
357 Register PassthruReg = MI.getOperand(1).getReg();
358 if (FalseReg.isValid() && FalseReg != PassthruReg)
359 return false;
361 return false;
362 uint64_t TruePolicy =
364 if (TruePolicy & RISCVVType::TAIL_AGNOSTIC)
365 return false;
366 }
367
368 // True's passthru needs to be equivalent to False
369 Register TruePassthruReg = True->getOperand(1).getReg();
370 if (TruePassthruReg != FalseReg) {
371 // If True's passthru is undef see if we can change it to False
372 if (TruePassthruReg.isValid() ||
373 !MRI->hasOneUse(MI.getOperand(3).getReg()) ||
374 !ensureDominates(&MI.getOperand(2), *True))
375 return false;
376 True->getOperand(1).setReg(MI.getOperand(2).getReg());
377 // If True is masked then its passthru needs to be in VRNoV0.
378 MRI->constrainRegClass(True->getOperand(1).getReg(),
379 TII->getRegClass(True->getDesc(), 1));
380 }
381
382 // If True is mask agnostic, we need to make it mask undisturbed.
384 MachineOperand &PolicyOp =
386 PolicyOp.setImm(PolicyOp.getImm() & ~RISCVVType::MASK_AGNOSTIC);
387 }
388
389 MI.setDesc(TII->get(NewOpc));
390 MI.removeOperand(2); // False operand
391 MI.removeOperand(3); // Mask operand
392 MI.addOperand(
394
395 // vmv.v.v doesn't have a mask operand, so we may be able to inflate the
396 // register class for the destination and passthru operands e.g. VRNoV0 -> VR
397 MRI->recomputeRegClass(MI.getOperand(0).getReg());
398 if (MI.getOperand(1).getReg().isValid())
399 MRI->recomputeRegClass(MI.getOperand(1).getReg());
400 return true;
401}
402
403bool RISCVVectorPeephole::convertToUnmasked(MachineInstr &MI) const {
404 const RISCV::RISCVMaskedPseudoInfo *I =
405 RISCV::getMaskedPseudoInfo(MI.getOpcode());
406 if (!I)
407 return false;
408
409 if (!isAllOnesMask(MRI->getVRegDef(
410 MI.getOperand(I->MaskOpIdx + MI.getNumExplicitDefs()).getReg())))
411 return false;
412
413 // There are two classes of pseudos in the table - compares and
414 // everything else. See the comment on RISCVMaskedPseudo for details.
415 const unsigned Opc = I->UnmaskedPseudo;
416 const MCInstrDesc &MCID = TII->get(Opc);
417 [[maybe_unused]] const bool HasPolicyOp =
419 const bool HasPassthru = RISCVII::isFirstDefTiedToFirstUse(MCID);
420 const MCInstrDesc &MaskedMCID = TII->get(MI.getOpcode());
423 "Unmasked pseudo has policy but masked pseudo doesn't?");
424 assert(HasPolicyOp == HasPassthru && "Unexpected pseudo structure");
425 assert(!(HasPassthru && !RISCVII::isFirstDefTiedToFirstUse(MaskedMCID)) &&
426 "Unmasked with passthru but masked with no passthru?");
427 (void)HasPolicyOp;
428
429 MI.setDesc(MCID);
430
431 // Drop the policy operand if unmasked doesn't need it.
432 if (RISCVII::hasVecPolicyOp(MaskedMCID.TSFlags) &&
434 MI.removeOperand(RISCVII::getVecPolicyOpNum(MaskedMCID));
435
436 // TODO: Increment all MaskOpIdxs in tablegen by num of explicit defs?
437 unsigned MaskOpIdx = I->MaskOpIdx + MI.getNumExplicitDefs();
438 MI.removeOperand(MaskOpIdx);
439
440 // The unmasked pseudo will no longer be constrained to the vrnov0 reg class,
441 // so try and relax it to vr.
442 MRI->recomputeRegClass(MI.getOperand(0).getReg());
443
444 // If the original masked pseudo had a passthru, relax it or remove it.
445 if (RISCVII::isFirstDefTiedToFirstUse(MaskedMCID)) {
446 unsigned PassthruOpIdx = MI.getNumExplicitDefs();
447 if (HasPassthru) {
448 if (MI.getOperand(PassthruOpIdx).getReg())
449 MRI->recomputeRegClass(MI.getOperand(PassthruOpIdx).getReg());
450 } else
451 MI.removeOperand(PassthruOpIdx);
452 }
453
454 return true;
455}
456
457/// Given A and B are in the same MBB, returns true if A comes before B.
460 assert(A->getParent() == B->getParent());
461 if (A == B)
462 return false;
463 const MachineBasicBlock *MBB = A->getParent();
464 auto MBBEnd = MBB->end();
465 if (B == MBBEnd)
466 return true;
467
469 for (; &*I != A && &*I != B; ++I)
470 ;
471
472 return &*I == A;
473}
474
475/// If a register in \p Defs doesn't dominate \p Use, try to move Use so it
476/// does. Returns false if any def doesn't dominate and we can't move Use. Each
477/// def must be in the same block as Use.
478bool RISCVVectorPeephole::ensureDominates(ArrayRef<const MachineOperand *> Defs,
479 MachineInstr &Use) const {
480 MachineInstr *Dest = &Use;
481
482 for (const MachineOperand *MO : Defs) {
483 assert(MO->getParent()->getParent() == Use.getParent());
484 if (!MO->isReg() || !MO->getReg().isValid())
485 continue;
486
487 MachineInstr *Def = MRI->getVRegDef(MO->getReg());
488 if (Def->getParent() == Dest->getParent() &&
489 !strictlyDominates(Def, *Dest)) {
490 if (!RISCVInstrInfo::isSafeToMove(*Dest, *Def->getNextNode()))
491 return false;
492 Dest = Def->getNextNode();
493 }
494 }
495
496 if (Dest != &Use)
497 Use.moveBefore(Dest);
498
499 return true;
500}
501
502/// If a PseudoVMV_V_V's passthru is undef then we can replace it with its input
503bool RISCVVectorPeephole::foldUndefPassthruVMV_V_V(MachineInstr &MI) {
504 if (RISCV::getRVVMCOpcode(MI.getOpcode()) != RISCV::VMV_V_V)
505 return false;
506 if (MI.getOperand(1).getReg().isValid())
507 return false;
508
509 // If the input was a pseudo with a policy operand, we can give it a tail
510 // agnostic policy if MI's undef tail subsumes the input's.
511 MachineInstr *Src = MRI->getVRegDef(MI.getOperand(2).getReg());
512 if (Src && !Src->hasUnmodeledSideEffects() &&
513 MRI->hasOneUse(MI.getOperand(2).getReg()) &&
514 RISCVII::hasVLOp(Src->getDesc().TSFlags) &&
515 RISCVII::hasVecPolicyOp(Src->getDesc().TSFlags) && hasSameEEW(MI, *Src)) {
516 const MachineOperand &MIVL = MI.getOperand(3);
517 const MachineOperand &SrcVL =
518 Src->getOperand(RISCVII::getVLOpNum(Src->getDesc()));
519
520 MachineOperand &SrcPolicy =
521 Src->getOperand(RISCVII::getVecPolicyOpNum(Src->getDesc()));
522
523 if (RISCV::isVLKnownLE(MIVL, SrcVL))
524 SrcPolicy.setImm(SrcPolicy.getImm() | RISCVVType::TAIL_AGNOSTIC);
525 }
526
527 MRI->constrainRegClass(MI.getOperand(2).getReg(),
528 MRI->getRegClass(MI.getOperand(0).getReg()));
529 MRI->replaceRegWith(MI.getOperand(0).getReg(), MI.getOperand(2).getReg());
530 MRI->clearKillFlags(MI.getOperand(2).getReg());
531 MI.eraseFromParent();
532 return true;
533}
534
535/// If a PseudoVMV_V_V is the only user of its input, fold its passthru and VL
536/// into it.
537///
538/// %x = PseudoVADD_V_V_M1 %passthru, %a, %b, %vl1, sew, policy
539/// %y = PseudoVMV_V_V_M1 %passthru, %x, %vl2, sew, policy
540/// (where %vl1 <= %vl2)
541///
542/// ->
543///
544/// %y = PseudoVADD_V_V_M1 %passthru, %a, %b, vl1, sew, policy
545bool RISCVVectorPeephole::foldVMV_V_V(MachineInstr &MI) {
546 if (RISCV::getRVVMCOpcode(MI.getOpcode()) != RISCV::VMV_V_V)
547 return false;
548
549 MachineOperand &Passthru = MI.getOperand(1);
550
551 if (!MRI->hasOneUse(MI.getOperand(2).getReg()))
552 return false;
553
554 MachineInstr *Src = MRI->getVRegDef(MI.getOperand(2).getReg());
555 if (!Src || Src->hasUnmodeledSideEffects() ||
556 Src->getParent() != MI.getParent() ||
557 !RISCVII::isFirstDefTiedToFirstUse(Src->getDesc()) ||
558 !RISCVII::hasVLOp(Src->getDesc().TSFlags))
559 return false;
560
561 // Src's dest needs to have the same EEW as MI's input.
562 if (!hasSameEEW(MI, *Src))
563 return false;
564
565 std::optional<std::pair<unsigned, unsigned>> NeedsCommute;
566
567 // Src needs to have the same passthru as VMV_V_V
568 MachineOperand &SrcPassthru = Src->getOperand(Src->getNumExplicitDefs());
569 if (SrcPassthru.getReg().isValid() &&
570 SrcPassthru.getReg() != Passthru.getReg()) {
571 // If Src's passthru != Passthru, check if it uses Passthru in another
572 // operand and try to commute it.
573 int OtherIdx = Src->findRegisterUseOperandIdx(Passthru.getReg(), TRI);
574 if (OtherIdx == -1)
575 return false;
576 unsigned OpIdx1 = OtherIdx;
577 unsigned OpIdx2 = Src->getNumExplicitDefs();
578 if (!TII->findCommutedOpIndices(*Src, OpIdx1, OpIdx2))
579 return false;
580 NeedsCommute = {OpIdx1, OpIdx2};
581 }
582
583 // Src VL will have already been reduced if legal by RISCVVLOptimizer,
584 // so we don't need to handle a smaller source VL here. However, the
585 // user's VL may be larger
586 MachineOperand &SrcVL = Src->getOperand(RISCVII::getVLOpNum(Src->getDesc()));
587 if (!RISCV::isVLKnownLE(SrcVL, MI.getOperand(3)))
588 return false;
589
590 // If the new passthru doesn't dominate Src, try to move Src so it does.
591 if (!ensureDominates(&Passthru, *Src))
592 return false;
593
594 if (NeedsCommute) {
595 auto [OpIdx1, OpIdx2] = *NeedsCommute;
596 [[maybe_unused]] bool Commuted =
597 TII->commuteInstruction(*Src, /*NewMI=*/false, OpIdx1, OpIdx2);
598 assert(Commuted && "Failed to commute Src?");
599 }
600
601 if (SrcPassthru.getReg() != Passthru.getReg()) {
602 SrcPassthru.setReg(Passthru.getReg());
603 // If Src is masked then its passthru needs to be in VRNoV0.
604 if (Passthru.getReg().isValid())
606 Passthru.getReg(),
607 TII->getRegClass(Src->getDesc(), SrcPassthru.getOperandNo()));
608 }
609
610 if (RISCVII::hasVecPolicyOp(Src->getDesc().TSFlags)) {
611 // If MI was tail agnostic and the VL didn't increase, preserve it.
613 if ((MI.getOperand(5).getImm() & RISCVVType::TAIL_AGNOSTIC) &&
614 RISCV::isVLKnownLE(MI.getOperand(3), SrcVL))
616 Src->getOperand(RISCVII::getVecPolicyOpNum(Src->getDesc())).setImm(Policy);
617 }
618
619 MRI->constrainRegClass(Src->getOperand(0).getReg(),
620 MRI->getRegClass(MI.getOperand(0).getReg()));
621 MRI->replaceRegWith(MI.getOperand(0).getReg(), Src->getOperand(0).getReg());
622 MI.eraseFromParent();
623
624 return true;
625}
626
627/// Try to fold away VMERGE_VVM instructions into their operands:
628///
629/// %true = PseudoVADD_VV ...
630/// %x = PseudoVMERGE_VVM_M1 %false, %false, %true, %mask
631/// ->
632/// %x = PseudoVADD_VV_M1_MASK %false, ..., %mask
633///
634/// We can only fold if vmerge's passthru operand, vmerge's false operand and
635/// %true's passthru operand (if it has one) are the same. This is because we
636/// have to consolidate them into one passthru operand in the result.
637///
638/// If %true is masked, then we can use its mask instead of vmerge's if vmerge's
639/// mask is all ones.
640///
641/// The resulting VL is the minimum of the two VLs.
642///
643/// The resulting policy is the effective policy the vmerge would have had,
644/// i.e. whether or not it's passthru operand was implicit-def.
645bool RISCVVectorPeephole::foldVMergeToMask(MachineInstr &MI) const {
646 if (RISCV::getRVVMCOpcode(MI.getOpcode()) != RISCV::VMERGE_VVM)
647 return false;
648
649 // Collect chain of COPYs on True's result for later cleanup.
650 SmallVector<MachineInstr *, 4> TrueCopies;
651 Register PassthruReg = lookThruCopies(MI.getOperand(1).getReg());
652 const MachineOperand &FalseOp = MI.getOperand(2);
653 Register FalseReg = lookThruCopies(FalseOp.getReg());
654 Register TrueReg = lookThruCopies(MI.getOperand(3).getReg(),
655 /*OneUseOnly=*/true, &TrueCopies);
656 if (!TrueReg.isVirtual() || !MRI->hasOneUse(TrueReg))
657 return false;
658 MachineInstr &True = *MRI->getUniqueVRegDef(TrueReg);
659 if (True.getParent() != MI.getParent())
660 return false;
661 const MachineOperand &MaskOp = MI.getOperand(4);
662 MachineInstr *Mask = MRI->getUniqueVRegDef(MaskOp.getReg());
663 assert(Mask);
664
665 const RISCV::RISCVMaskedPseudoInfo *Info =
666 RISCV::lookupMaskedIntrinsicByUnmasked(True.getOpcode());
667 if (!Info)
668 return false;
669
670 // If the EEW of True is different from vmerge's SEW, then we can't fold.
671 if (!hasSameEEW(MI, True))
672 return false;
673
674 // We require that either passthru and false are the same, or that passthru
675 // is undefined.
676 if (PassthruReg && !(PassthruReg.isVirtual() && PassthruReg == FalseReg))
677 return false;
678
679 std::optional<std::pair<unsigned, unsigned>> NeedsCommute;
680
681 // If True has a passthru operand then it needs to be the same as vmerge's
682 // False, since False will be used for the result's passthru operand.
683 Register TruePassthru;
685 TruePassthru =
686 lookThruCopies(True.getOperand(True.getNumExplicitDefs()).getReg());
687 if (TruePassthru && !(TruePassthru.isVirtual() && TruePassthru == FalseReg)) {
688 // If True's passthru != False, check if it uses False in another operand
689 // and try to commute it.
690 int OtherIdx = True.findRegisterUseOperandIdx(FalseReg, TRI);
691 if (OtherIdx == -1)
692 return false;
693 unsigned OpIdx1 = OtherIdx;
694 unsigned OpIdx2 = True.getNumExplicitDefs();
695 if (!TII->findCommutedOpIndices(True, OpIdx1, OpIdx2))
696 return false;
697 NeedsCommute = {OpIdx1, OpIdx2};
698 }
699
700 // Make sure it doesn't raise any observable fp exceptions, since changing the
701 // active elements will affect how fflags is set.
702 if (True.hasUnmodeledSideEffects() || True.mayRaiseFPException())
703 return false;
704
705 const MachineOperand &VMergeVL =
706 MI.getOperand(RISCVII::getVLOpNum(MI.getDesc()));
707 const MachineOperand &TrueVL =
709
710 MachineOperand MinVL = MachineOperand::CreateImm(0);
711 if (RISCV::isVLKnownLE(TrueVL, VMergeVL))
712 MinVL = TrueVL;
713 else if (RISCV::isVLKnownLE(VMergeVL, TrueVL))
714 MinVL = VMergeVL;
715 else if (!TruePassthru && !True.mayLoadOrStore())
716 // If True's passthru is undef, we can use vmerge's vl.
717 MinVL = VMergeVL;
718 else
719 return false;
720
721 unsigned RVVTSFlags =
722 TII->get(RISCV::getRVVMCOpcode(True.getOpcode())).TSFlags;
723 if (RISCVII::elementsDependOnVL(RVVTSFlags) && !TrueVL.isIdenticalTo(MinVL))
724 return false;
725 if (RISCVII::elementsDependOnMask(RVVTSFlags) && !isAllOnesMask(Mask))
726 return false;
727
728 // Use a tumu policy, relaxing it to tail agnostic provided that the passthru
729 // operand is undefined.
730 //
731 // However, if the VL became smaller than what the vmerge had originally, then
732 // elements past VL that were previously in the vmerge's body will have moved
733 // to the tail. In that case we always need to use tail undisturbed to
734 // preserve them.
736 if (!PassthruReg && RISCV::isVLKnownLE(VMergeVL, MinVL))
738
740 "Foldable unmasked pseudo should have a policy op already");
741
742 // Make sure Mask, False and MinVL dominate True and its copies, otherwise
743 // move down True so it does.
744 if (!ensureDominates({&MaskOp, &FalseOp, &MinVL}, True))
745 return false;
746
747 if (NeedsCommute) {
748 auto [OpIdx1, OpIdx2] = *NeedsCommute;
749 [[maybe_unused]] bool Commuted =
750 TII->commuteInstruction(True, /*NewMI=*/false, OpIdx1, OpIdx2);
751 assert(Commuted && "Failed to commute True?");
752 Info = RISCV::lookupMaskedIntrinsicByUnmasked(True.getOpcode());
753 }
754
755 True.setDesc(TII->get(Info->MaskedPseudo));
756
757 // Insert the mask operand.
758 // TODO: Increment MaskOpIdx by number of explicit defs?
759 True.insert(True.operands_begin() + Info->MaskOpIdx +
760 True.getNumExplicitDefs(),
761 MachineOperand::CreateReg(MaskOp.getReg(), false));
762
763 // Update the passthru, AVL and policy.
764 True.getOperand(True.getNumExplicitDefs()).setReg(FalseReg);
766 True.insert(True.operands_begin() + RISCVII::getVLOpNum(True.getDesc()),
767 MinVL);
769
770 MRI->replaceRegWith(True.getOperand(0).getReg(), MI.getOperand(0).getReg());
771 // Now that True is masked, constrain its operands from vr -> vrnov0.
772 for (MachineOperand &MO : True.explicit_operands()) {
773 if (!MO.isReg() || !MO.getReg().isVirtual())
774 continue;
776 MO.getReg(), True.getRegClassConstraint(MO.getOperandNo(), TII, TRI));
777 }
778 // We should clear the IsKill flag since we have a new use now.
779 MRI->clearKillFlags(FalseReg);
780 MI.eraseFromParent();
781
782 // Cleanup all the COPYs on True's value. We have to manually do this because
783 // sometimes sinking True causes these COPY to be invalid (use before define).
784 for (MachineInstr *TrueCopy : TrueCopies)
785 TrueCopy->eraseFromParent();
786
787 return true;
788}
789
790bool RISCVVectorPeephole::runOnMachineFunction(MachineFunction &MF) {
791 if (skipFunction(MF.getFunction()))
792 return false;
793
794 // Skip if the vector extension is not enabled.
795 ST = &MF.getSubtarget<RISCVSubtarget>();
796 if (!ST->hasVInstructions())
797 return false;
798
799 TII = ST->getInstrInfo();
800 MRI = &MF.getRegInfo();
801 TRI = MRI->getTargetRegisterInfo();
802
803 bool Changed = false;
804
805 for (MachineBasicBlock &MBB : MF) {
806 for (MachineInstr &MI : make_early_inc_range(MBB))
807 Changed |= foldVMergeToMask(MI);
808
809 for (MachineInstr &MI : make_early_inc_range(MBB)) {
810 Changed |= convertToVLMAX(MI);
811 Changed |= convertToUnmasked(MI);
812 Changed |= convertToWholeRegister(MI);
813 Changed |= convertAllOnesVMergeToVMv(MI);
814 Changed |= convertSameMaskVMergeToVMv(MI);
815 if (foldUndefPassthruVMV_V_V(MI)) {
816 Changed |= true;
817 continue; // MI is erased
818 }
819 Changed |= foldVMV_V_V(MI);
820 }
821 }
822
823 return Changed;
824}
825
827 return new RISCVVectorPeephole();
828}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
aarch64 promote const
MachineBasicBlock & MBB
static uint64_t getConstant(const Value *IndexValue)
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
#define DEBUG_TYPE
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
#define I(x, y, z)
Definition MD5.cpp:57
Register Reg
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
if(PassOpts->AAPipeline)
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
static bool strictlyDominates(MachineBasicBlock::const_iterator A, MachineBasicBlock::const_iterator B)
Given A and B are in the same MBB, returns true if A comes before B.
#define CASE_WHOLE_REGISTER_LMUL(lmul)
SI Lower i1 Copies
Represent the analysis usage information of a pass.
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition Pass.cpp:275
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
MachineInstrBundleIterator< const MachineInstr > const_iterator
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
Properties which a MachineFunction may have at a given point in time.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
Representation of each machine instruction.
mop_iterator operands_begin()
bool mayRaiseFPException() const
Return true if this instruction could possibly raise a floating-point exception.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
bool mayLoadOrStore(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly read or modify memory.
bool isCopy() const
const MachineBasicBlock * getParent() const
LLVM_ABI int findRegisterUseOperandIdx(Register Reg, const TargetRegisterInfo *TRI, bool isKill=false) const
Returns the operand index that is a use of the specific register or -1 if it is not found.
const MCInstrDesc & getDesc() const
Returns the target instruction descriptor of this MachineInstr.
LLVM_ABI bool hasUnmodeledSideEffects() const
Return true if this instruction has side effects that are not modeled by mayLoad / mayStore,...
LLVM_ABI void insert(mop_iterator InsertBefore, ArrayRef< MachineOperand > Ops)
Inserts Ops BEFORE It. Can untie/retie tied operands.
LLVM_ABI void setDesc(const MCInstrDesc &TID)
Replace the instruction descriptor (thus opcode) of the current instruction with a new one.
LLVM_ABI unsigned getNumExplicitDefs() const
Returns the number of non-implicit definitions.
mop_range explicit_operands()
LLVM_ABI void removeOperand(unsigned OpNo)
Erase an operand from an instruction, leaving it with one fewer operand than it started with.
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI const TargetRegisterClass * getRegClassConstraint(unsigned OpIdx, const TargetInstrInfo *TII, const TargetRegisterInfo *TRI) const
Compute the static register class constraint for operand OpIdx.
MachineOperand class - Representation of each machine instruction operand.
LLVM_ABI unsigned getOperandNo() const
Returns the index of this operand in the instruction that it belongs to.
void setImm(int64_t immVal)
int64_t getImm() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
LLVM_ABI void ChangeToImmediate(int64_t ImmVal, unsigned TargetFlags=0)
ChangeToImmediate - Replace this operand with a new immediate operand of the specified value.
static MachineOperand CreateImm(int64_t Val)
Register getReg() const
getReg - Returns the register number.
LLVM_ABI bool isIdenticalTo(const MachineOperand &Other) const
Returns true if this operand is identical to the specified operand except for liveness related flags ...
static MachineOperand CreateReg(Register Reg, bool isDef, bool isImp=false, bool isKill=false, bool isDead=false, bool isUndef=false, bool isEarlyClobber=false, unsigned SubReg=0, bool isDebug=false, bool isInternalRead=false, bool isRenamable=false)
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI bool hasOneNonDBGUse(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug use of the specified register.
LLVM_ABI bool recomputeRegClass(Register Reg)
recomputeRegClass - Try to find a legal super-class of Reg's register class that still satisfies the ...
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual register.
LLVM_ABI void clearKillFlags(Register Reg) const
clearKillFlags - Iterate over all the uses of the given register and clear the kill flag from the Mac...
LLVM_ABI MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
bool hasOneUse(Register RegNo) const
hasOneUse - Return true if there is exactly one instruction using the specified register.
const TargetRegisterInfo * getTargetRegisterInfo() const
LLVM_ABI const TargetRegisterClass * constrainRegClass(Register Reg, const TargetRegisterClass *RC, unsigned MinNumRegs=0)
constrainRegClass - Constrain the register class of the specified virtual register to be a common sub...
LLVM_ABI void replaceRegWith(Register FromReg, Register ToReg)
replaceRegWith - Replace all instances of FromReg with ToReg in the machine function.
LLVM_ABI MachineInstr * getUniqueVRegDef(Register Reg) const
getUniqueVRegDef - Return the unique machine instr that defines the specified virtual register or nul...
static bool isSafeToMove(const MachineInstr &From, const MachineBasicBlock::iterator &To)
Return true if moving From down to To won't cause any physical register reads or writes to be clobber...
bool hasVInstructions() const
std::optional< unsigned > getRealVLen() const
const RISCVInstrInfo * getInstrInfo() const override
Wrapper class representing virtual and physical registers.
Definition Register.h:20
constexpr bool isValid() const
Definition Register.h:112
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
Definition Register.h:79
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
TargetInstrInfo - Interface to description of machine instruction set.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
A Use represents the edge between a Value definition and its users.
Definition Use.h:35
Value * getOperand(unsigned i) const
Definition User.h:207
Changed
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
static unsigned getVecPolicyOpNum(const MCInstrDesc &Desc)
static RISCVVType::VLMUL getLMul(uint64_t TSFlags)
static unsigned getVLOpNum(const MCInstrDesc &Desc)
static bool hasVLOp(uint64_t TSFlags)
static bool elementsDependOnMask(uint64_t TSFlags)
static bool hasVecPolicyOp(uint64_t TSFlags)
static unsigned getSEWOpNum(const MCInstrDesc &Desc)
static bool elementsDependOnVL(uint64_t TSFlags)
static bool hasSEWOp(uint64_t TSFlags)
static bool isFirstDefTiedToFirstUse(const MCInstrDesc &Desc)
LLVM_ABI std::pair< unsigned, bool > decodeVLMUL(VLMUL VLMul)
static bool isValidSEW(unsigned SEW)
bool isVLKnownLE(const MachineOperand &LHS, const MachineOperand &RHS)
Given two VL operands, do we know that LHS <= RHS?
unsigned getRVVMCOpcode(unsigned RVVPseudoOpcode)
unsigned getDestLog2EEW(const MCInstrDesc &Desc, unsigned Log2SEW)
static constexpr int64_t VLMaxSentinel
NodeAddr< DefNode * > Def
Definition RDFGraph.h:384
NodeAddr< UseNode * > Use
Definition RDFGraph.h:385
This is an optimization pass for GlobalISel generic memory operations.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
Definition STLExtras.h:633
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
ArrayRef(const T &OneElt) -> ArrayRef< T >
FunctionPass * createRISCVVectorPeepholePass()