OLD | NEW |
1 //===- subzero/src/IceTargetLoweringMIPS32.cpp - MIPS32 lowering ----------===// | 1 //===- subzero/src/IceTargetLoweringMIPS32.cpp - MIPS32 lowering ----------===// |
2 // | 2 // |
3 // The Subzero Code Generator | 3 // The Subzero Code Generator |
4 // | 4 // |
5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
7 // | 7 // |
8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
9 /// | 9 /// |
10 /// \file | 10 /// \file |
11 /// \brief Implements the TargetLoweringMIPS32 class, which consists almost | 11 /// \brief Implements the TargetLoweringMIPS32 class, which consists almost |
12 /// entirely of the lowering sequence for each high-level instruction. | 12 /// entirely of the lowering sequence for each high-level instruction. |
13 /// | 13 /// |
14 //===----------------------------------------------------------------------===// | 14 //===----------------------------------------------------------------------===// |
15 | 15 |
16 #include "IceTargetLoweringMIPS32.h" | 16 #include "IceTargetLoweringMIPS32.h" |
17 | 17 |
18 #include "IceCfg.h" | 18 #include "IceCfg.h" |
19 #include "IceCfgNode.h" | 19 #include "IceCfgNode.h" |
20 #include "IceClFlags.h" | 20 #include "IceClFlags.h" |
21 #include "IceDefs.h" | 21 #include "IceDefs.h" |
22 #include "IceELFObjectWriter.h" | 22 #include "IceELFObjectWriter.h" |
23 #include "IceGlobalInits.h" | 23 #include "IceGlobalInits.h" |
24 #include "IceInstMIPS32.h" | 24 #include "IceInstMIPS32.h" |
| 25 #include "IceInstVarIter.h" |
25 #include "IceLiveness.h" | 26 #include "IceLiveness.h" |
26 #include "IceOperand.h" | 27 #include "IceOperand.h" |
27 #include "IcePhiLoweringImpl.h" | 28 #include "IcePhiLoweringImpl.h" |
28 #include "IceRegistersMIPS32.h" | 29 #include "IceRegistersMIPS32.h" |
29 #include "IceTargetLoweringMIPS32.def" | 30 #include "IceTargetLoweringMIPS32.def" |
30 #include "IceUtils.h" | 31 #include "IceUtils.h" |
31 #include "llvm/Support/MathExtras.h" | 32 #include "llvm/Support/MathExtras.h" |
32 | 33 |
33 namespace MIPS32 { | 34 namespace MIPS32 { |
34 std::unique_ptr<::Ice::TargetLowering> createTargetLowering(::Ice::Cfg *Func) { | 35 std::unique_ptr<::Ice::TargetLowering> createTargetLowering(::Ice::Cfg *Func) { |
(...skipping 771 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
806 _mov(Dest, SrcR); | 807 _mov(Dest, SrcR); |
807 } | 808 } |
808 } | 809 } |
809 } | 810 } |
810 | 811 |
811 void TargetMIPS32::lowerBr(const InstBr *Instr) { | 812 void TargetMIPS32::lowerBr(const InstBr *Instr) { |
812 if (Instr->isUnconditional()) { | 813 if (Instr->isUnconditional()) { |
813 _br(Instr->getTargetUnconditional()); | 814 _br(Instr->getTargetUnconditional()); |
814 return; | 815 return; |
815 } | 816 } |
816 UnimplementedLoweringError(this, Instr); | 817 CfgNode *TargetTrue = Instr->getTargetTrue(); |
| 818 CfgNode *TargetFalse = Instr->getTargetFalse(); |
| 819 Operand *Boolean = Instr->getCondition(); |
| 820 const Inst *Producer = Computations.getProducerOf(Boolean); |
| 821 if (Producer == nullptr) { |
| 822 // Since we don't know the producer of this boolean we will assume its |
| 823 // producer will keep it in positive logic and just emit beqz with this |
| 824 // Boolean as an operand. |
| 825 auto *BooleanR = legalizeToReg(Boolean); |
| 826 _br(TargetTrue, TargetFalse, BooleanR, CondMIPS32::Cond::EQZ); |
| 827 return; |
| 828 } |
| 829 if (Producer->getKind() == Inst::Icmp) { |
| 830 const InstIcmp *CompareInst = llvm::cast<InstIcmp>(Producer); |
| 831 Operand *Src0 = CompareInst->getSrc(0); |
| 832 Operand *Src1 = CompareInst->getSrc(1); |
| 833 const Type Src0Ty = Src0->getType(); |
| 834 assert(Src0Ty == Src1->getType()); |
| 835 if (Src0Ty == IceType_i64) { |
| 836 UnimplementedLoweringError(this, Instr); |
| 837 return; |
| 838 } |
| 839 auto *Src0R = legalizeToReg(Src0); |
| 840 auto *Src1R = legalizeToReg(Src1); |
| 841 auto *DestT = makeReg(Src0Ty); |
| 842 switch (CompareInst->getCondition()) { |
| 843 default: |
| 844 break; |
| 845 case InstIcmp::Eq: { |
| 846 _br(TargetTrue, TargetFalse, Src0R, Src1R, CondMIPS32::Cond::NE); |
| 847 break; |
| 848 } |
| 849 case InstIcmp::Ne: { |
| 850 _br(TargetTrue, TargetFalse, Src0R, Src1R, CondMIPS32::Cond::EQ); |
| 851 break; |
| 852 } |
| 853 case InstIcmp::Ugt: { |
| 854 _sltu(DestT, Src1R, Src0R); |
| 855 _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::EQZ); |
| 856 break; |
| 857 } |
| 858 case InstIcmp::Uge: { |
| 859 _sltu(DestT, Src0R, Src1R); |
| 860 _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::NEZ); |
| 861 break; |
| 862 } |
| 863 case InstIcmp::Ult: { |
| 864 _sltu(DestT, Src0R, Src1R); |
| 865 _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::EQZ); |
| 866 break; |
| 867 } |
| 868 case InstIcmp::Ule: { |
| 869 _sltu(DestT, Src1R, Src0R); |
| 870 _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::NEZ); |
| 871 break; |
| 872 } |
| 873 case InstIcmp::Sgt: { |
| 874 _slt(DestT, Src1R, Src0R); |
| 875 _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::EQZ); |
| 876 break; |
| 877 } |
| 878 case InstIcmp::Sge: { |
| 879 _slt(DestT, Src0R, Src1R); |
| 880 _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::NEZ); |
| 881 break; |
| 882 } |
| 883 case InstIcmp::Slt: { |
| 884 _slt(DestT, Src0R, Src1R); |
| 885 _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::EQZ); |
| 886 break; |
| 887 } |
| 888 case InstIcmp::Sle: { |
| 889 _slt(DestT, Src1R, Src0R); |
| 890 _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::NEZ); |
| 891 break; |
| 892 } |
| 893 } |
| 894 } |
817 } | 895 } |
818 | 896 |
819 void TargetMIPS32::lowerCall(const InstCall *Instr) { | 897 void TargetMIPS32::lowerCall(const InstCall *Instr) { |
820 // TODO(rkotler): assign arguments to registers and stack. Also reserve stack. | 898 // TODO(rkotler): assign arguments to registers and stack. Also reserve stack. |
821 if (Instr->getNumArgs()) { | 899 if (Instr->getNumArgs()) { |
822 UnimplementedLoweringError(this, Instr); | 900 UnimplementedLoweringError(this, Instr); |
823 return; | 901 return; |
824 } | 902 } |
825 // Generate the call instruction. Assign its result to a temporary with high | 903 // Generate the call instruction. Assign its result to a temporary with high |
826 // register allocation weight. | 904 // register allocation weight. |
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1024 } | 1102 } |
1025 case InstIcmp::Sgt: { | 1103 case InstIcmp::Sgt: { |
1026 auto *DestT = I32Reg(); | 1104 auto *DestT = I32Reg(); |
1027 _slt(DestT, Src1R, Src0R); | 1105 _slt(DestT, Src1R, Src0R); |
1028 _mov(Dest, DestT); | 1106 _mov(Dest, DestT); |
1029 return; | 1107 return; |
1030 } | 1108 } |
1031 case InstIcmp::Sge: { | 1109 case InstIcmp::Sge: { |
1032 auto *DestT = I32Reg(); | 1110 auto *DestT = I32Reg(); |
1033 auto *T = I32Reg(); | 1111 auto *T = I32Reg(); |
1034 _slt(T, Src1R, Src0R); | 1112 _slt(T, Src0R, Src1R); |
1035 _xori(DestT, T, 1); | 1113 _xori(DestT, T, 1); |
1036 _mov(Dest, DestT); | 1114 _mov(Dest, DestT); |
1037 return; | 1115 return; |
1038 } | 1116 } |
1039 case InstIcmp::Slt: { | 1117 case InstIcmp::Slt: { |
1040 auto *DestT = I32Reg(); | 1118 auto *DestT = I32Reg(); |
1041 _slt(DestT, Src0R, Src1R); | 1119 _slt(DestT, Src0R, Src1R); |
1042 _mov(Dest, DestT); | 1120 _mov(Dest, DestT); |
1043 return; | 1121 return; |
1044 } | 1122 } |
(...skipping 358 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1403 // RegNum is required and Var->getRegNum() doesn't match. | 1481 // RegNum is required and Var->getRegNum() doesn't match. |
1404 if ((!(Allowed & Legal_Mem) && !MustHaveRegister) || | 1482 if ((!(Allowed & Legal_Mem) && !MustHaveRegister) || |
1405 (RegNum.hasValue() && RegNum != Var->getRegNum())) { | 1483 (RegNum.hasValue() && RegNum != Var->getRegNum())) { |
1406 From = copyToReg(From, RegNum); | 1484 From = copyToReg(From, RegNum); |
1407 } | 1485 } |
1408 return From; | 1486 return From; |
1409 } | 1487 } |
1410 return From; | 1488 return From; |
1411 } | 1489 } |
1412 | 1490 |
| 1491 namespace BoolFolding { |
| 1492 // TODO(sagar.thakur): Add remaining instruction kinds to shouldTrackProducer() |
| 1493 // and isValidConsumer() |
| 1494 bool shouldTrackProducer(const Inst &Instr) { |
| 1495 return Instr.getKind() == Inst::Icmp; |
| 1496 } |
| 1497 |
| 1498 bool isValidConsumer(const Inst &Instr) { return Instr.getKind() == Inst::Br; } |
| 1499 } // end of namespace BoolFolding |
| 1500 |
| 1501 void TargetMIPS32::ComputationTracker::recordProducers(CfgNode *Node) { |
| 1502 for (Inst &Instr : Node->getInsts()) { |
| 1503 if (Instr.isDeleted()) |
| 1504 continue; |
| 1505 // Check whether Instr is a valid producer. |
| 1506 Variable *Dest = Instr.getDest(); |
| 1507 if (Dest // only consider instructions with an actual dest var; and |
| 1508 && Dest->getType() == IceType_i1 // only bool-type dest vars; and |
| 1509 && BoolFolding::shouldTrackProducer(Instr)) { // white-listed instr. |
| 1510 KnownComputations.emplace(Dest->getIndex(), |
| 1511 ComputationEntry(&Instr, IceType_i1)); |
| 1512 } |
| 1513 // Check each src variable against the map. |
| 1514 FOREACH_VAR_IN_INST(Var, Instr) { |
| 1515 SizeT VarNum = Var->getIndex(); |
| 1516 auto ComputationIter = KnownComputations.find(VarNum); |
| 1517 if (ComputationIter == KnownComputations.end()) { |
| 1518 continue; |
| 1519 } |
| 1520 |
| 1521 ++ComputationIter->second.NumUses; |
| 1522 switch (ComputationIter->second.ComputationType) { |
| 1523 default: |
| 1524 KnownComputations.erase(VarNum); |
| 1525 continue; |
| 1526 case IceType_i1: |
| 1527 if (!BoolFolding::isValidConsumer(Instr)) { |
| 1528 KnownComputations.erase(VarNum); |
| 1529 continue; |
| 1530 } |
| 1531 break; |
| 1532 } |
| 1533 |
| 1534 if (Instr.isLastUse(Var)) { |
| 1535 ComputationIter->second.IsLiveOut = false; |
| 1536 } |
| 1537 } |
| 1538 } |
| 1539 |
| 1540 for (auto Iter = KnownComputations.begin(), End = KnownComputations.end(); |
| 1541 Iter != End;) { |
| 1542 // Disable the folding if its dest may be live beyond this block. |
| 1543 if (Iter->second.IsLiveOut || Iter->second.NumUses > 1) { |
| 1544 Iter = KnownComputations.erase(Iter); |
| 1545 continue; |
| 1546 } |
| 1547 |
| 1548 // Mark as "dead" rather than outright deleting. This is so that other |
| 1549 // peephole style optimizations during or before lowering have access to |
| 1550 // this instruction in undeleted form. See for example |
| 1551 // tryOptimizedCmpxchgCmpBr(). |
| 1552 Iter->second.Instr->setDead(); |
| 1553 ++Iter; |
| 1554 } |
| 1555 } |
| 1556 |
1413 TargetHeaderMIPS32::TargetHeaderMIPS32(GlobalContext *Ctx) | 1557 TargetHeaderMIPS32::TargetHeaderMIPS32(GlobalContext *Ctx) |
1414 : TargetHeaderLowering(Ctx) {} | 1558 : TargetHeaderLowering(Ctx) {} |
1415 | 1559 |
1416 void TargetHeaderMIPS32::lower() { | 1560 void TargetHeaderMIPS32::lower() { |
1417 OstreamLocker L(Ctx); | 1561 OstreamLocker L(Ctx); |
1418 Ostream &Str = Ctx->getStrEmit(); | 1562 Ostream &Str = Ctx->getStrEmit(); |
1419 Str << "\t.set\t" | 1563 Str << "\t.set\t" |
1420 << "nomicromips\n"; | 1564 << "nomicromips\n"; |
1421 Str << "\t.set\t" | 1565 Str << "\t.set\t" |
1422 << "nomips16\n"; | 1566 << "nomips16\n"; |
1423 } | 1567 } |
1424 | 1568 |
1425 SmallBitVector TargetMIPS32::TypeToRegisterSet[RCMIPS32_NUM]; | 1569 SmallBitVector TargetMIPS32::TypeToRegisterSet[RCMIPS32_NUM]; |
1426 SmallBitVector TargetMIPS32::TypeToRegisterSetUnfiltered[RCMIPS32_NUM]; | 1570 SmallBitVector TargetMIPS32::TypeToRegisterSetUnfiltered[RCMIPS32_NUM]; |
1427 SmallBitVector TargetMIPS32::RegisterAliases[RegMIPS32::Reg_NUM]; | 1571 SmallBitVector TargetMIPS32::RegisterAliases[RegMIPS32::Reg_NUM]; |
1428 | 1572 |
1429 } // end of namespace MIPS32 | 1573 } // end of namespace MIPS32 |
1430 } // end of namespace Ice | 1574 } // end of namespace Ice |
OLD | NEW |