diff options
author | Jacques Pienaar <jpienaar@google.com> | 2016-07-07 23:36:04 +0000 |
---|---|---|
committer | Jacques Pienaar <jpienaar@google.com> | 2016-07-07 23:36:04 +0000 |
commit | 6d3eecc84304c0b36ed5f1ababa22cd974de1f5b (patch) | |
tree | 7754b66e6fb7eb27a95f26e03c130a403b878559 /llvm/lib/Target | |
parent | 3f36781dec71788e87779005d7c18cb78c6f163d (diff) | |
download | bcm5719-llvm-6d3eecc84304c0b36ed5f1ababa22cd974de1f5b.tar.gz bcm5719-llvm-6d3eecc84304c0b36ed5f1ababa22cd974de1f5b.zip |
[lanai] Use peephole optimizer to generate more conditional ALU operations.
Summary:
* Similiar to the ARM backend yse the peephole optimizer to generate more conditional ALU operations;
* Add predicated type with default always true to RR instructions in LanaiInstrInfo.td;
* Move LanaiSetflagAluCombiner into optimizeCompare;
* The ASM parser can currently only handle explicitly specified CC, so specify ".t" (true) where needed in the ASM test;
* Remove unused MachineOperand flags;
Reviewers: eliben
Subscribers: aemerson
Differential Revision: http://reviews.llvm.org/D22072
llvm-svn: 274807
Diffstat (limited to 'llvm/lib/Target')
-rw-r--r-- | llvm/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp | 30 | ||||
-rw-r--r-- | llvm/lib/Target/Lanai/CMakeLists.txt | 1 | ||||
-rw-r--r-- | llvm/lib/Target/Lanai/Disassembler/LanaiDisassembler.cpp | 13 | ||||
-rw-r--r-- | llvm/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.cpp | 20 | ||||
-rw-r--r-- | llvm/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.h | 1 | ||||
-rw-r--r-- | llvm/lib/Target/Lanai/LanaiAsmPrinter.cpp | 12 | ||||
-rw-r--r-- | llvm/lib/Target/Lanai/LanaiISelLowering.cpp | 170 | ||||
-rw-r--r-- | llvm/lib/Target/Lanai/LanaiISelLowering.h | 2 | ||||
-rw-r--r-- | llvm/lib/Target/Lanai/LanaiInstrInfo.cpp | 395 | ||||
-rw-r--r-- | llvm/lib/Target/Lanai/LanaiInstrInfo.h | 47 | ||||
-rw-r--r-- | llvm/lib/Target/Lanai/LanaiInstrInfo.td | 43 | ||||
-rw-r--r-- | llvm/lib/Target/Lanai/LanaiRegisterInfo.cpp | 15 | ||||
-rw-r--r-- | llvm/lib/Target/Lanai/LanaiSetflagAluCombiner.cpp | 294 | ||||
-rw-r--r-- | llvm/lib/Target/Lanai/LanaiTargetMachine.cpp | 2 | ||||
-rw-r--r-- | llvm/lib/Target/Lanai/MCTargetDesc/LanaiBaseInfo.h | 26 |
15 files changed, 707 insertions, 364 deletions
diff --git a/llvm/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp b/llvm/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp index 799f587ff3f..c3c4468d54c 100644 --- a/llvm/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp +++ b/llvm/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp @@ -357,6 +357,20 @@ public: return isInt<10>(Value); } + bool isCondCode() { + if (!isImm()) + return false; + + const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value); + if (!ConstExpr) + return false; + uint64_t Value = ConstExpr->getValue(); + // The condition codes are between 0 (ICC_T) and 15 (ICC_LE). If the + // unsigned value of the immediate is less than LPCC::UNKNOWN (16) then + // value corresponds to a valid condition code. + return Value < LPCC::UNKNOWN; + } + void addExpr(MCInst &Inst, const MCExpr *Expr) const { // Add as immediates where possible. Null MCExpr = 0 if (Expr == nullptr) @@ -388,6 +402,11 @@ public: addExpr(Inst, getImm()); } + void addCondCodeOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + addExpr(Inst, getImm()); + } + void addMemImmOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); const MCExpr *Expr = getMemOffset(); @@ -1031,7 +1050,16 @@ StringRef LanaiAsmParser::splitMnemonic(StringRef Name, SMLoc NameLoc, LPCC::CondCode CondCode = LPCC::suffixToLanaiCondCode(Mnemonic); if (CondCode != LPCC::UNKNOWN) { size_t Next = Mnemonic.rfind('.', Name.size()); - Mnemonic = Mnemonic.substr(0, Next + 1); + // 'sel' doesn't use a predicate operand whose printer adds the period, + // but instead has the period as part of the identifier (i.e., 'sel.' is + // expected by the generated matcher). If the mnemonic starts with 'sel' + // then include the period as part of the mnemonic, else don't include it + // as part of the mnemonic. + if (Mnemonic.startswith("sel")) { + Mnemonic = Mnemonic.substr(0, Next + 1); + } else { + Mnemonic = Mnemonic.substr(0, Next); + } Operands->push_back(LanaiOperand::CreateToken(Mnemonic, NameLoc)); Operands->push_back(LanaiOperand::createImm( MCConstantExpr::create(CondCode, getContext()), NameLoc, NameLoc)); diff --git a/llvm/lib/Target/Lanai/CMakeLists.txt b/llvm/lib/Target/Lanai/CMakeLists.txt index e5aec96e476..867f6165c25 100644 --- a/llvm/lib/Target/Lanai/CMakeLists.txt +++ b/llvm/lib/Target/Lanai/CMakeLists.txt @@ -23,7 +23,6 @@ add_llvm_target(LanaiCodeGen LanaiMemAluCombiner.cpp LanaiRegisterInfo.cpp LanaiSelectionDAGInfo.cpp - LanaiSetflagAluCombiner.cpp LanaiSubtarget.cpp LanaiTargetMachine.cpp LanaiTargetObjectFile.cpp diff --git a/llvm/lib/Target/Lanai/Disassembler/LanaiDisassembler.cpp b/llvm/lib/Target/Lanai/Disassembler/LanaiDisassembler.cpp index 3a71b80b2ba..d8ead5d67bc 100644 --- a/llvm/lib/Target/Lanai/Disassembler/LanaiDisassembler.cpp +++ b/llvm/lib/Target/Lanai/Disassembler/LanaiDisassembler.cpp @@ -62,6 +62,10 @@ static DecodeStatus decodeSplsValue(MCInst &Inst, unsigned Insn, static DecodeStatus decodeBranch(MCInst &Inst, unsigned Insn, uint64_t Address, const void *Decoder); +static DecodeStatus decodePredicateOperand(MCInst &Inst, unsigned Val, + uint64_t Address, + const void *Decoder); + static DecodeStatus decodeShiftImm(MCInst &Inst, unsigned Insn, uint64_t Address, const void *Decoder); @@ -226,3 +230,12 @@ static DecodeStatus decodeShiftImm(MCInst &Inst, unsigned Insn, return MCDisassembler::Success; } + +static DecodeStatus decodePredicateOperand(MCInst &Inst, unsigned Val, + uint64_t Address, + const void *Decoder) { + if (Val >= LPCC::UNKNOWN) + return MCDisassembler::Fail; + Inst.addOperand(MCOperand::createImm(Val)); + return MCDisassembler::Success; +} diff --git a/llvm/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.cpp b/llvm/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.cpp index 4a1dcd881b5..82b720cea8d 100644 --- a/llvm/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.cpp +++ b/llvm/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.cpp @@ -284,6 +284,22 @@ void LanaiInstPrinter::printMemSplsOperand(const MCInst *MI, int OpNo, void LanaiInstPrinter::printCCOperand(const MCInst *MI, int OpNo, raw_ostream &OS) { - const int CC = static_cast<const int>(MI->getOperand(OpNo).getImm()); - OS << lanaiCondCodeToString(static_cast<LPCC::CondCode>(CC)); + LPCC::CondCode CC = + static_cast<LPCC::CondCode>(MI->getOperand(OpNo).getImm()); + // Handle the undefined value here for printing so we don't abort(). + if (CC >= LPCC::UNKNOWN) + OS << "<und>"; + else + OS << lanaiCondCodeToString(CC); +} + +void LanaiInstPrinter::printPredicateOperand(const MCInst *MI, unsigned OpNo, + raw_ostream &OS) { + LPCC::CondCode CC = + static_cast<LPCC::CondCode>(MI->getOperand(OpNo).getImm()); + // Handle the undefined value here for printing so we don't abort(). + if (CC >= LPCC::UNKNOWN) + OS << "<und>"; + else if (CC != LPCC::ICC_T) + OS << "." << lanaiCondCodeToString(CC); } diff --git a/llvm/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.h b/llvm/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.h index 4bd5bb0e7fc..1c9d186ad81 100644 --- a/llvm/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.h +++ b/llvm/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.h @@ -29,6 +29,7 @@ public: const MCSubtargetInfo &STI) override; void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O, const char *Modifier = 0); + void printPredicateOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O); void printMemRiOperand(const MCInst *MI, int OpNo, raw_ostream &O, const char *Modifier = 0); void printMemRrOperand(const MCInst *MI, int OpNo, raw_ostream &O, diff --git a/llvm/lib/Target/Lanai/LanaiAsmPrinter.cpp b/llvm/lib/Target/Lanai/LanaiAsmPrinter.cpp index 0effa5cc653..d3ff9e8668d 100644 --- a/llvm/lib/Target/Lanai/LanaiAsmPrinter.cpp +++ b/llvm/lib/Target/Lanai/LanaiAsmPrinter.cpp @@ -65,7 +65,6 @@ private: void LanaiAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O, const char *Modifier) { const MachineOperand &MO = MI->getOperand(OpNum); - unsigned TF = MO.getTargetFlags(); switch (MO.getType()) { case MachineOperand::MO_Register: @@ -81,10 +80,7 @@ void LanaiAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, break; case MachineOperand::MO_GlobalAddress: - if (TF == LanaiII::MO_PLT) - O << "plt(" << *getSymbol(MO.getGlobal()) << ")"; - else - O << *getSymbol(MO.getGlobal()); + O << *getSymbol(MO.getGlobal()); break; case MachineOperand::MO_BlockAddress: { @@ -94,10 +90,7 @@ void LanaiAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, } case MachineOperand::MO_ExternalSymbol: - if (TF == LanaiII::MO_PLT) - O << "plt(" << *GetExternalSymbolSymbol(MO.getSymbolName()) << ")"; - else - O << *GetExternalSymbolSymbol(MO.getSymbolName()); + O << *GetExternalSymbolSymbol(MO.getSymbolName()); break; case MachineOperand::MO_JumpTableIndex: @@ -116,7 +109,6 @@ void LanaiAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, } // PrintAsmOperand - Print out an operand for an inline asm expression. -// bool LanaiAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode, raw_ostream &O) { diff --git a/llvm/lib/Target/Lanai/LanaiISelLowering.cpp b/llvm/lib/Target/Lanai/LanaiISelLowering.cpp index fd2d7fffd0e..a383cf844b6 100644 --- a/llvm/lib/Target/Lanai/LanaiISelLowering.cpp +++ b/llvm/lib/Target/Lanai/LanaiISelLowering.cpp @@ -124,6 +124,12 @@ LanaiTargetLowering::LanaiTargetLowering(const TargetMachine &TM, setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i1, Promote); } + setTargetDAGCombine(ISD::ADD); + setTargetDAGCombine(ISD::SUB); + setTargetDAGCombine(ISD::AND); + setTargetDAGCombine(ISD::OR); + setTargetDAGCombine(ISD::XOR); + // Function alignments (log2) setMinFunctionAlignment(2); setPrefFunctionAlignment(2); @@ -1268,3 +1274,167 @@ SDValue LanaiTargetLowering::LowerSRL_PARTS(SDValue Op, SDValue Ops[2] = {Lo, Hi}; return DAG.getMergeValues(Ops, dl); } + +// Helper function that checks if N is a null or all ones constant. +static inline bool isZeroOrAllOnes(SDValue N, bool AllOnes) { + return AllOnes ? isAllOnesConstant(N) : isNullConstant(N); +} + +// Return true if N is conditionally 0 or all ones. +// Detects these expressions where cc is an i1 value: +// +// (select cc 0, y) [AllOnes=0] +// (select cc y, 0) [AllOnes=0] +// (zext cc) [AllOnes=0] +// (sext cc) [AllOnes=0/1] +// (select cc -1, y) [AllOnes=1] +// (select cc y, -1) [AllOnes=1] +// +// * AllOnes determines whether to check for an all zero (AllOnes false) or an +// all ones operand (AllOnes true). +// * Invert is set when N is the all zero/ones constant when CC is false. +// * OtherOp is set to the alternative value of N. +// +// For example, for (select cc X, Y) and AllOnes = 0 if: +// * X = 0, Invert = False and OtherOp = Y +// * Y = 0, Invert = True and OtherOp = X +static bool isConditionalZeroOrAllOnes(SDNode *N, bool AllOnes, SDValue &CC, + bool &Invert, SDValue &OtherOp, + SelectionDAG &DAG) { + switch (N->getOpcode()) { + default: + return false; + case ISD::SELECT: { + CC = N->getOperand(0); + SDValue N1 = N->getOperand(1); + SDValue N2 = N->getOperand(2); + if (isZeroOrAllOnes(N1, AllOnes)) { + Invert = false; + OtherOp = N2; + return true; + } + if (isZeroOrAllOnes(N2, AllOnes)) { + Invert = true; + OtherOp = N1; + return true; + } + return false; + } + case ISD::ZERO_EXTEND: { + // (zext cc) can never be the all ones value. + if (AllOnes) + return false; + CC = N->getOperand(0); + if (CC.getValueType() != MVT::i1) + return false; + SDLoc dl(N); + EVT VT = N->getValueType(0); + OtherOp = DAG.getConstant(1, dl, VT); + Invert = true; + return true; + } + case ISD::SIGN_EXTEND: { + CC = N->getOperand(0); + if (CC.getValueType() != MVT::i1) + return false; + SDLoc dl(N); + EVT VT = N->getValueType(0); + Invert = !AllOnes; + if (AllOnes) + // When looking for an AllOnes constant, N is an sext, and the 'other' + // value is 0. + OtherOp = DAG.getConstant(0, dl, VT); + else + OtherOp = + DAG.getConstant(APInt::getAllOnesValue(VT.getSizeInBits()), dl, VT); + return true; + } + } +} + +// Combine a constant select operand into its use: +// +// (add (select cc, 0, c), x) -> (select cc, x, (add, x, c)) +// (sub x, (select cc, 0, c)) -> (select cc, x, (sub, x, c)) +// (and (select cc, -1, c), x) -> (select cc, x, (and, x, c)) [AllOnes=1] +// (or (select cc, 0, c), x) -> (select cc, x, (or, x, c)) +// (xor (select cc, 0, c), x) -> (select cc, x, (xor, x, c)) +// +// The transform is rejected if the select doesn't have a constant operand that +// is null, or all ones when AllOnes is set. +// +// Also recognize sext/zext from i1: +// +// (add (zext cc), x) -> (select cc (add x, 1), x) +// (add (sext cc), x) -> (select cc (add x, -1), x) +// +// These transformations eventually create predicated instructions. +static SDValue combineSelectAndUse(SDNode *N, SDValue Slct, SDValue OtherOp, + TargetLowering::DAGCombinerInfo &DCI, + bool AllOnes) { + SelectionDAG &DAG = DCI.DAG; + EVT VT = N->getValueType(0); + SDValue NonConstantVal; + SDValue CCOp; + bool SwapSelectOps; + if (!isConditionalZeroOrAllOnes(Slct.getNode(), AllOnes, CCOp, SwapSelectOps, + NonConstantVal, DAG)) + return SDValue(); + + // Slct is now know to be the desired identity constant when CC is true. + SDValue TrueVal = OtherOp; + SDValue FalseVal = + DAG.getNode(N->getOpcode(), SDLoc(N), VT, OtherOp, NonConstantVal); + // Unless SwapSelectOps says CC should be false. + if (SwapSelectOps) + std::swap(TrueVal, FalseVal); + + return DAG.getNode(ISD::SELECT, SDLoc(N), VT, CCOp, TrueVal, FalseVal); +} + +// Attempt combineSelectAndUse on each operand of a commutative operator N. +static SDValue +combineSelectAndUseCommutative(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, + bool AllOnes) { + SDValue N0 = N->getOperand(0); + SDValue N1 = N->getOperand(1); + if (N0.getNode()->hasOneUse()) + if (SDValue Result = combineSelectAndUse(N, N0, N1, DCI, AllOnes)) + return Result; + if (N1.getNode()->hasOneUse()) + if (SDValue Result = combineSelectAndUse(N, N1, N0, DCI, AllOnes)) + return Result; + return SDValue(); +} + +// PerformSUBCombine - Target-specific dag combine xforms for ISD::SUB. +static SDValue PerformSUBCombine(SDNode *N, + TargetLowering::DAGCombinerInfo &DCI) { + SDValue N0 = N->getOperand(0); + SDValue N1 = N->getOperand(1); + + // fold (sub x, (select cc, 0, c)) -> (select cc, x, (sub, x, c)) + if (N1.getNode()->hasOneUse()) + if (SDValue Result = combineSelectAndUse(N, N1, N0, DCI, /*AllOnes=*/false)) + return Result; + + return SDValue(); +} + +SDValue LanaiTargetLowering::PerformDAGCombine(SDNode *N, + DAGCombinerInfo &DCI) const { + switch (N->getOpcode()) { + default: + break; + case ISD::ADD: + case ISD::OR: + case ISD::XOR: + return combineSelectAndUseCommutative(N, DCI, /*AllOnes=*/false); + case ISD::AND: + return combineSelectAndUseCommutative(N, DCI, /*AllOnes=*/true); + case ISD::SUB: + return PerformSUBCombine(N, DCI); + } + + return SDValue(); +} diff --git a/llvm/lib/Target/Lanai/LanaiISelLowering.h b/llvm/lib/Target/Lanai/LanaiISelLowering.h index 20ca9a01684..16ce8edd27c 100644 --- a/llvm/lib/Target/Lanai/LanaiISelLowering.h +++ b/llvm/lib/Target/Lanai/LanaiISelLowering.h @@ -103,6 +103,8 @@ public: std::vector<SDValue> &Ops, SelectionDAG &DAG) const override; + SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const override; + private: SDValue LowerCCCCallTo(SDValue Chain, SDValue Callee, CallingConv::ID CallConv, bool IsVarArg, diff --git a/llvm/lib/Target/Lanai/LanaiInstrInfo.cpp b/llvm/lib/Target/Lanai/LanaiInstrInfo.cpp index 797fd8e5c53..861604266cd 100644 --- a/llvm/lib/Target/Lanai/LanaiInstrInfo.cpp +++ b/llvm/lib/Target/Lanai/LanaiInstrInfo.cpp @@ -122,7 +122,7 @@ bool LanaiInstrInfo::expandPostRAPseudo(MachineInstr &MI) const { return false; } -static LPCC::CondCode GetOppositeBranchCondition(LPCC::CondCode CC) { +static LPCC::CondCode getOppositeCondition(LPCC::CondCode CC) { switch (CC) { case LPCC::ICC_T: // true return LPCC::ICC_F; @@ -161,6 +161,397 @@ static LPCC::CondCode GetOppositeBranchCondition(LPCC::CondCode CC) { } } +std::pair<unsigned, unsigned> +LanaiInstrInfo::decomposeMachineOperandsTargetFlags(unsigned TF) const { + return std::make_pair(TF, 0u); +} + +ArrayRef<std::pair<unsigned, const char *>> +LanaiInstrInfo::getSerializableDirectMachineOperandTargetFlags() const { + using namespace LanaiII; + static const std::pair<unsigned, const char *> TargetFlags[] = { + {MO_ABS_HI, "lanai-hi"}, + {MO_ABS_LO, "lanai-lo"}, + {MO_NO_FLAG, "lanai-nf"}}; + return makeArrayRef(TargetFlags); +} + +bool LanaiInstrInfo::analyzeCompare(const MachineInstr &MI, unsigned &SrcReg, + unsigned &SrcReg2, int &CmpMask, + int &CmpValue) const { + switch (MI.getOpcode()) { + default: + break; + case Lanai::SFSUB_F_RI_LO: + case Lanai::SFSUB_F_RI_HI: + SrcReg = MI.getOperand(0).getReg(); + SrcReg2 = 0; + CmpMask = ~0; + CmpValue = MI.getOperand(1).getImm(); + return true; + case Lanai::SFSUB_F_RR: + SrcReg = MI.getOperand(0).getReg(); + SrcReg2 = MI.getOperand(1).getReg(); + CmpMask = ~0; + CmpValue = 0; + return true; + } + + return false; +} + +// isRedundantFlagInstr - check whether the first instruction, whose only +// purpose is to update flags, can be made redundant. +// * SFSUB_F_RR can be made redundant by SUB_RI if the operands are the same. +// * SFSUB_F_RI can be made redundant by SUB_I if the operands are the same. +inline static bool isRedundantFlagInstr(MachineInstr *CmpI, unsigned SrcReg, + unsigned SrcReg2, int ImmValue, + MachineInstr *OI) { + if (CmpI->getOpcode() == Lanai::SFSUB_F_RR && + OI->getOpcode() == Lanai::SUB_R && + ((OI->getOperand(1).getReg() == SrcReg && + OI->getOperand(2).getReg() == SrcReg2) || + (OI->getOperand(1).getReg() == SrcReg2 && + OI->getOperand(2).getReg() == SrcReg))) + return true; + + if (((CmpI->getOpcode() == Lanai::SFSUB_F_RI_LO && + OI->getOpcode() == Lanai::SUB_I_LO) || + (CmpI->getOpcode() == Lanai::SFSUB_F_RI_HI && + OI->getOpcode() == Lanai::SUB_I_HI)) && + OI->getOperand(1).getReg() == SrcReg && + OI->getOperand(2).getImm() == ImmValue) + return true; + return false; +} + +inline static unsigned flagSettingOpcodeVariant(unsigned OldOpcode) { + switch (OldOpcode) { + case Lanai::ADD_I_HI: + return Lanai::ADD_F_I_HI; + case Lanai::ADD_I_LO: + return Lanai::ADD_F_I_LO; + case Lanai::ADD_R: + return Lanai::ADD_F_R; + case Lanai::ADDC_I_HI: + return Lanai::ADDC_F_I_HI; + case Lanai::ADDC_I_LO: + return Lanai::ADDC_F_I_LO; + case Lanai::ADDC_R: + return Lanai::ADDC_F_R; + case Lanai::AND_I_HI: + return Lanai::AND_F_I_HI; + case Lanai::AND_I_LO: + return Lanai::AND_F_I_LO; + case Lanai::AND_R: + return Lanai::AND_F_R; + case Lanai::OR_I_HI: + return Lanai::OR_F_I_HI; + case Lanai::OR_I_LO: + return Lanai::OR_F_I_LO; + case Lanai::OR_R: + return Lanai::OR_F_R; + case Lanai::SL_I: + return Lanai::SL_F_I; + case Lanai::SRL_R: + return Lanai::SRL_F_R; + case Lanai::SA_I: + return Lanai::SA_F_I; + case Lanai::SRA_R: + return Lanai::SRA_F_R; + case Lanai::SUB_I_HI: + return Lanai::SUB_F_I_HI; + case Lanai::SUB_I_LO: + return Lanai::SUB_F_I_LO; + case Lanai::SUB_R: + return Lanai::SUB_F_R; + case Lanai::SUBB_I_HI: + return Lanai::SUBB_F_I_HI; + case Lanai::SUBB_I_LO: + return Lanai::SUBB_F_I_LO; + case Lanai::SUBB_R: + return Lanai::SUBB_F_R; + case Lanai::XOR_I_HI: + return Lanai::XOR_F_I_HI; + case Lanai::XOR_I_LO: + return Lanai::XOR_F_I_LO; + case Lanai::XOR_R: + return Lanai::XOR_F_R; + default: + return Lanai::NOP; + } +} + +bool LanaiInstrInfo::optimizeCompareInstr( + MachineInstr &CmpInstr, unsigned SrcReg, unsigned SrcReg2, int CmpMask, + int CmpValue, const MachineRegisterInfo *MRI) const { + // Get the unique definition of SrcReg. + MachineInstr *MI = MRI->getUniqueVRegDef(SrcReg); + if (!MI) + return false; + + // Get ready to iterate backward from CmpInstr. + MachineBasicBlock::iterator I = CmpInstr, E = MI, + B = CmpInstr.getParent()->begin(); + + // Early exit if CmpInstr is at the beginning of the BB. + if (I == B) + return false; + + // There are two possible candidates which can be changed to set SR: + // One is MI, the other is a SUB instruction. + // * For SFSUB_F_RR(r1,r2), we are looking for SUB(r1,r2) or SUB(r2,r1). + // * For SFSUB_F_RI(r1, CmpValue), we are looking for SUB(r1, CmpValue). + MachineInstr *Sub = nullptr; + if (SrcReg2 != 0) + // MI is not a candidate to transform into a flag setting instruction. + MI = nullptr; + else if (MI->getParent() != CmpInstr.getParent() || CmpValue != 0) { + // Conservatively refuse to convert an instruction which isn't in the same + // BB as the comparison. Don't return if SFSUB_F_RI and CmpValue != 0 as Sub + // may still be a candidate. + if (CmpInstr.getOpcode() == Lanai::SFSUB_F_RI_LO) + MI = nullptr; + else + return false; + } + + // Check that SR isn't set between the comparison instruction and the + // instruction we want to change while searching for Sub. + const TargetRegisterInfo *TRI = &getRegisterInfo(); + for (--I; I != E; --I) { + const MachineInstr &Instr = *I; + + if (Instr.modifiesRegister(Lanai::SR, TRI) || + Instr.readsRegister(Lanai::SR, TRI)) + // This instruction modifies or uses SR after the one we want to change. + // We can't do this transformation. + return false; + + // Check whether CmpInstr can be made redundant by the current instruction. + if (isRedundantFlagInstr(&CmpInstr, SrcReg, SrcReg2, CmpValue, &*I)) { + Sub = &*I; + break; + } + + // Don't search outside the containing basic block. + if (I == B) + return false; + } + + // Return false if no candidates exist. + if (!MI && !Sub) + return false; + + // The single candidate is called MI. + if (!MI) + MI = Sub; + + if (flagSettingOpcodeVariant(MI->getOpcode()) != Lanai::NOP) { + bool isSafe = false; + + SmallVector<std::pair<MachineOperand *, LPCC::CondCode>, 4> + OperandsToUpdate; + I = CmpInstr; + E = CmpInstr.getParent()->end(); + while (!isSafe && ++I != E) { + const MachineInstr &Instr = *I; + for (unsigned IO = 0, EO = Instr.getNumOperands(); !isSafe && IO != EO; + ++IO) { + const MachineOperand &MO = Instr.getOperand(IO); + if (MO.isRegMask() && MO.clobbersPhysReg(Lanai::SR)) { + isSafe = true; + break; + } + if (!MO.isReg() || MO.getReg() != Lanai::SR) + continue; + if (MO.isDef()) { + isSafe = true; + break; + } + // Condition code is after the operand before SR. + LPCC::CondCode CC; + CC = (LPCC::CondCode)Instr.getOperand(IO - 1).getImm(); + + if (Sub) { + LPCC::CondCode NewCC = getOppositeCondition(CC); + if (NewCC == LPCC::ICC_T) + return false; + // If we have SUB(r1, r2) and CMP(r2, r1), the condition code based on + // CMP needs to be updated to be based on SUB. Push the condition + // code operands to OperandsToUpdate. If it is safe to remove + // CmpInstr, the condition code of these operands will be modified. + if (SrcReg2 != 0 && Sub->getOperand(1).getReg() == SrcReg2 && + Sub->getOperand(2).getReg() == SrcReg) { + OperandsToUpdate.push_back( + std::make_pair(&((*I).getOperand(IO - 1)), NewCC)); + } + } else { + // No Sub, so this is x = <op> y, z; cmp x, 0. + switch (CC) { + case LPCC::ICC_EQ: // Z + case LPCC::ICC_NE: // Z + case LPCC::ICC_MI: // N + case LPCC::ICC_PL: // N + case LPCC::ICC_F: // none + case LPCC::ICC_T: // none + // SR can be used multiple times, we should continue. + break; + case LPCC::ICC_CS: // C + case LPCC::ICC_CC: // C + case LPCC::ICC_VS: // V + case LPCC::ICC_VC: // V + case LPCC::ICC_HI: // C Z + case LPCC::ICC_LS: // C Z + case LPCC::ICC_GE: // N V + case LPCC::ICC_LT: // N V + case LPCC::ICC_GT: // Z N V + case LPCC::ICC_LE: // Z N V + // The instruction uses the V bit or C bit which is not safe. + return false; + case LPCC::UNKNOWN: + return false; + } + } + } + } + + // If SR is not killed nor re-defined, we should check whether it is + // live-out. If it is live-out, do not optimize. + if (!isSafe) { + MachineBasicBlock *MBB = CmpInstr.getParent(); + for (MachineBasicBlock::succ_iterator SI = MBB->succ_begin(), + SE = MBB->succ_end(); + SI != SE; ++SI) + if ((*SI)->isLiveIn(Lanai::SR)) + return false; + } + + // Toggle the optional operand to SR. + MI->setDesc(get(flagSettingOpcodeVariant(MI->getOpcode()))); + MI->addRegisterDefined(Lanai::SR); + CmpInstr.eraseFromParent(); + return true; + } + + return false; +} + +bool LanaiInstrInfo::analyzeSelect(const MachineInstr &MI, + SmallVectorImpl<MachineOperand> &Cond, + unsigned &TrueOp, unsigned &FalseOp, + bool &Optimizable) const { + assert(MI.getOpcode() == Lanai::SELECT && "unknown select instruction"); + // Select operands: + // 0: Def. + // 1: True use. + // 2: False use. + // 3: Condition code. + TrueOp = 1; + FalseOp = 2; + Cond.push_back(MI.getOperand(3)); + Optimizable = true; + return false; +} + +// Identify instructions that can be folded into a SELECT instruction, and +// return the defining instruction. +static MachineInstr *canFoldIntoSelect(unsigned Reg, + const MachineRegisterInfo &MRI, + const TargetInstrInfo *TII) { + if (!TargetRegisterInfo::isVirtualRegister(Reg)) + return nullptr; + if (!MRI.hasOneNonDBGUse(Reg)) + return nullptr; + MachineInstr *MI = MRI.getVRegDef(Reg); + if (!MI) + return nullptr; + // MI is folded into the SELECT by predicating it. + if (!MI->isPredicable()) + return nullptr; + // Check if MI has any non-dead defs or physreg uses. This also detects + // predicated instructions which will be reading SR. + for (unsigned i = 1, e = MI->getNumOperands(); i != e; ++i) { + const MachineOperand &MO = MI->getOperand(i); + // Reject frame index operands. + if (MO.isFI() || MO.isCPI() || MO.isJTI()) + return nullptr; + if (!MO.isReg()) + continue; + // MI can't have any tied operands, that would conflict with predication. + if (MO.isTied()) + return nullptr; + if (TargetRegisterInfo::isPhysicalRegister(MO.getReg())) + return nullptr; + if (MO.isDef() && !MO.isDead()) + return nullptr; + } + bool DontMoveAcrossStores = true; + if (!MI->isSafeToMove(/*AliasAnalysis=*/nullptr, DontMoveAcrossStores)) + return nullptr; + return MI; +} + +MachineInstr * +LanaiInstrInfo::optimizeSelect(MachineInstr &MI, + SmallPtrSetImpl<MachineInstr *> &SeenMIs, + bool PreferFalse) const { + assert(MI.getOpcode() == Lanai::SELECT && "unknown select instruction"); + MachineRegisterInfo &MRI = MI.getParent()->getParent()->getRegInfo(); + MachineInstr *DefMI = canFoldIntoSelect(MI.getOperand(1).getReg(), MRI, this); + bool Invert = !DefMI; + if (!DefMI) + DefMI = canFoldIntoSelect(MI.getOperand(2).getReg(), MRI, this); + if (!DefMI) + return nullptr; + + // Find new register class to use. + MachineOperand FalseReg = MI.getOperand(Invert ? 1 : 2); + unsigned DestReg = MI.getOperand(0).getReg(); + const TargetRegisterClass *PreviousClass = MRI.getRegClass(FalseReg.getReg()); + if (!MRI.constrainRegClass(DestReg, PreviousClass)) + return nullptr; + + // Create a new predicated version of DefMI. + MachineInstrBuilder NewMI = + BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), DefMI->getDesc(), DestReg); + + // Copy all the DefMI operands, excluding its (null) predicate. + const MCInstrDesc &DefDesc = DefMI->getDesc(); + for (unsigned i = 1, e = DefDesc.getNumOperands(); + i != e && !DefDesc.OpInfo[i].isPredicate(); ++i) + NewMI.addOperand(DefMI->getOperand(i)); + + unsigned CondCode = MI.getOperand(3).getImm(); + if (Invert) + NewMI.addImm(getOppositeCondition(LPCC::CondCode(CondCode))); + else + NewMI.addImm(CondCode); + NewMI.copyImplicitOps(MI); + + // The output register value when the predicate is false is an implicit + // register operand tied to the first def. The tie makes the register + // allocator ensure the FalseReg is allocated the same register as operand 0. + FalseReg.setImplicit(); + NewMI.addOperand(FalseReg); + NewMI->tieOperands(0, NewMI->getNumOperands() - 1); + + // Update SeenMIs set: register newly created MI and erase removed DefMI. + SeenMIs.insert(NewMI); + SeenMIs.erase(DefMI); + + // If MI is inside a loop, and DefMI is outside the loop, then kill flags on + // DefMI would be invalid when transferred inside the loop. Checking for a + // loop is expensive, but at least remove kill flags if they are in different + // BBs. + if (DefMI->getParent() != MI.getParent()) + NewMI->clearKillInfo(); + + // The caller will erase MI, but not DefMI. + DefMI->eraseFromParent(); + return NewMI; +} + // The AnalyzeBranch function is used to examine conditional instructions and // remove unnecessary instructions. This method is used by BranchFolder and // IfConverter machine function passes to improve the CFG. @@ -262,7 +653,7 @@ bool LanaiInstrInfo::ReverseBranchCondition( LPCC::CondCode BranchCond = static_cast<LPCC::CondCode>(Condition[0].getImm()); - Condition[0].setImm(GetOppositeBranchCondition(BranchCond)); + Condition[0].setImm(getOppositeCondition(BranchCond)); return false; } diff --git a/llvm/lib/Target/Lanai/LanaiInstrInfo.h b/llvm/lib/Target/Lanai/LanaiInstrInfo.h index ff2a51a26df..2d12d3d2228 100644 --- a/llvm/lib/Target/Lanai/LanaiInstrInfo.h +++ b/llvm/lib/Target/Lanai/LanaiInstrInfo.h @@ -75,6 +75,12 @@ public: int64_t &Offset, unsigned &Width, const TargetRegisterInfo *TRI) const; + std::pair<unsigned, unsigned> + decomposeMachineOperandsTargetFlags(unsigned TF) const override; + + ArrayRef<std::pair<unsigned, const char *>> + getSerializableDirectMachineOperandTargetFlags() const override; + bool AnalyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TrueBlock, MachineBasicBlock *&FalseBlock, SmallVectorImpl<MachineOperand> &Condition, @@ -82,6 +88,47 @@ public: unsigned RemoveBranch(MachineBasicBlock &MBB) const override; + // For a comparison instruction, return the source registers in SrcReg and + // SrcReg2 if having two register operands, and the value it compares against + // in CmpValue. Return true if the comparison instruction can be analyzed. + bool analyzeCompare(const MachineInstr &MI, unsigned &SrcReg, + unsigned &SrcReg2, int &CmpMask, + int &CmpValue) const override; + + // See if the comparison instruction can be converted into something more + // efficient. E.g., on Lanai register-register instructions can set the flag + // register, obviating the need for a separate compare. + bool optimizeCompareInstr(MachineInstr &CmpInstr, unsigned SrcReg, + unsigned SrcReg2, int CmpMask, int CmpValue, + const MachineRegisterInfo *MRI) const override; + + // Analyze the given select instruction, returning true if it cannot be + // understood. It is assumed that MI->isSelect() is true. + // + // When successful, return the controlling condition and the operands that + // determine the true and false result values. + // + // Result = SELECT Cond, TrueOp, FalseOp + // + // Lanai can optimize certain select instructions, for example by predicating + // the instruction defining one of the operands and sets Optimizable to true. + bool analyzeSelect(const MachineInstr &MI, + SmallVectorImpl<MachineOperand> &Cond, unsigned &TrueOp, + unsigned &FalseOp, bool &Optimizable) const override; + + // Given a select instruction that was understood by analyzeSelect and + // returned Optimizable = true, attempt to optimize MI by merging it with one + // of its operands. Returns NULL on failure. + // + // When successful, returns the new select instruction. The client is + // responsible for deleting MI. + // + // If both sides of the select can be optimized, the TrueOp is modifed. + // PreferFalse is not used. + MachineInstr *optimizeSelect(MachineInstr &MI, + SmallPtrSetImpl<MachineInstr *> &SeenMIs, + bool PreferFalse) const override; + bool ReverseBranchCondition( SmallVectorImpl<MachineOperand> &Condition) const override; diff --git a/llvm/lib/Target/Lanai/LanaiInstrInfo.td b/llvm/lib/Target/Lanai/LanaiInstrInfo.td index 20dd4ee58fa..05f4f75b9c7 100644 --- a/llvm/lib/Target/Lanai/LanaiInstrInfo.td +++ b/llvm/lib/Target/Lanai/LanaiInstrInfo.td @@ -235,6 +235,15 @@ def CCOp : Operand<i32> { let PrintMethod = "printCCOperand"; } +// Predicate operand. Default to 0 = true. +def CondCodeOperand : AsmOperandClass { let Name = "CondCode"; } + +def pred : PredicateOperand<i32, (ops i32imm), (ops (i32 0))> { + let PrintMethod = "printPredicateOperand"; + let ParserMatchClass = CondCodeOperand; + let DecoderMethod = "decodePredicateOperand"; +} + let hasSideEffects = 0, Inst = 0x00000001 in def NOP : InstLanai<(outs), (ins), "nop", []>; @@ -283,16 +292,10 @@ multiclass ALUarith<bits<3> subOp, string AsmStr, SDNode OpNode, defm I_ : ALUbase<subOp, AsmStr, OpNode, LoExt, HiExt, [], []>; // Register Register - let JJJJJ = 0, DDDI = 0 in - def R : InstRR<subOp, (outs GPR:$Rd), (ins GPR:$Rs1, GPR:$Rs2), - !strconcat(AsmStr, "\t$Rs1, $Rs2, $Rd"), + let JJJJJ = 0 in + def R : InstRR<subOp, (outs GPR:$Rd), (ins GPR:$Rs1, GPR:$Rs2, pred:$DDDI), + !strconcat(AsmStr, "$DDDI\t$Rs1, $Rs2, $Rd"), [(set GPR:$Rd, (OpNode GPR:$Rs1, GPR:$Rs2))]>; - // RR Conditional - let JJJJJ = 0, Uses = [SR] in - def R_CC : InstRR<subOp, (outs GPR:$Rd), - (ins GPR:$Rs1, GPR:$Rs2, CCOp:$DDDI), - !strconcat(AsmStr, ".$DDDI\t$Rs1, $Rs2, $Rd"), - []>; } multiclass ALUlogic<bits<3> subOp, string AsmStr, SDNode OpNode, @@ -302,16 +305,10 @@ multiclass ALUlogic<bits<3> subOp, string AsmStr, SDNode OpNode, [(set GPR:$Rd, (OpNode GPR:$Rs1, HiExt:$imm16))]>; // Register Register - let JJJJJ = 0, DDDI = 0 in - def R : InstRR<subOp, (outs GPR:$Rd), (ins GPR:$Rs1, GPR:$Rs2), - !strconcat(AsmStr, "\t$Rs1, $Rs2, $Rd"), + let JJJJJ = 0 in + def R : InstRR<subOp, (outs GPR:$Rd), (ins GPR:$Rs1, GPR:$Rs2, pred:$DDDI), + !strconcat(AsmStr, "$DDDI\t$Rs1, $Rs2, $Rd"), [(set GPR:$Rd, (OpNode GPR:$Rs1, GPR:$Rs2))]>; - // RR Conditional - let JJJJJ = 0, Uses = [SR] in - def R_CC : InstRR<subOp, (outs GPR:$Rd), - (ins GPR:$Rs1, GPR:$Rs2, CCOp:$DDDI), - !strconcat(AsmStr, ".$DDDI\t$Rs1, $Rs2, $Rd"), - []>; } // Non flag setting ALU operations @@ -407,7 +404,7 @@ def : Pat<(LanaiSubbF GPR:$Rs1, i32lo16z:$imm), def : Pat<(LanaiSubbF GPR:$Rs1, i32hi16:$imm), (SUBB_F_I_HI GPR:$Rs1, i32hi16:$imm)>; -def : InstAlias<"mov $src, $dst", (ADD_R GPR:$dst, GPR:$src, R0)>; +def : InstAlias<"mov $src, $dst", (ADD_R GPR:$dst, GPR:$src, R0, 0)>; let isAsCheapAsAMove = 1, Rs1 = R0.Num, isCodeGenOnly = 1, H = 1, F = 0, isReMaterializable = 1 in @@ -716,11 +713,15 @@ multiclass SF<bits<3> op2Val, string AsmStr> { !strconcat(AsmStr, "\t$Rs1, $Rs2, %r0"), [(LanaiSetFlag (i32 GPR:$Rs1), (i32 GPR:$Rs2))]>; let F = 1, Rd = R0.Num, H = 0, Defs = [SR] in - def _RI : InstRI<op2Val, (outs), (ins GPR:$Rs1, i32lo16z:$imm16), + def _RI_LO : InstRI<op2Val, (outs), (ins GPR:$Rs1, i32lo16z:$imm16), !strconcat(AsmStr, "\t$Rs1, $imm16, %r0"), [(LanaiSetFlag (i32 GPR:$Rs1), i32lo16z:$imm16)]>; + let F = 1, Rd = R0.Num, H = 1, Defs = [SR] in + def _RI_HI : InstRI<op2Val, (outs), (ins GPR:$Rs1, i32hi16:$imm16), + !strconcat(AsmStr, "\t$Rs1, $imm16, %r0"), + [(LanaiSetFlag (i32 GPR:$Rs1), i32hi16:$imm16)]>; } -let isCodeGenOnly = 1 in { +let isCodeGenOnly = 1, isCompare = 1 in { defm SFSUB_F : SF<0b010, "sub.f">; } diff --git a/llvm/lib/Target/Lanai/LanaiRegisterInfo.cpp b/llvm/lib/Target/Lanai/LanaiRegisterInfo.cpp index 5d99f12d7a0..7bfe992d1d5 100644 --- a/llvm/lib/Target/Lanai/LanaiRegisterInfo.cpp +++ b/llvm/lib/Target/Lanai/LanaiRegisterInfo.cpp @@ -197,11 +197,16 @@ void LanaiRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, } // Reg = FrameReg OP Reg if (MI.getOpcode() == Lanai::ADD_I_LO) { - if (HasNegOffset) - MI.setDesc(TII->get(Lanai::SUB_R)); - else - MI.setDesc(TII->get(Lanai::ADD_R)); - } else if (isSPLSOpcode(MI.getOpcode()) || isRMOpcode(MI.getOpcode())) { + BuildMI(*MI.getParent(), II, DL, + HasNegOffset ? TII->get(Lanai::SUB_R) : TII->get(Lanai::ADD_R), + MI.getOperand(0).getReg()) + .addReg(FrameReg) + .addReg(Reg) + .addImm(LPCC::ICC_T); + MI.eraseFromParent(); + return; + } + if (isSPLSOpcode(MI.getOpcode()) || isRMOpcode(MI.getOpcode())) { MI.setDesc(TII->get(getRRMOpcodeVariant(MI.getOpcode()))); if (HasNegOffset) { // Change the ALU op (operand 3) from LPAC::ADD (the default) to diff --git a/llvm/lib/Target/Lanai/LanaiSetflagAluCombiner.cpp b/llvm/lib/Target/Lanai/LanaiSetflagAluCombiner.cpp deleted file mode 100644 index cd728778a65..00000000000 --- a/llvm/lib/Target/Lanai/LanaiSetflagAluCombiner.cpp +++ /dev/null @@ -1,294 +0,0 @@ -//===-- LanaiSetflagAluCombiner.cpp - Pass to combine set flag & ALU ops --===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "Lanai.h" -#include "LanaiTargetMachine.h" -#include "llvm/ADT/SmallSet.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/CodeGen/MachineFunctionPass.h" -#include "llvm/CodeGen/MachineInstrBuilder.h" -#include "llvm/CodeGen/RegisterScavenging.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Target/TargetInstrInfo.h" - -using namespace llvm; - -#define DEBUG_TYPE "lanai-setflag-alu-combiner" - -STATISTIC(NumSetflagAluCombined, - "Number of SET_FLAG and ALU instructions combined"); - -static llvm::cl::opt<bool> DisableSetflagAluCombiner( - "disable-lanai-setflag-alu-combiner", llvm::cl::init(false), - llvm::cl::desc("Do not combine SET_FLAG and ALU operators"), - llvm::cl::Hidden); - -namespace llvm { -void initializeLanaiSetflagAluCombinerPass(PassRegistry &); -} // namespace llvm - -namespace { -typedef MachineBasicBlock::iterator MbbIterator; -typedef MachineFunction::iterator MfIterator; - -class LanaiSetflagAluCombiner : public MachineFunctionPass { -public: - static char ID; - LanaiSetflagAluCombiner() : MachineFunctionPass(ID) { - initializeLanaiSetflagAluCombinerPass(*PassRegistry::getPassRegistry()); - } - - const char *getPassName() const override { - return "Lanai SET_FLAG ALU combiner pass"; - } - - bool runOnMachineFunction(MachineFunction &F) override; - - MachineFunctionProperties getRequiredProperties() const override { - return MachineFunctionProperties().set( - MachineFunctionProperties::Property::AllVRegsAllocated); - } - -private: - bool CombineSetflagAluInBasicBlock(MachineFunction *MF, - MachineBasicBlock *BB); -}; -} // namespace - -char LanaiSetflagAluCombiner::ID = 0; - -INITIALIZE_PASS(LanaiSetflagAluCombiner, DEBUG_TYPE, - "Lanai SET_FLAG ALU combiner pass", false, false) - -namespace { - -const unsigned kInvalid = -1; - -static unsigned flagSettingOpcodeVariant(unsigned OldOpcode) { - switch (OldOpcode) { - case Lanai::ADD_I_HI: - return Lanai::ADD_F_I_HI; - case Lanai::ADD_I_LO: - return Lanai::ADD_F_I_LO; - case Lanai::ADD_R: - return Lanai::ADD_F_R; - case Lanai::ADD_R_CC: - return Lanai::ADD_F_R_CC; - case Lanai::ADDC_I_HI: - return Lanai::ADDC_F_I_HI; - case Lanai::ADDC_I_LO: - return Lanai::ADDC_F_I_LO; - case Lanai::ADDC_R: - return Lanai::ADDC_F_R; - case Lanai::ADDC_R_CC: - return Lanai::ADDC_F_R_CC; - case Lanai::AND_I_HI: - return Lanai::AND_F_I_HI; - case Lanai::AND_I_LO: - return Lanai::AND_F_I_LO; - case Lanai::AND_R: - return Lanai::AND_F_R; - case Lanai::AND_R_CC: - return Lanai::AND_F_R_CC; - case Lanai::OR_I_HI: - return Lanai::OR_F_I_HI; - case Lanai::OR_I_LO: - return Lanai::OR_F_I_LO; - case Lanai::OR_R: - return Lanai::OR_F_R; - case Lanai::OR_R_CC: - return Lanai::OR_F_R_CC; - case Lanai::SL_I: - return Lanai::SL_F_I; - case Lanai::SRL_R: - return Lanai::SRL_F_R; - case Lanai::SA_I: - return Lanai::SA_F_I; - case Lanai::SRA_R: - return Lanai::SRA_F_R; - case Lanai::SUB_I_HI: - return Lanai::SUB_F_I_HI; - case Lanai::SUB_I_LO: - return Lanai::SUB_F_I_LO; - case Lanai::SUB_R: - return Lanai::SUB_F_R; - case Lanai::SUB_R_CC: - return Lanai::SUB_F_R_CC; - case Lanai::SUBB_I_HI: - return Lanai::SUBB_F_I_HI; - case Lanai::SUBB_I_LO: - return Lanai::SUBB_F_I_LO; - case Lanai::SUBB_R: - return Lanai::SUBB_F_R; - case Lanai::SUBB_R_CC: - return Lanai::SUBB_F_R_CC; - case Lanai::XOR_I_HI: - return Lanai::XOR_F_I_HI; - case Lanai::XOR_I_LO: - return Lanai::XOR_F_I_LO; - case Lanai::XOR_R: - return Lanai::XOR_F_R; - case Lanai::XOR_R_CC: - return Lanai::XOR_F_R_CC; - default: - return kInvalid; - } -} - -// Returns whether opcode corresponds to instruction that sets flags. -static bool isFlagSettingInstruction(MbbIterator Instruction) { - return Instruction->killsRegister(Lanai::SR); -} - -// Return the Conditional Code operand for a given instruction kind. For -// example, operand at index 1 of a BRIND_CC instruction is the conditional code -// (eq, ne, etc.). Returns -1 if the instruction does not have a conditional -// code. -static int getCCOperandPosition(unsigned Opcode) { - switch (Opcode) { - case Lanai::BRIND_CC: - case Lanai::BRIND_CCA: - case Lanai::BRR: - case Lanai::BRCC: - case Lanai::SCC: - return 1; - case Lanai::SELECT: - case Lanai::ADDC_F_R_CC: - case Lanai::ADDC_R_CC: - case Lanai::ADD_F_R_CC: - case Lanai::ADD_R_CC: - case Lanai::AND_F_R_CC: - case Lanai::AND_R_CC: - case Lanai::OR_F_R_CC: - case Lanai::OR_R_CC: - case Lanai::SUBB_F_R_CC: - case Lanai::SUBB_R_CC: - case Lanai::SUB_F_R_CC: - case Lanai::SUB_R_CC: - case Lanai::XOR_F_R_CC: - case Lanai::XOR_R_CC: - return 3; - default: - return -1; - } -} - -// Returns true if instruction is a lowered SET_FLAG instruction with 0/R0 as -// the first operand and whose conditional code is such that it can be merged -// (i.e., EQ, NE, PL and MI). -static bool isSuitableSetflag(MbbIterator Instruction, MbbIterator End) { - unsigned Opcode = Instruction->getOpcode(); - if (Opcode == Lanai::SFSUB_F_RI || Opcode == Lanai::SFSUB_F_RR) { - const MachineOperand &Operand = Instruction->getOperand(1); - if (Operand.isReg() && Operand.getReg() != Lanai::R0) - return false; - if (Operand.isImm() && Operand.getImm() != 0) - return false; - - MbbIterator SCCUserIter = Instruction; - while (SCCUserIter != End) { - ++SCCUserIter; - if (SCCUserIter == End) - break; - // Skip debug instructions. Debug instructions don't affect codegen. - if (SCCUserIter->isDebugValue()) - continue; - // Early exit when encountering flag setting or return instruction. - if (isFlagSettingInstruction(SCCUserIter)) - // Only return true if flags are set post the flag setting instruction - // tested or a return is executed. - return true; - int CCIndex = getCCOperandPosition(SCCUserIter->getOpcode()); - if (CCIndex != -1) { - LPCC::CondCode CC = static_cast<LPCC::CondCode>( - SCCUserIter->getOperand(CCIndex).getImm()); - // Return false if the flag is used outside of a EQ, NE, PL and MI. - if (CC != LPCC::ICC_EQ && CC != LPCC::ICC_NE && CC != LPCC::ICC_PL && - CC != LPCC::ICC_MI) - return false; - } - } - } - - return false; -} - -// Combines a SET_FLAG instruction comparing a register with 0 and an ALU -// operation that sets the same register used in the comparison into a single -// flag setting ALU instruction (both instructions combined are removed and new -// flag setting ALU operation inserted where ALU instruction was). -bool LanaiSetflagAluCombiner::CombineSetflagAluInBasicBlock( - MachineFunction *MF, MachineBasicBlock *BB) { - bool Modified = false; - const TargetInstrInfo *TII = - MF->getSubtarget<LanaiSubtarget>().getInstrInfo(); - - MbbIterator SetflagIter = BB->begin(); - MbbIterator End = BB->end(); - MbbIterator Begin = BB->begin(); - while (SetflagIter != End) { - bool Replaced = false; - if (isSuitableSetflag(SetflagIter, End)) { - MbbIterator AluIter = SetflagIter; - while (AluIter != Begin) { - --AluIter; - // Skip debug instructions. Debug instructions don't affect codegen. - if (AluIter->isDebugValue()) - continue; - // Early exit when encountering flag setting instruction. - if (isFlagSettingInstruction(AluIter)) - break; - // Check that output of AluIter is equal to input of SetflagIter. - if (AluIter->getNumOperands() > 1 && AluIter->getOperand(0).isReg() && - (AluIter->getOperand(0).getReg() == - SetflagIter->getOperand(0).getReg())) { - unsigned NewOpc = flagSettingOpcodeVariant(AluIter->getOpcode()); - if (NewOpc == kInvalid) - break; - - // Change the ALU instruction to the flag setting variant. - AluIter->setDesc(TII->get(NewOpc)); - AluIter->addImplicitDefUseOperands(*MF); - - Replaced = true; - ++NumSetflagAluCombined; - break; - } - } - // Erase the setflag instruction if merged. - if (Replaced) - BB->erase(SetflagIter++); - } - - Modified |= Replaced; - if (!Replaced) - ++SetflagIter; - } - - return Modified; -} - -// Driver function that iterates over the machine basic building blocks of a -// machine function -bool LanaiSetflagAluCombiner::runOnMachineFunction(MachineFunction &MF) { - if (DisableSetflagAluCombiner) - return false; - - bool Modified = false; - MfIterator End = MF.end(); - for (MfIterator MFI = MF.begin(); MFI != End; ++MFI) { - Modified |= CombineSetflagAluInBasicBlock(&MF, &*MFI); - } - return Modified; -} -} // namespace - -FunctionPass *llvm::createLanaiSetflagAluCombinerPass() { - return new LanaiSetflagAluCombiner(); -} diff --git a/llvm/lib/Target/Lanai/LanaiTargetMachine.cpp b/llvm/lib/Target/Lanai/LanaiTargetMachine.cpp index b43e9702f2b..2d1846c9874 100644 --- a/llvm/lib/Target/Lanai/LanaiTargetMachine.cpp +++ b/llvm/lib/Target/Lanai/LanaiTargetMachine.cpp @@ -28,7 +28,6 @@ using namespace llvm; namespace llvm { void initializeLanaiMemAluCombinerPass(PassRegistry &); -void initializeLanaiSetflagAluCombinerPass(PassRegistry &); } // namespace llvm extern "C" void LLVMInitializeLanaiTarget() { @@ -112,5 +111,4 @@ void LanaiPassConfig::addPreEmitPass() { // scheduling pass. void LanaiPassConfig::addPreSched2() { addPass(createLanaiMemAluCombinerPass()); - addPass(createLanaiSetflagAluCombinerPass()); } diff --git a/llvm/lib/Target/Lanai/MCTargetDesc/LanaiBaseInfo.h b/llvm/lib/Target/Lanai/MCTargetDesc/LanaiBaseInfo.h index 42bda1e894f..ce7f83509c9 100644 --- a/llvm/lib/Target/Lanai/MCTargetDesc/LanaiBaseInfo.h +++ b/llvm/lib/Target/Lanai/MCTargetDesc/LanaiBaseInfo.h @@ -24,7 +24,6 @@ namespace llvm { // LanaiII - This namespace holds all of the target specific flags that // instruction info tracks. -// namespace LanaiII { // Target Operand Flag enum. enum TOF { @@ -36,31 +35,6 @@ enum TOF { // address. MO_ABS_HI, MO_ABS_LO, - - // MO_PIC_BASE_OFFSET - On a symbol operand this indicates that the - // immediate should get the value of the symbol minus the PIC base label: - // SYMBOL_LABEL - PICBASELABEL - MO_PIC_BASE_OFFSET, - - // MO_GOT - On a symbol operand this indicates that the immediate is the - // offset to the GOT entry for the symbol name from the base of the GOT. - MO_GOT, - - // MO_GOTOFFHI/MO_GOTOFFLO - On a symbol operand this indicates that the - // immediate is the offset to the location of the symbol name from the - // base of the GOT. - MO_GOTOFFHI, - MO_GOTOFFLO, - - // MO_GOTPCHI/MO_GOTPCLO - On a symbol operand this indicates that - // the immediate is an offset to the GOT entry for the symbol name - // from the current code location. - MO_GOTPCHI, - MO_GOTPCLO, - - // MO_PLT - On a symbol operand this indicates that the immediate is - // offset to the PLT entry of symbol name from the current code location. - MO_PLT }; } // namespace LanaiII |