llvm.org GIT mirror llvm / a3db459
[ARM] GlobalISel: Simplify inst selector code. NFC Refactor CmpHelper into something simpler. It was overkill to use templates for this - instead, use a simple CmpConstants structure to hold the opcodes and other constants that are different when selecting int / float / double comparisons. Also, extract some of the helpers that were in CmpHelper into ARMInstructionSelector and make use of some of them when selecting other things than just compares. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@307766 91177308-0d34-0410-b5e6-96231b3b80d8 Diana Picus 3 years ago
1 changed file(s) with 155 addition(s) and 210 deletion(s). Raw diff Collapse all Expand all
4343 private:
4444 bool selectImpl(MachineInstr &I) const;
4545
46 template struct CmpHelper;
47
48 template
49 bool selectCmp(MachineInstrBuilder &MIB, const ARMBaseInstrInfo &TII,
50 MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
51 const RegisterBankInfo &RBI) const;
52
53 bool selectSelect(MachineInstrBuilder &MIB, const ARMBaseInstrInfo &TII,
54 MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
55 const RegisterBankInfo &RBI) const;
46 struct CmpConstants;
47 struct InsertInfo;
48
49 bool selectCmp(CmpConstants Helper, MachineInstrBuilder &MIB,
50 MachineRegisterInfo &MRI) const;
51
52 // Helper for inserting a comparison sequence that sets \p ResReg to either 1
53 // if \p LHSReg and \p RHSReg are in the relationship defined by \p Cond, or
54 // \p PrevRes otherwise. In essence, it computes PrevRes OR (LHS Cond RHS).
55 bool insertComparison(CmpConstants Helper, InsertInfo I, unsigned ResReg,
56 ARMCC::CondCodes Cond, unsigned LHSReg, unsigned RHSReg,
57 unsigned PrevRes) const;
58
59 // Set \p DestReg to \p Constant.
60 void putConstant(InsertInfo I, unsigned DestReg, unsigned Constant) const;
61
62 bool selectSelect(MachineInstrBuilder &MIB, MachineRegisterInfo &MRI) const;
63
64 // Check if the types match and both operands have the expected size and
65 // register bank.
66 bool validOpRegPair(MachineRegisterInfo &MRI, unsigned LHS, unsigned RHS,
67 unsigned ExpectedSize, unsigned ExpectedRegBankID) const;
68
69 // Check if the register has the expected size and register bank.
70 bool validReg(MachineRegisterInfo &MRI, unsigned Reg, unsigned ExpectedSize,
71 unsigned ExpectedRegBankID) const;
5672
5773 const ARMBaseInstrInfo &TII;
5874 const ARMBaseRegisterInfo &TRI;
325341 return Preds;
326342 }
327343
328 template struct ARMInstructionSelector::CmpHelper {
329 CmpHelper(const ARMInstructionSelector &Selector, MachineInstrBuilder &MIB,
330 const ARMBaseInstrInfo &TII, MachineRegisterInfo &MRI,
331 const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
332 : MBB(*MIB->getParent()), InsertBefore(std::next(MIB->getIterator())),
333 DbgLoc(MIB->getDebugLoc()), TII(TII), MRI(MRI), TRI(TRI), RBI(RBI),
334 Selector(Selector) {}
344 struct ARMInstructionSelector::CmpConstants {
345 CmpConstants(unsigned CmpOpcode, unsigned FlagsOpcode, unsigned OpRegBank,
346 unsigned OpSize)
347 : ComparisonOpcode(CmpOpcode), ReadFlagsOpcode(FlagsOpcode),
348 OperandRegBankID(OpRegBank), OperandSize(OpSize) {}
335349
336350 // The opcode used for performing the comparison.
337 static const unsigned ComparisonOpcode;
351 const unsigned ComparisonOpcode;
338352
339353 // The opcode used for reading the flags set by the comparison. May be
340354 // ARM::INSTRUCTION_LIST_END if we don't need to read the flags.
341 static const unsigned ReadFlagsOpcode;
342
343 // The opcode used for selecting the result register, based on the value
344 // of the flags.
345 static const unsigned SetResultOpcode = ARM::MOVCCi;
355 const unsigned ReadFlagsOpcode;
346356
347357 // The assumed register bank ID for the operands.
348 static const unsigned OperandRegBankID;
358 const unsigned OperandRegBankID;
349359
350360 // The assumed size in bits for the operands.
351 static const unsigned OperandSize;
352
353 // The assumed register bank ID for the result.
354 static const unsigned ResultRegBankID = ARM::GPRRegBankID;
355
356 unsigned getZeroRegister() {
357 unsigned Reg = MRI.createVirtualRegister(&ARM::GPRRegClass);
358 putConstant(Reg, 0);
359 return Reg;
360 }
361
362 void putConstant(unsigned DestReg, unsigned Constant) {
363 (void)BuildMI(MBB, InsertBefore, DbgLoc, TII.get(ARM::MOVi))
364 .addDef(DestReg)
365 .addImm(Constant)
366 .add(predOps(ARMCC::AL))
367 .add(condCodeOp());
368 }
369
370 bool insertComparison(unsigned ResReg, ARMCC::CondCodes Cond, unsigned LHSReg,
371 unsigned RHSReg, unsigned PrevRes) {
372
373 // Perform the comparison.
374 auto CmpI = BuildMI(MBB, InsertBefore, DbgLoc, TII.get(ComparisonOpcode))
375 .addUse(LHSReg)
376 .addUse(RHSReg)
377 .add(predOps(ARMCC::AL));
378 if (!Selector.constrainSelectedInstRegOperands(*CmpI, TII, TRI, RBI))
379 return false;
380
381 // Read the comparison flags (if necessary).
382 if (ReadFlagsOpcode != ARM::INSTRUCTION_LIST_END) {
383 auto ReadI = BuildMI(MBB, InsertBefore, DbgLoc, TII.get(ReadFlagsOpcode))
384 .add(predOps(ARMCC::AL));
385 if (!Selector.constrainSelectedInstRegOperands(*ReadI, TII, TRI, RBI))
386 return false;
387 }
388
389 // Select either 1 or the previous result based on the value of the flags.
390 auto Mov1I = BuildMI(MBB, InsertBefore, DbgLoc, TII.get(SetResultOpcode))
391 .addDef(ResReg)
392 .addUse(PrevRes)
393 .addImm(1)
394 .add(predOps(Cond, ARM::CPSR));
395 if (!Selector.constrainSelectedInstRegOperands(*Mov1I, TII, TRI, RBI))
396 return false;
397
398 return true;
399 }
400
401 bool validateOpRegs(unsigned LHSReg, unsigned RHSReg) {
402 return MRI.getType(LHSReg) == MRI.getType(RHSReg) &&
403 validateOpReg(LHSReg, MRI, TRI, RBI) &&
404 validateOpReg(RHSReg, MRI, TRI, RBI);
405 }
406
407 bool validateResReg(unsigned ResReg) {
408 if (MRI.getType(ResReg).getSizeInBits() != 1) {
409 DEBUG(dbgs() << "Unsupported size for comparison operand");
410 return false;
411 }
412
413 if (RBI.getRegBank(ResReg, MRI, TRI)->getID() != ResultRegBankID) {
414 DEBUG(dbgs() << "Unsupported register bank for comparison operand");
415 return false;
416 }
417
418 return true;
419 }
420
421 private:
422 bool validateOpReg(unsigned OpReg, MachineRegisterInfo &MRI,
423 const TargetRegisterInfo &TRI,
424 const RegisterBankInfo &RBI) {
425 if (MRI.getType(OpReg).getSizeInBits() != OperandSize) {
426 DEBUG(dbgs() << "Unsupported size for comparison operand");
427 return false;
428 }
429
430 if (RBI.getRegBank(OpReg, MRI, TRI)->getID() != OperandRegBankID) {
431 DEBUG(dbgs() << "Unsupported register bank for comparison operand");
432 return false;
433 }
434
435 return true;
436 }
361 const unsigned OperandSize;
362 };
363
364 struct ARMInstructionSelector::InsertInfo {
365 InsertInfo(MachineInstrBuilder &MIB)
366 : MBB(*MIB->getParent()), InsertBefore(std::next(MIB->getIterator())),
367 DbgLoc(MIB->getDebugLoc()) {}
437368
438369 MachineBasicBlock &MBB;
439 MachineBasicBlock::instr_iterator InsertBefore;
370 const MachineBasicBlock::instr_iterator InsertBefore;
440371 const DebugLoc &DbgLoc;
441
442 const ARMBaseInstrInfo &TII;
443 MachineRegisterInfo &MRI;
444 const TargetRegisterInfo &TRI;
445 const RegisterBankInfo &RBI;
446
447 const ARMInstructionSelector &Selector;
448372 };
449373
450 // Specialize the opcode to be used for comparing different types of operands.
451 template <>
452 const unsigned ARMInstructionSelector::CmpHelper::ComparisonOpcode =
453 ARM::CMPrr;
454 template <>
455 const unsigned ARMInstructionSelector::CmpHelper::ComparisonOpcode =
456 ARM::VCMPS;
457 template <>
458 const unsigned ARMInstructionSelector::CmpHelper::ComparisonOpcode =
459 ARM::VCMPD;
460
461 // Specialize the opcode to be used for reading the comparison flags for
462 // different types of operands.
463 template <>
464 const unsigned ARMInstructionSelector::CmpHelper::ReadFlagsOpcode =
465 ARM::INSTRUCTION_LIST_END;
466 template <>
467 const unsigned ARMInstructionSelector::CmpHelper::ReadFlagsOpcode =
468 ARM::FMSTAT;
469 template <>
470 const unsigned ARMInstructionSelector::CmpHelper::ReadFlagsOpcode =
471 ARM::FMSTAT;
472
473 // Specialize the register bank where the operands of the comparison are assumed
474 // to live.
475 template <>
476 const unsigned ARMInstructionSelector::CmpHelper::OperandRegBankID =
477 ARM::GPRRegBankID;
478 template <>
479 const unsigned ARMInstructionSelector::CmpHelper::OperandRegBankID =
480 ARM::FPRRegBankID;
481 template <>
482 const unsigned ARMInstructionSelector::CmpHelper::OperandRegBankID =
483 ARM::FPRRegBankID;
484
485 // Specialize the size that the operands of the comparison are assumed to have.
486 template <>
487 const unsigned ARMInstructionSelector::CmpHelper::OperandSize = 32;
488 template <>
489 const unsigned ARMInstructionSelector::CmpHelper::OperandSize = 32;
490 template <>
491 const unsigned ARMInstructionSelector::CmpHelper::OperandSize = 64;
492
493 template
494 bool ARMInstructionSelector::selectCmp(MachineInstrBuilder &MIB,
495 const ARMBaseInstrInfo &TII,
496 MachineRegisterInfo &MRI,
497 const TargetRegisterInfo &TRI,
498 const RegisterBankInfo &RBI) const {
499 auto Helper = CmpHelper(*this, MIB, TII, MRI, TRI, RBI);
374 void ARMInstructionSelector::putConstant(InsertInfo I, unsigned DestReg,
375 unsigned Constant) const {
376 (void)BuildMI(I.MBB, I.InsertBefore, I.DbgLoc, TII.get(ARM::MOVi))
377 .addDef(DestReg)
378 .addImm(Constant)
379 .add(predOps(ARMCC::AL))
380 .add(condCodeOp());
381 }
382
383 bool ARMInstructionSelector::validOpRegPair(MachineRegisterInfo &MRI,
384 unsigned LHSReg, unsigned RHSReg,
385 unsigned ExpectedSize,
386 unsigned ExpectedRegBankID) const {
387 return MRI.getType(LHSReg) == MRI.getType(RHSReg) &&
388 validReg(MRI, LHSReg, ExpectedSize, ExpectedRegBankID) &&
389 validReg(MRI, RHSReg, ExpectedSize, ExpectedRegBankID);
390 }
391
392 bool ARMInstructionSelector::validReg(MachineRegisterInfo &MRI, unsigned Reg,
393 unsigned ExpectedSize,
394 unsigned ExpectedRegBankID) const {
395 if (MRI.getType(Reg).getSizeInBits() != ExpectedSize) {
396 DEBUG(dbgs() << "Unexpected size for register");
397 return false;
398 }
399
400 if (RBI.getRegBank(Reg, MRI, TRI)->getID() != ExpectedRegBankID) {
401 DEBUG(dbgs() << "Unexpected register bank for register");
402 return false;
403 }
404
405 return true;
406 }
407
408 bool ARMInstructionSelector::selectCmp(CmpConstants Helper,
409 MachineInstrBuilder &MIB,
410 MachineRegisterInfo &MRI) const {
411 const InsertInfo I(MIB);
500412
501413 auto ResReg = MIB->getOperand(0).getReg();
502 if (!Helper.validateResReg(ResReg))
414 if (!validReg(MRI, ResReg, 1, ARM::GPRRegBankID))
503415 return false;
504416
505417 auto Cond =
506418 static_cast(MIB->getOperand(1).getPredicate());
507419 if (Cond == CmpInst::FCMP_TRUE || Cond == CmpInst::FCMP_FALSE) {
508 Helper.putConstant(ResReg, Cond == CmpInst::FCMP_TRUE ? 1 : 0);
420 putConstant(I, ResReg, Cond == CmpInst::FCMP_TRUE ? 1 : 0);
509421 MIB->eraseFromParent();
510422 return true;
511423 }
512424
513425 auto LHSReg = MIB->getOperand(2).getReg();
514426 auto RHSReg = MIB->getOperand(3).getReg();
515 if (!Helper.validateOpRegs(LHSReg, RHSReg))
427 if (!validOpRegPair(MRI, LHSReg, RHSReg, Helper.OperandSize,
428 Helper.OperandRegBankID))
516429 return false;
517430
518431 auto ARMConds = getComparePreds(Cond);
519 auto ZeroReg = Helper.getZeroRegister();
432 auto ZeroReg = MRI.createVirtualRegister(&ARM::GPRRegClass);
433 putConstant(I, ZeroReg, 0);
520434
521435 if (ARMConds.second == ARMCC::AL) {
522436 // Simple case, we only need one comparison and we're done.
523 if (!Helper.insertComparison(ResReg, ARMConds.first, LHSReg, RHSReg,
524 ZeroReg))
437 if (!insertComparison(Helper, I, ResReg, ARMConds.first, LHSReg, RHSReg,
438 ZeroReg))
525439 return false;
526440 } else {
527441 // Not so simple, we need two successive comparisons.
528442 auto IntermediateRes = MRI.createVirtualRegister(&ARM::GPRRegClass);
529 if (!Helper.insertComparison(IntermediateRes, ARMConds.first, LHSReg,
530 RHSReg, ZeroReg))
531 return false;
532 if (!Helper.insertComparison(ResReg, ARMConds.second, LHSReg, RHSReg,
533 IntermediateRes))
443 if (!insertComparison(Helper, I, IntermediateRes, ARMConds.first, LHSReg,
444 RHSReg, ZeroReg))
445 return false;
446 if (!insertComparison(Helper, I, ResReg, ARMConds.second, LHSReg, RHSReg,
447 IntermediateRes))
534448 return false;
535449 }
536450
538452 return true;
539453 }
540454
455 bool ARMInstructionSelector::insertComparison(CmpConstants Helper, InsertInfo I,
456 unsigned ResReg,
457 ARMCC::CondCodes Cond,
458 unsigned LHSReg, unsigned RHSReg,
459 unsigned PrevRes) const {
460 // Perform the comparison.
461 auto CmpI =
462 BuildMI(I.MBB, I.InsertBefore, I.DbgLoc, TII.get(Helper.ComparisonOpcode))
463 .addUse(LHSReg)
464 .addUse(RHSReg)
465 .add(predOps(ARMCC::AL));
466 if (!constrainSelectedInstRegOperands(*CmpI, TII, TRI, RBI))
467 return false;
468
469 // Read the comparison flags (if necessary).
470 if (Helper.ReadFlagsOpcode != ARM::INSTRUCTION_LIST_END) {
471 auto ReadI = BuildMI(I.MBB, I.InsertBefore, I.DbgLoc,
472 TII.get(Helper.ReadFlagsOpcode))
473 .add(predOps(ARMCC::AL));
474 if (!constrainSelectedInstRegOperands(*ReadI, TII, TRI, RBI))
475 return false;
476 }
477
478 // Select either 1 or the previous result based on the value of the flags.
479 auto Mov1I = BuildMI(I.MBB, I.InsertBefore, I.DbgLoc, TII.get(ARM::MOVCCi))
480 .addDef(ResReg)
481 .addUse(PrevRes)
482 .addImm(1)
483 .add(predOps(Cond, ARM::CPSR));
484 if (!constrainSelectedInstRegOperands(*Mov1I, TII, TRI, RBI))
485 return false;
486
487 return true;
488 }
489
541490 bool ARMInstructionSelector::selectSelect(MachineInstrBuilder &MIB,
542 const ARMBaseInstrInfo &TII,
543 MachineRegisterInfo &MRI,
544 const TargetRegisterInfo &TRI,
545 const RegisterBankInfo &RBI) const {
491 MachineRegisterInfo &MRI) const {
546492 auto &MBB = *MIB->getParent();
547493 auto InsertBefore = std::next(MIB->getIterator());
548494 auto &DbgLoc = MIB->getDebugLoc();
549495
550496 // Compare the condition to 0.
551497 auto CondReg = MIB->getOperand(1).getReg();
552 assert(MRI.getType(CondReg).getSizeInBits() == 1 &&
553 RBI.getRegBank(CondReg, MRI, TRI)->getID() == ARM::GPRRegBankID &&
498 assert(validReg(MRI, CondReg, 1, ARM::GPRRegBankID) &&
554499 "Unsupported types for select operation");
555500 auto CmpI = BuildMI(MBB, InsertBefore, DbgLoc, TII.get(ARM::CMPri))
556501 .addUse(CondReg)
564509 auto ResReg = MIB->getOperand(0).getReg();
565510 auto TrueReg = MIB->getOperand(2).getReg();
566511 auto FalseReg = MIB->getOperand(3).getReg();
567 assert(MRI.getType(ResReg) == MRI.getType(TrueReg) &&
568 MRI.getType(TrueReg) == MRI.getType(FalseReg) &&
569 MRI.getType(FalseReg).getSizeInBits() == 32 &&
570 RBI.getRegBank(TrueReg, MRI, TRI)->getID() == ARM::GPRRegBankID &&
571 RBI.getRegBank(FalseReg, MRI, TRI)->getID() == ARM::GPRRegBankID &&
512 assert(validOpRegPair(MRI, ResReg, TrueReg, 32, ARM::GPRRegBankID) &&
513 validOpRegPair(MRI, TrueReg, FalseReg, 32, ARM::GPRRegBankID) &&
572514 "Unsupported types for select operation");
573515 auto Mov1I = BuildMI(MBB, InsertBefore, DbgLoc, TII.get(ARM::MOVCCr))
574516 .addDef(ResReg)
683625 return selectCopy(I, TII, MRI, TRI, RBI);
684626 }
685627 case G_SELECT:
686 return selectSelect(MIB, TII, MRI, TRI, RBI);
687 case G_ICMP:
688 return selectCmp(MIB, TII, MRI, TRI, RBI);
628 return selectSelect(MIB, MRI);
629 case G_ICMP: {
630 CmpConstants Helper(ARM::CMPrr, ARM::INSTRUCTION_LIST_END,
631 ARM::GPRRegBankID, 32);
632 return selectCmp(Helper, MIB, MRI);
633 }
689634 case G_FCMP: {
690635 assert(TII.getSubtarget().hasVFP2() && "Can't select fcmp without VFP");
691636
692637 unsigned OpReg = I.getOperand(2).getReg();
693638 unsigned Size = MRI.getType(OpReg).getSizeInBits();
694 if (Size == 32)
695 return selectCmp(MIB, TII, MRI, TRI, RBI);
696 if (Size == 64) {
697 if (TII.getSubtarget().isFPOnlySP()) {
698 DEBUG(dbgs() << "Subtarget only supports single precision");
699 return false;
700 }
701 return selectCmp(MIB, TII, MRI, TRI, RBI);
702 }
703
704 DEBUG(dbgs() << "Unsupported size for G_FCMP operand");
705 return false;
639
640 if (Size == 64 && TII.getSubtarget().isFPOnlySP()) {
641 DEBUG(dbgs() << "Subtarget only supports single precision");
642 return false;
643 }
644 if (Size != 32 && Size != 64) {
645 DEBUG(dbgs() << "Unsupported size for G_FCMP operand");
646 return false;
647 }
648
649 CmpConstants Helper(Size == 32 ? ARM::VCMPS : ARM::VCMPD, ARM::FMSTAT,
650 ARM::FPRRegBankID, Size);
651 return selectCmp(Helper, MIB, MRI);
706652 }
707653 case G_GEP:
708654 I.setDesc(TII.get(ARM::ADDrr));
716662 break;
717663 case G_CONSTANT: {
718664 unsigned Reg = I.getOperand(0).getReg();
719 if (MRI.getType(Reg).getSizeInBits() != 32)
720 return false;
721
722 assert(RBI.getRegBank(Reg, MRI, TRI)->getID() == ARM::GPRRegBankID &&
723 "Expected constant to live in a GPR");
665
666 if (!validReg(MRI, Reg, 32, ARM::GPRRegBankID))
667 return false;
668
724669 I.setDesc(TII.get(ARM::MOVi));
725670 MIB.add(predOps(ARMCC::AL)).add(condCodeOp());
726671