[llvm] r274807 - [lanai] Use peephole optimizer to generate more conditional ALU operations.

Jacques Pienaar via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 7 16:36:04 PDT 2016


Author: jpienaar
Date: Thu Jul  7 18:36:04 2016
New Revision: 274807

URL: http://llvm.org/viewvc/llvm-project?rev=274807&view=rev
Log:
[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

Added:
    llvm/trunk/test/CodeGen/Lanai/sub-cmp-peephole.ll
    llvm/trunk/test/CodeGen/MIR/Lanai/
    llvm/trunk/test/CodeGen/MIR/Lanai/lit.local.cfg
    llvm/trunk/test/CodeGen/MIR/Lanai/peephole-compare.mir
Removed:
    llvm/trunk/lib/Target/Lanai/LanaiSetflagAluCombiner.cpp
    llvm/trunk/test/CodeGen/Lanai/combined_alu_setcc.ll
Modified:
    llvm/trunk/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp
    llvm/trunk/lib/Target/Lanai/CMakeLists.txt
    llvm/trunk/lib/Target/Lanai/Disassembler/LanaiDisassembler.cpp
    llvm/trunk/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.cpp
    llvm/trunk/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.h
    llvm/trunk/lib/Target/Lanai/LanaiAsmPrinter.cpp
    llvm/trunk/lib/Target/Lanai/LanaiISelLowering.cpp
    llvm/trunk/lib/Target/Lanai/LanaiISelLowering.h
    llvm/trunk/lib/Target/Lanai/LanaiInstrInfo.cpp
    llvm/trunk/lib/Target/Lanai/LanaiInstrInfo.h
    llvm/trunk/lib/Target/Lanai/LanaiInstrInfo.td
    llvm/trunk/lib/Target/Lanai/LanaiRegisterInfo.cpp
    llvm/trunk/lib/Target/Lanai/LanaiTargetMachine.cpp
    llvm/trunk/lib/Target/Lanai/MCTargetDesc/LanaiBaseInfo.h
    llvm/trunk/test/MC/Lanai/v11.s

Modified: llvm/trunk/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp?rev=274807&r1=274806&r2=274807&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp (original)
+++ llvm/trunk/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp Thu Jul  7 18:36:04 2016
@@ -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(
     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));

Modified: llvm/trunk/lib/Target/Lanai/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Lanai/CMakeLists.txt?rev=274807&r1=274806&r2=274807&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Lanai/CMakeLists.txt (original)
+++ llvm/trunk/lib/Target/Lanai/CMakeLists.txt Thu Jul  7 18:36:04 2016
@@ -23,7 +23,6 @@ add_llvm_target(LanaiCodeGen
   LanaiMemAluCombiner.cpp
   LanaiRegisterInfo.cpp
   LanaiSelectionDAGInfo.cpp
-  LanaiSetflagAluCombiner.cpp
   LanaiSubtarget.cpp
   LanaiTargetMachine.cpp
   LanaiTargetObjectFile.cpp

Modified: llvm/trunk/lib/Target/Lanai/Disassembler/LanaiDisassembler.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Lanai/Disassembler/LanaiDisassembler.cpp?rev=274807&r1=274806&r2=274807&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Lanai/Disassembler/LanaiDisassembler.cpp (original)
+++ llvm/trunk/lib/Target/Lanai/Disassembler/LanaiDisassembler.cpp Thu Jul  7 18:36:04 2016
@@ -62,6 +62,10 @@ static DecodeStatus decodeSplsValue(MCIn
 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(MCIns
 
   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;
+}

Modified: llvm/trunk/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.cpp?rev=274807&r1=274806&r2=274807&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.cpp (original)
+++ llvm/trunk/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.cpp Thu Jul  7 18:36:04 2016
@@ -284,6 +284,22 @@ void LanaiInstPrinter::printMemSplsOpera
 
 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);
 }

Modified: llvm/trunk/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.h?rev=274807&r1=274806&r2=274807&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.h (original)
+++ llvm/trunk/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.h Thu Jul  7 18:36:04 2016
@@ -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,

Modified: llvm/trunk/lib/Target/Lanai/LanaiAsmPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Lanai/LanaiAsmPrinter.cpp?rev=274807&r1=274806&r2=274807&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Lanai/LanaiAsmPrinter.cpp (original)
+++ llvm/trunk/lib/Target/Lanai/LanaiAsmPrinter.cpp Thu Jul  7 18:36:04 2016
@@ -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
     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
   }
 
   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
 }
 
 // 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) {

Modified: llvm/trunk/lib/Target/Lanai/LanaiISelLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Lanai/LanaiISelLowering.cpp?rev=274807&r1=274806&r2=274807&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Lanai/LanaiISelLowering.cpp (original)
+++ llvm/trunk/lib/Target/Lanai/LanaiISelLowering.cpp Thu Jul  7 18:36:04 2016
@@ -124,6 +124,12 @@ LanaiTargetLowering::LanaiTargetLowering
     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_PA
   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();
+}

Modified: llvm/trunk/lib/Target/Lanai/LanaiISelLowering.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Lanai/LanaiISelLowering.h?rev=274807&r1=274806&r2=274807&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Lanai/LanaiISelLowering.h (original)
+++ llvm/trunk/lib/Target/Lanai/LanaiISelLowering.h Thu Jul  7 18:36:04 2016
@@ -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,

Modified: llvm/trunk/lib/Target/Lanai/LanaiInstrInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Lanai/LanaiInstrInfo.cpp?rev=274807&r1=274806&r2=274807&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Lanai/LanaiInstrInfo.cpp (original)
+++ llvm/trunk/lib/Target/Lanai/LanaiInstrInfo.cpp Thu Jul  7 18:36:04 2016
@@ -122,7 +122,7 @@ bool LanaiInstrInfo::expandPostRAPseudo(
   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 GetOppositeBranchC
   }
 }
 
+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::ReverseBranchCondit
 
   LPCC::CondCode BranchCond =
       static_cast<LPCC::CondCode>(Condition[0].getImm());
-  Condition[0].setImm(GetOppositeBranchCondition(BranchCond));
+  Condition[0].setImm(getOppositeCondition(BranchCond));
   return false;
 }
 

Modified: llvm/trunk/lib/Target/Lanai/LanaiInstrInfo.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Lanai/LanaiInstrInfo.h?rev=274807&r1=274806&r2=274807&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Lanai/LanaiInstrInfo.h (original)
+++ llvm/trunk/lib/Target/Lanai/LanaiInstrInfo.h Thu Jul  7 18:36:04 2016
@@ -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;
 

Modified: llvm/trunk/lib/Target/Lanai/LanaiInstrInfo.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Lanai/LanaiInstrInfo.td?rev=274807&r1=274806&r2=274807&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Lanai/LanaiInstrInfo.td (original)
+++ llvm/trunk/lib/Target/Lanai/LanaiInstrInfo.td Thu Jul  7 18:36:04 2016
@@ -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, strin
   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, strin
                     [(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
 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 Asm
                      !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">;
 }
 

Modified: llvm/trunk/lib/Target/Lanai/LanaiRegisterInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Lanai/LanaiRegisterInfo.cpp?rev=274807&r1=274806&r2=274807&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Lanai/LanaiRegisterInfo.cpp (original)
+++ llvm/trunk/lib/Target/Lanai/LanaiRegisterInfo.cpp Thu Jul  7 18:36:04 2016
@@ -197,11 +197,16 @@ void LanaiRegisterInfo::eliminateFrameIn
     }
     // 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

Removed: llvm/trunk/lib/Target/Lanai/LanaiSetflagAluCombiner.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Lanai/LanaiSetflagAluCombiner.cpp?rev=274806&view=auto
==============================================================================
--- llvm/trunk/lib/Target/Lanai/LanaiSetflagAluCombiner.cpp (original)
+++ llvm/trunk/lib/Target/Lanai/LanaiSetflagAluCombiner.cpp (removed)
@@ -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();
-}

Modified: llvm/trunk/lib/Target/Lanai/LanaiTargetMachine.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Lanai/LanaiTargetMachine.cpp?rev=274807&r1=274806&r2=274807&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Lanai/LanaiTargetMachine.cpp (original)
+++ llvm/trunk/lib/Target/Lanai/LanaiTargetMachine.cpp Thu Jul  7 18:36:04 2016
@@ -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());
 }

Modified: llvm/trunk/lib/Target/Lanai/MCTargetDesc/LanaiBaseInfo.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Lanai/MCTargetDesc/LanaiBaseInfo.h?rev=274807&r1=274806&r2=274807&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Lanai/MCTargetDesc/LanaiBaseInfo.h (original)
+++ llvm/trunk/lib/Target/Lanai/MCTargetDesc/LanaiBaseInfo.h Thu Jul  7 18:36:04 2016
@@ -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
 

Removed: llvm/trunk/test/CodeGen/Lanai/combined_alu_setcc.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Lanai/combined_alu_setcc.ll?rev=274806&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/Lanai/combined_alu_setcc.ll (original)
+++ llvm/trunk/test/CodeGen/Lanai/combined_alu_setcc.ll (removed)
@@ -1,170 +0,0 @@
-; RUN: llc < %s -march=lanai | FileCheck %s
-
-; Test the alu setcc combiner.
-
-; TODO: Enhance combiner to handle this case. This expands into:
-;   sub     %r7, %r6, %r3
-;   sub.f   %r7, %r6, %r0
-;   sel.eq %r18, %r3, %rv
-; This is different from the pattern currently matched. If the lowered form had
-; been sub.f %r3, 0, %r0 then it would have matched.
-
-; Function Attrs: norecurse nounwind readnone
-define i32 @test0a(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) #0 {
-entry:
-  %sub = sub i32 %b, %a
-  %cmp = icmp eq i32 %sub, 0
-  %cond = select i1 %cmp, i32 %c, i32 %sub
-  ret i32 %cond
-}
-; CHECK-LABEL: test0a
-; CHECK: sub.f %r7
-; CHECK: sel.eq
-
-; Function Attrs: norecurse nounwind readnone
-define i32 @test0b(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) #0 {
-entry:
-  %cmp = icmp eq i32 %b, %a
-  %cond = select i1 %cmp, i32 %c, i32 %b
-  ret i32 %cond
-}
-; CHECK-LABEL: test0b
-; CHECK: sub.f %r7, %r6, %r0
-; CHECK-NEXT: sel.eq
-
-; Function Attrs: norecurse nounwind readnone
-define i32 @test1a(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) #0 {
-entry:
-  %sub = sub i32 %b, %a
-  %cmp = icmp slt i32 %sub, 0
-  %cond = select i1 %cmp, i32 %c, i32 %d
-  ret i32 %cond
-}
-; CHECK-LABEL: test1a
-; CHECK: sub.f %r7, %r6
-; CHECK-NEXT: sel.mi
-
-; Function Attrs: norecurse nounwind readnone
-define i32 @test1b(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) #0 {
-entry:
-  %sub = sub i32 %b, %a
-  %cmp = icmp slt i32 %sub, 0
-  %cond = select i1 %cmp, i32 %c, i32 %d
-  ret i32 %cond
-}
-; CHECK-LABEL: test1b
-; CHECK: sub.f %r7, %r6
-; CHECK-NEXT: sel.mi
-
-; Function Attrs: norecurse nounwind readnone
-define i32 @test2a(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) #0 {
-entry:
-  %sub = sub i32 %b, %a
-  %cmp = icmp sgt i32 %sub, -1
-  %cond = select i1 %cmp, i32 %c, i32 %d
-  ret i32 %cond
-}
-; CHECK-LABEL: test2a
-; CHECK: sub.f %r7, %r6
-; CHECK: sel.pl
-
-; Function Attrs: norecurse nounwind readnone
-define i32 @test2b(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) #0 {
-entry:
-  %sub = sub i32 %b, %a
-  %cmp = icmp sgt i32 %sub, -1
-  %cond = select i1 %cmp, i32 %c, i32 %d
-  ret i32 %cond
-}
-; CHECK-LABEL: test2b
-; CHECK: sub.f %r7, %r6
-; CHECK: sel.pl
-
-; Function Attrs: norecurse nounwind readnone
-define i32 @test3(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) #0 {
-entry:
-  %sub = sub i32 %b, %a
-  %cmp = icmp slt i32 %sub, 1
-  %cond = select i1 %cmp, i32 %c, i32 %d
-  ret i32 %cond
-}
-
-; Function Attrs: norecurse nounwind readnone
-define i32 @test4(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) #0 {
-entry:
-  %cmp = icmp ne i32 %a, 0
-  %cmp1 = icmp ult i32 %a, %b
-  %or.cond = and i1 %cmp, %cmp1
-  br i1 %or.cond, label %return, label %if.end
-
-if.end:                                           ; preds = %entry
-  %cmp2 = icmp ne i32 %b, 0
-  %cmp4 = icmp ult i32 %b, %c
-  %or.cond29 = and i1 %cmp2, %cmp4
-  br i1 %or.cond29, label %return, label %if.end6
-
-if.end6:                                          ; preds = %if.end
-  %cmp7 = icmp ne i32 %c, 0
-  %cmp9 = icmp ult i32 %c, %d
-  %or.cond30 = and i1 %cmp7, %cmp9
-  br i1 %or.cond30, label %return, label %if.end11
-
-if.end11:                                         ; preds = %if.end6
-  %cmp12 = icmp ne i32 %d, 0
-  %cmp14 = icmp ult i32 %d, %a
-  %or.cond31 = and i1 %cmp12, %cmp14
-  %b. = select i1 %or.cond31, i32 %b, i32 21
-  ret i32 %b.
-
-return:                                           ; preds = %if.end6, %if.end, %entry
-  %retval.0 = phi i32 [ %c, %entry ], [ %d, %if.end ], [ %a, %if.end6 ]
-  ret i32 %retval.0
-}
-; CHECK-LABEL: test4
-; TODO: Re-enable test. This test is disabled post making the combiner more
-; conservative.
-; DISABLED_CHECK: and.f
-
-; Test to avoid incorrect fusing that spans across basic blocks
- at a = global i32 -1, align 4
- at b = global i32 0, align 4
-
-; Function Attrs: nounwind
-define void @testBB() {
-entry:
-  %0 = load i32, i32* @a, align 4, !tbaa !1
-  %1 = load i32, i32* @b, align 4, !tbaa !1
-  %sub.i = sub i32 %1, %0
-  %tobool = icmp sgt i32 %sub.i, -1
-  br i1 %tobool, label %if.end, label %if.then
-
-if.then:                                          ; preds = %entry
-  %call1 = tail call i32 bitcast (i32 (...)* @g to i32 ()*)()
-  br label %while.body
-
-while.body:                                       ; preds = %if.then, %while.body
-  br label %while.body
-
-if.end:                                           ; preds = %entry
-  %cmp.i = icmp slt i32 %sub.i, 1
-  br i1 %cmp.i, label %if.then4, label %if.end7
-
-if.then4:                                         ; preds = %if.end
-  %call5 = tail call i32 bitcast (i32 (...)* @g to i32 ()*)()
-  br label %while.body6
-
-while.body6:                                      ; preds = %if.then4, %while.body6
-  br label %while.body6
-
-if.end7:                                          ; preds = %if.end
-  ret void
-}
-
-declare i32 @g(...)
-; CHECK-LABEL: testBB
-; CHECK: sub.f {{.*}}, %r0
-
-!1 = !{!2, !2, i64 0}
-!2 = !{!"int", !3, i64 0}
-!3 = !{!"omnipotent char", !4, i64 0}
-!4 = !{!"Simple C/C++ TBAA"}

Added: llvm/trunk/test/CodeGen/Lanai/sub-cmp-peephole.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Lanai/sub-cmp-peephole.ll?rev=274807&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/Lanai/sub-cmp-peephole.ll (added)
+++ llvm/trunk/test/CodeGen/Lanai/sub-cmp-peephole.ll Thu Jul  7 18:36:04 2016
@@ -0,0 +1,109 @@
+; RUN: llc < %s -mtriple=lanai | FileCheck %s
+
+define i32 @f(i32 inreg %a, i32 inreg %b) nounwind ssp {
+entry:
+; CHECK-LABEL: f:
+; CHECK: sub.f %r6, %r7, [[IN:%.*]]
+; CHECK: sel.gt [[IN]], %r0, %rv
+  %cmp = icmp sgt i32 %a, %b
+  %sub = sub nsw i32 %a, %b
+  %sub. = select i1 %cmp, i32 %sub, i32 0
+  ret i32 %sub.
+}
+
+define i32 @g(i32 inreg %a, i32 inreg %b) nounwind ssp {
+entry:
+; CHECK-LABEL: g:
+; CHECK: sub.f %r7, %r6, [[IN:%.*]]
+; CHECK: sel.lt [[IN]], %r0, %rv
+  %cmp = icmp slt i32 %a, %b
+  %sub = sub nsw i32 %b, %a
+  %sub. = select i1 %cmp, i32 %sub, i32 0
+  ret i32 %sub.
+}
+
+define i32 @h(i32 inreg %a, i32 inreg %b) nounwind ssp {
+entry:
+; CHECK-LABEL: h:
+; CHECK: sub.f %r6, 0x3, [[IN:%.*]]
+; CHECK: sel.gt [[IN]], %r7, %rv
+  %cmp = icmp sgt i32 %a, 3
+  %sub = sub nsw i32 %a, 3
+  %sub. = select i1 %cmp, i32 %sub, i32 %b
+  ret i32 %sub.
+}
+
+define i32 @i(i32 inreg %a, i32 inreg %b) nounwind readnone ssp {
+entry:
+; CHECK-LABEL: i:
+; CHECK: sub.f %r7, %r6, [[IN:%.*]]
+; CHECK: sel.ult [[IN]], %r0, %rv
+  %cmp = icmp ult i32 %a, %b
+  %sub = sub i32 %b, %a
+  %sub. = select i1 %cmp, i32 %sub, i32 0
+  ret i32 %sub.
+}
+; If SR is live-out, we can't remove cmp if there exists a swapped sub.
+define i32 @j(i32 inreg %a, i32 inreg %b) nounwind {
+entry:
+; CHECK-LABEL: j:
+; CHECK: sub.f %r7, %r6, %r0
+; CHECK: sub %r6, %r7, %rv
+  %cmp = icmp eq i32 %b, %a
+  %sub = sub nsw i32 %a, %b
+  br i1 %cmp, label %if.then, label %if.else
+
+if.then:
+  %cmp2 = icmp sgt i32 %b, %a
+  %sel = select i1 %cmp2, i32 %sub, i32 %a
+  ret i32 %sel
+
+if.else:
+  ret i32 %sub
+}
+
+declare void @abort()
+declare void @exit(i32)
+ at t = common global i32 0
+
+; If the comparison uses the C bit (signed overflow/underflow), we can't
+; omit the comparison.
+define i32 @cmp_ult0(i32 inreg %a, i32 inreg %b, i32 inreg %x, i32 inreg %y) {
+entry:
+; CHECK-LABEL: cmp_ult0
+; CHECK: sub {{.*}}, 0x11, [[IN:%.*]]
+; CHECK: sub.f [[IN]], 0x0, %r0
+  %load = load i32, i32* @t, align 4
+  %sub = sub i32 %load, 17
+  %cmp = icmp ult i32 %sub, 0
+  br i1 %cmp, label %if.then, label %if.else
+
+if.then:
+  call void @abort()
+  unreachable
+
+if.else:
+  call void @exit(i32 0)
+  unreachable
+}
+
+; Same for the V bit.
+; TODO: add test that exercises V bit individually (VC/VS).
+define i32 @cmp_gt0(i32 inreg %a, i32 inreg %b, i32 inreg %x, i32 inreg %y) {
+entry:
+; CHECK-LABEL: cmp_gt0
+; CHECK: sub {{.*}}, 0x11, [[IN:%.*]]
+; CHECK: sub.f [[IN]], 0x1, %r0
+  %load = load i32, i32* @t, align 4
+  %sub = sub i32 %load, 17
+  %cmp = icmp sgt i32 %sub, 0
+  br i1 %cmp, label %if.then, label %if.else
+
+if.then:
+  call void @abort()
+  unreachable
+
+if.else:
+  call void @exit(i32 0)
+  unreachable
+}

Added: llvm/trunk/test/CodeGen/MIR/Lanai/lit.local.cfg
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/MIR/Lanai/lit.local.cfg?rev=274807&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/MIR/Lanai/lit.local.cfg (added)
+++ llvm/trunk/test/CodeGen/MIR/Lanai/lit.local.cfg Thu Jul  7 18:36:04 2016
@@ -0,0 +1,2 @@
+if not 'Lanai' in config.root.targets:
+    config.unsupported = True

Added: llvm/trunk/test/CodeGen/MIR/Lanai/peephole-compare.mir
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/MIR/Lanai/peephole-compare.mir?rev=274807&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/MIR/Lanai/peephole-compare.mir (added)
+++ llvm/trunk/test/CodeGen/MIR/Lanai/peephole-compare.mir Thu Jul  7 18:36:04 2016
@@ -0,0 +1,714 @@
+# RUN: llc -run-pass=peephole-opts %s -o /dev/null 2>&1 | FileCheck %s
+
+# Test the compare fold peephole.
+
+# CHECK-LABEL: name: test0a
+# TODO: Enhance combiner to handle this case. This expands into:
+#   sub     %r7, %r6, %r3
+#   sub.f   %r7, %r6, %r0
+#   sel.eq %r18, %r3, %rv
+# This is different from the pattern currently matched. If the lowered form had
+# been sub.f %r3, 0, %r0 then it would have matched.
+
+# CHECK-LABEL: name: test1a
+# CHECK: [[IN1:%.*]] = COPY %r7
+# CHECK: [[IN2:%.*]] = COPY %r6
+# CHECK: SUB_F_R [[IN1]], [[IN2]], 0, implicit-def %sr
+
+# CHECK-LABEL: name: test1b
+# CHECK: [[IN1:%.*]] = COPY %r7
+# CHECK: [[IN2:%.*]] = COPY %r6
+# CHECK: SUB_F_R [[IN1]], [[IN2]], 0, implicit-def %sr
+
+# CHECK-LABEL: name: test2a
+# CHECK: [[IN1:%.*]] = COPY %r7
+# CHECK: [[IN2:%.*]] = COPY %r6
+# CHECK: SUB_F_R [[IN1]], [[IN2]], 0, implicit-def %sr
+
+# CHECK-LABEL: name: test2b
+# CHECK: [[IN1:%.*]] = COPY %r7
+# CHECK: [[IN2:%.*]] = COPY %r6
+# CHECK: SUB_F_R [[IN1]], [[IN2]], 0, implicit-def %sr
+
+# CHECK-LABEL: name: test3
+# CHECK: AND_F_R
+# CHECK: AND_F_R
+# CHECK: AND_F_R
+
+--- |
+  target datalayout = "E-m:e-p:32:32-i64:64-a:0:32-n32-S64"
+  target triple = "lanai-unknown-unknown"
+  
+  @a = global i32 -1, align 4
+  @b = global i32 0, align 4
+  
+  define i32 @test0a(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) {
+  entry:
+    %sub = sub i32 %b, %a
+    %cmp = icmp eq i32 %sub, 0
+    %cond = select i1 %cmp, i32 %c, i32 %sub
+    ret i32 %cond
+  }
+  
+  define i32 @test0b(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) {
+  entry:
+    %cmp = icmp eq i32 %b, %a
+    %cond = select i1 %cmp, i32 %c, i32 %b
+    ret i32 %cond
+  }
+  
+  define i32 @test1a(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) {
+  entry:
+    %sub = sub i32 %b, %a
+    %cmp = icmp slt i32 %sub, 0
+    %cond = select i1 %cmp, i32 %c, i32 %d
+    ret i32 %cond
+  }
+  
+  define i32 @test1b(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) {
+  entry:
+    %sub = sub i32 %b, %a
+    %cmp = icmp slt i32 %sub, 0
+    %cond = select i1 %cmp, i32 %c, i32 %d
+    ret i32 %cond
+  }
+  
+  define i32 @test2a(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) {
+  entry:
+    %sub = sub i32 %b, %a
+    %cmp = icmp sgt i32 %sub, -1
+    %cond = select i1 %cmp, i32 %c, i32 %d
+    ret i32 %cond
+  }
+  
+  define i32 @test2b(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) {
+  entry:
+    %sub = sub i32 %b, %a
+    %cmp = icmp sgt i32 %sub, -1
+    %cond = select i1 %cmp, i32 %c, i32 %d
+    ret i32 %cond
+  }
+  
+  define i32 @test3(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) {
+  entry:
+    %sub = sub i32 %b, %a
+    %cmp = icmp slt i32 %sub, 1
+    %cond = select i1 %cmp, i32 %c, i32 %d
+    ret i32 %cond
+  }
+  
+  define i32 @test4(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) {
+  entry:
+    %cmp = icmp ne i32 %a, 0
+    %cmp1 = icmp ult i32 %a, %b
+    %or.cond = and i1 %cmp, %cmp1
+    br i1 %or.cond, label %return, label %if.end
+  
+  if.end:                                           ; preds = %entry
+    %cmp2 = icmp ne i32 %b, 0
+    %cmp4 = icmp ult i32 %b, %c
+    %or.cond29 = and i1 %cmp2, %cmp4
+    br i1 %or.cond29, label %return, label %if.end6
+  
+  if.end6:                                          ; preds = %if.end
+    %cmp7 = icmp ne i32 %c, 0
+    %cmp9 = icmp ult i32 %c, %d
+    %or.cond30 = and i1 %cmp7, %cmp9
+    br i1 %or.cond30, label %return, label %if.end11
+  
+  if.end11:                                         ; preds = %if.end6
+    %cmp12 = icmp ne i32 %d, 0
+    %cmp14 = icmp ult i32 %d, %a
+    %or.cond31 = and i1 %cmp12, %cmp14
+    %b. = select i1 %or.cond31, i32 %b, i32 21
+    ret i32 %b.
+  
+  return:                                           ; preds = %if.end6, %if.end, %entry
+    %retval.0 = phi i32 [ %c, %entry ], [ %d, %if.end ], [ %a, %if.end6 ]
+    ret i32 %retval.0
+  }
+  
+  define void @testBB() {
+  entry:
+    %0 = load i32, i32* @a, align 4, !tbaa !0
+    %1 = load i32, i32* @b, align 4, !tbaa !0
+    %sub.i = sub i32 %1, %0
+    %tobool = icmp sgt i32 %sub.i, -1
+    br i1 %tobool, label %if.end, label %if.then
+  
+  if.then:                                          ; preds = %entry
+    %call1 = tail call i32 bitcast (i32 (...)* @g to i32 ()*)()
+    br label %while.body
+  
+  while.body:                                       ; preds = %while.body, %if.then
+    br label %while.body
+  
+  if.end:                                           ; preds = %entry
+    %cmp.i = icmp slt i32 %sub.i, 1
+    br i1 %cmp.i, label %if.then4, label %if.end7
+  
+  if.then4:                                         ; preds = %if.end
+    %call5 = tail call i32 bitcast (i32 (...)* @g to i32 ()*)()
+    br label %while.body6
+  
+  while.body6:                                      ; preds = %while.body6, %if.then4
+    br label %while.body6
+  
+  if.end7:                                          ; preds = %if.end
+    ret void
+  }
+  
+  declare i32 @g(...)
+  
+  ; Function Attrs: nounwind
+  declare void @llvm.stackprotector(i8*, i8**) #0
+  
+  attributes #0 = { nounwind }
+  
+  !0 = !{!1, !1, i64 0}
+  !1 = !{!"int", !2, i64 0}
+  !2 = !{!"omnipotent char", !3, i64 0}
+  !3 = !{!"Simple C/C++ TBAA"}
+
+...
+---
+name:            test0a
+alignment:       2
+exposesReturnsTwice: false
+hasInlineAsm:    false
+allVRegsAllocated: false
+isSSA:           true
+tracksRegLiveness: true
+tracksSubRegLiveness: false
+registers:       
+  - { id: 0, class: gpr }
+  - { id: 1, class: gpr }
+  - { id: 2, class: gpr }
+  - { id: 3, class: gpr }
+  - { id: 4, class: gpr }
+  - { id: 5, class: gpr }
+liveins:         
+  - { reg: '%r6', virtual-reg: '%0' }
+  - { reg: '%r7', virtual-reg: '%1' }
+  - { reg: '%r18', virtual-reg: '%2' }
+frameInfo:       
+  isFrameAddressTaken: false
+  isReturnAddressTaken: false
+  hasStackMap:     false
+  hasPatchPoint:   false
+  stackSize:       0
+  offsetAdjustment: 0
+  maxAlignment:    0
+  adjustsStack:    false
+  hasCalls:        false
+  maxCallFrameSize: 0
+  hasOpaqueSPAdjustment: false
+  hasVAStart:      false
+  hasMustTailInVarArgFunc: false
+body:             |
+  bb.0.entry:
+    liveins: %r6, %r7, %r18
+  
+    %2 = COPY %r18
+    %1 = COPY %r7
+    %0 = COPY %r6
+    %4 = SUB_R %1, %0, 0
+    SFSUB_F_RI_LO %4, 0, implicit-def %sr
+    %5 = SELECT %2, %4, 7, implicit %sr
+    %rv = COPY %5
+    RET implicit %rca, implicit %rv
+
+...
+---
+name:            test0b
+alignment:       2
+exposesReturnsTwice: false
+hasInlineAsm:    false
+allVRegsAllocated: false
+isSSA:           true
+tracksRegLiveness: true
+tracksSubRegLiveness: false
+registers:       
+  - { id: 0, class: gpr }
+  - { id: 1, class: gpr }
+  - { id: 2, class: gpr }
+  - { id: 3, class: gpr }
+  - { id: 4, class: gpr }
+liveins:         
+  - { reg: '%r6', virtual-reg: '%0' }
+  - { reg: '%r7', virtual-reg: '%1' }
+  - { reg: '%r18', virtual-reg: '%2' }
+frameInfo:       
+  isFrameAddressTaken: false
+  isReturnAddressTaken: false
+  hasStackMap:     false
+  hasPatchPoint:   false
+  stackSize:       0
+  offsetAdjustment: 0
+  maxAlignment:    0
+  adjustsStack:    false
+  hasCalls:        false
+  maxCallFrameSize: 0
+  hasOpaqueSPAdjustment: false
+  hasVAStart:      false
+  hasMustTailInVarArgFunc: false
+body:             |
+  bb.0.entry:
+    liveins: %r6, %r7, %r18
+  
+    %2 = COPY %r18
+    %1 = COPY %r7
+    %0 = COPY %r6
+    SFSUB_F_RR %1, %0, implicit-def %sr
+    %4 = SELECT %2, %1, 7, implicit %sr
+    %rv = COPY %4
+    RET implicit %rca, implicit %rv
+
+...
+---
+name:            test1a
+alignment:       2
+exposesReturnsTwice: false
+hasInlineAsm:    false
+allVRegsAllocated: false
+isSSA:           true
+tracksRegLiveness: true
+tracksSubRegLiveness: false
+registers:       
+  - { id: 0, class: gpr }
+  - { id: 1, class: gpr }
+  - { id: 2, class: gpr }
+  - { id: 3, class: gpr }
+  - { id: 4, class: gpr }
+  - { id: 5, class: gpr }
+liveins:         
+  - { reg: '%r6', virtual-reg: '%0' }
+  - { reg: '%r7', virtual-reg: '%1' }
+  - { reg: '%r18', virtual-reg: '%2' }
+  - { reg: '%r19', virtual-reg: '%3' }
+frameInfo:       
+  isFrameAddressTaken: false
+  isReturnAddressTaken: false
+  hasStackMap:     false
+  hasPatchPoint:   false
+  stackSize:       0
+  offsetAdjustment: 0
+  maxAlignment:    0
+  adjustsStack:    false
+  hasCalls:        false
+  maxCallFrameSize: 0
+  hasOpaqueSPAdjustment: false
+  hasVAStart:      false
+  hasMustTailInVarArgFunc: false
+body:             |
+  bb.0.entry:
+    liveins: %r6, %r7, %r18, %r19
+  
+    %3 = COPY %r19
+    %2 = COPY %r18
+    %1 = COPY %r7
+    %0 = COPY %r6
+    %4 = SUB_R %1, %0, 0
+    SFSUB_F_RI_LO killed %4, 0, implicit-def %sr
+    %5 = SELECT %2, %3, 11, implicit %sr
+    %rv = COPY %5
+    RET implicit %rca, implicit %rv
+
+...
+---
+name:            test1b
+alignment:       2
+exposesReturnsTwice: false
+hasInlineAsm:    false
+allVRegsAllocated: false
+isSSA:           true
+tracksRegLiveness: true
+tracksSubRegLiveness: false
+registers:       
+  - { id: 0, class: gpr }
+  - { id: 1, class: gpr }
+  - { id: 2, class: gpr }
+  - { id: 3, class: gpr }
+  - { id: 4, class: gpr }
+  - { id: 5, class: gpr }
+liveins:         
+  - { reg: '%r6', virtual-reg: '%0' }
+  - { reg: '%r7', virtual-reg: '%1' }
+  - { reg: '%r18', virtual-reg: '%2' }
+  - { reg: '%r19', virtual-reg: '%3' }
+frameInfo:       
+  isFrameAddressTaken: false
+  isReturnAddressTaken: false
+  hasStackMap:     false
+  hasPatchPoint:   false
+  stackSize:       0
+  offsetAdjustment: 0
+  maxAlignment:    0
+  adjustsStack:    false
+  hasCalls:        false
+  maxCallFrameSize: 0
+  hasOpaqueSPAdjustment: false
+  hasVAStart:      false
+  hasMustTailInVarArgFunc: false
+body:             |
+  bb.0.entry:
+    liveins: %r6, %r7, %r18, %r19
+  
+    %3 = COPY %r19
+    %2 = COPY %r18
+    %1 = COPY %r7
+    %0 = COPY %r6
+    %4 = SUB_R %1, %0, 0
+    SFSUB_F_RI_LO killed %4, 0, implicit-def %sr
+    %5 = SELECT %2, %3, 11, implicit %sr
+    %rv = COPY %5
+    RET implicit %rca, implicit %rv
+
+...
+---
+name:            test2a
+alignment:       2
+exposesReturnsTwice: false
+hasInlineAsm:    false
+allVRegsAllocated: false
+isSSA:           true
+tracksRegLiveness: true
+tracksSubRegLiveness: false
+registers:       
+  - { id: 0, class: gpr }
+  - { id: 1, class: gpr }
+  - { id: 2, class: gpr }
+  - { id: 3, class: gpr }
+  - { id: 4, class: gpr }
+  - { id: 5, class: gpr }
+liveins:         
+  - { reg: '%r6', virtual-reg: '%0' }
+  - { reg: '%r7', virtual-reg: '%1' }
+  - { reg: '%r18', virtual-reg: '%2' }
+  - { reg: '%r19', virtual-reg: '%3' }
+frameInfo:       
+  isFrameAddressTaken: false
+  isReturnAddressTaken: false
+  hasStackMap:     false
+  hasPatchPoint:   false
+  stackSize:       0
+  offsetAdjustment: 0
+  maxAlignment:    0
+  adjustsStack:    false
+  hasCalls:        false
+  maxCallFrameSize: 0
+  hasOpaqueSPAdjustment: false
+  hasVAStart:      false
+  hasMustTailInVarArgFunc: false
+body:             |
+  bb.0.entry:
+    liveins: %r6, %r7, %r18, %r19
+  
+    %3 = COPY %r19
+    %2 = COPY %r18
+    %1 = COPY %r7
+    %0 = COPY %r6
+    %4 = SUB_R %1, %0, 0
+    SFSUB_F_RI_LO killed %4, 0, implicit-def %sr
+    %5 = SELECT %2, %3, 10, implicit %sr
+    %rv = COPY %5
+    RET implicit %rca, implicit %rv
+
+...
+---
+name:            test2b
+alignment:       2
+exposesReturnsTwice: false
+hasInlineAsm:    false
+allVRegsAllocated: false
+isSSA:           true
+tracksRegLiveness: true
+tracksSubRegLiveness: false
+registers:       
+  - { id: 0, class: gpr }
+  - { id: 1, class: gpr }
+  - { id: 2, class: gpr }
+  - { id: 3, class: gpr }
+  - { id: 4, class: gpr }
+  - { id: 5, class: gpr }
+liveins:         
+  - { reg: '%r6', virtual-reg: '%0' }
+  - { reg: '%r7', virtual-reg: '%1' }
+  - { reg: '%r18', virtual-reg: '%2' }
+  - { reg: '%r19', virtual-reg: '%3' }
+frameInfo:       
+  isFrameAddressTaken: false
+  isReturnAddressTaken: false
+  hasStackMap:     false
+  hasPatchPoint:   false
+  stackSize:       0
+  offsetAdjustment: 0
+  maxAlignment:    0
+  adjustsStack:    false
+  hasCalls:        false
+  maxCallFrameSize: 0
+  hasOpaqueSPAdjustment: false
+  hasVAStart:      false
+  hasMustTailInVarArgFunc: false
+body:             |
+  bb.0.entry:
+    liveins: %r6, %r7, %r18, %r19
+  
+    %3 = COPY %r19
+    %2 = COPY %r18
+    %1 = COPY %r7
+    %0 = COPY %r6
+    %4 = SUB_R %1, %0, 0
+    SFSUB_F_RI_LO killed %4, 0, implicit-def %sr
+    %5 = SELECT %2, %3, 10, implicit %sr
+    %rv = COPY %5
+    RET implicit %rca, implicit %rv
+
+...
+---
+name:            test3
+alignment:       2
+exposesReturnsTwice: false
+hasInlineAsm:    false
+allVRegsAllocated: false
+isSSA:           true
+tracksRegLiveness: true
+tracksSubRegLiveness: false
+registers:       
+  - { id: 0, class: gpr }
+  - { id: 1, class: gpr }
+  - { id: 2, class: gpr }
+  - { id: 3, class: gpr }
+  - { id: 4, class: gpr }
+  - { id: 5, class: gpr }
+liveins:         
+  - { reg: '%r6', virtual-reg: '%0' }
+  - { reg: '%r7', virtual-reg: '%1' }
+  - { reg: '%r18', virtual-reg: '%2' }
+  - { reg: '%r19', virtual-reg: '%3' }
+frameInfo:       
+  isFrameAddressTaken: false
+  isReturnAddressTaken: false
+  hasStackMap:     false
+  hasPatchPoint:   false
+  stackSize:       0
+  offsetAdjustment: 0
+  maxAlignment:    0
+  adjustsStack:    false
+  hasCalls:        false
+  maxCallFrameSize: 0
+  hasOpaqueSPAdjustment: false
+  hasVAStart:      false
+  hasMustTailInVarArgFunc: false
+body:             |
+  bb.0.entry:
+    liveins: %r6, %r7, %r18, %r19
+  
+    %3 = COPY %r19
+    %2 = COPY %r18
+    %1 = COPY %r7
+    %0 = COPY %r6
+    %4 = SUB_R %1, %0, 0
+    SFSUB_F_RI_LO killed %4, 1, implicit-def %sr
+    %5 = SELECT %2, %3, 13, implicit %sr
+    %rv = COPY %5
+    RET implicit %rca, implicit %rv
+
+...
+---
+name:            test4
+alignment:       2
+exposesReturnsTwice: false
+hasInlineAsm:    false
+allVRegsAllocated: false
+isSSA:           true
+tracksRegLiveness: true
+tracksSubRegLiveness: false
+registers:       
+  - { id: 0, class: gpr }
+  - { id: 1, class: gpr }
+  - { id: 2, class: gpr }
+  - { id: 3, class: gpr }
+  - { id: 4, class: gpr }
+  - { id: 5, class: gpr }
+  - { id: 6, class: gpr }
+  - { id: 7, class: gpr }
+  - { id: 8, class: gpr }
+  - { id: 9, class: gpr }
+  - { id: 10, class: gpr }
+  - { id: 11, class: gpr }
+  - { id: 12, class: gpr }
+  - { id: 13, class: gpr }
+  - { id: 14, class: gpr }
+  - { id: 15, class: gpr }
+  - { id: 16, class: gpr }
+  - { id: 17, class: gpr }
+  - { id: 18, class: gpr }
+  - { id: 19, class: gpr }
+  - { id: 20, class: gpr }
+  - { id: 21, class: gpr }
+  - { id: 22, class: gpr }
+liveins:         
+  - { reg: '%r6', virtual-reg: '%1' }
+  - { reg: '%r7', virtual-reg: '%2' }
+  - { reg: '%r18', virtual-reg: '%3' }
+  - { reg: '%r19', virtual-reg: '%4' }
+frameInfo:       
+  isFrameAddressTaken: false
+  isReturnAddressTaken: false
+  hasStackMap:     false
+  hasPatchPoint:   false
+  stackSize:       0
+  offsetAdjustment: 0
+  maxAlignment:    0
+  adjustsStack:    false
+  hasCalls:        false
+  maxCallFrameSize: 0
+  hasOpaqueSPAdjustment: false
+  hasVAStart:      false
+  hasMustTailInVarArgFunc: false
+body:             |
+  bb.0.entry:
+    successors: %bb.4.return, %bb.1.if.end
+    liveins: %r6, %r7, %r18, %r19
+  
+    %4 = COPY %r19
+    %3 = COPY %r18
+    %2 = COPY %r7
+    %1 = COPY %r6
+    SFSUB_F_RI_LO %1, 0, implicit-def %sr
+    %5 = SCC 6, implicit %sr
+    SFSUB_F_RR %1, %2, implicit-def %sr
+    %6 = SCC 4, implicit %sr
+    %7 = AND_R killed %5, killed %6, 0
+    %8 = SLI 1
+    %9 = AND_R killed %7, %8, 0
+    SFSUB_F_RI_LO killed %9, 0, implicit-def %sr
+    BRCC %bb.4.return, 6, implicit %sr
+    BT %bb.1.if.end
+  
+  bb.1.if.end:
+    successors: %bb.4.return, %bb.2.if.end6
+  
+    SFSUB_F_RI_LO %2, 0, implicit-def %sr
+    %10 = SCC 6, implicit %sr
+    SFSUB_F_RR %2, %3, implicit-def %sr
+    %11 = SCC 4, implicit %sr
+    %12 = AND_R killed %10, killed %11, 0
+    %14 = AND_R killed %12, %8, 0
+    SFSUB_F_RI_LO killed %14, 0, implicit-def %sr
+    BRCC %bb.4.return, 6, implicit %sr
+    BT %bb.2.if.end6
+  
+  bb.2.if.end6:
+    successors: %bb.4.return, %bb.3.if.end11
+  
+    SFSUB_F_RI_LO %3, 0, implicit-def %sr
+    %15 = SCC 6, implicit %sr
+    SFSUB_F_RR %3, %4, implicit-def %sr
+    %16 = SCC 4, implicit %sr
+    %17 = AND_R killed %15, killed %16, 0
+    %18 = SLI 1
+    %19 = AND_R killed %17, killed %18, 0
+    SFSUB_F_RI_LO killed %19, 0, implicit-def %sr
+    BRCC %bb.4.return, 6, implicit %sr
+    BT %bb.3.if.end11
+  
+  bb.3.if.end11:
+    %20 = SLI 21
+    SFSUB_F_RR %4, %1, implicit-def %sr
+    %21 = SELECT %2, %20, 4, implicit %sr
+    SFSUB_F_RI_LO %4, 0, implicit-def %sr
+    %22 = SELECT killed %21, %20, 6, implicit %sr
+    %rv = COPY %22
+    RET implicit %rca, implicit %rv
+  
+  bb.4.return:
+    %0 = PHI %3, %bb.0.entry, %4, %bb.1.if.end, %1, %bb.2.if.end6
+    %rv = COPY %0
+    RET implicit %rca, implicit %rv
+
+...
+---
+name:            testBB
+alignment:       2
+exposesReturnsTwice: false
+hasInlineAsm:    false
+allVRegsAllocated: false
+isSSA:           true
+tracksRegLiveness: true
+tracksSubRegLiveness: false
+registers:       
+  - { id: 0, class: gpr }
+  - { id: 1, class: gpr }
+  - { id: 2, class: gpr }
+  - { id: 3, class: gpr }
+  - { id: 4, class: gpr }
+  - { id: 5, class: gpr }
+  - { id: 6, class: gpr }
+  - { id: 7, class: gpr }
+  - { id: 8, class: gpr }
+frameInfo:       
+  isFrameAddressTaken: false
+  isReturnAddressTaken: false
+  hasStackMap:     false
+  hasPatchPoint:   false
+  stackSize:       0
+  offsetAdjustment: 0
+  maxAlignment:    0
+  adjustsStack:    false
+  hasCalls:        true
+  maxCallFrameSize: 0
+  hasOpaqueSPAdjustment: false
+  hasVAStart:      false
+  hasMustTailInVarArgFunc: false
+body:             |
+  bb.0.entry:
+    successors: %bb.3.if.end, %bb.1.if.then
+  
+    %1 = MOVHI target-flags(lanai-hi) @a
+    %2 = OR_I_LO killed %1, target-flags(lanai-lo) @a
+    %3 = LDW_RI killed %2, 0, 0 :: (load 4 from @a, !tbaa !0)
+    %4 = MOVHI target-flags(lanai-hi) @b
+    %5 = OR_I_LO killed %4, target-flags(lanai-lo) @b
+    %6 = LDW_RI killed %5, 0, 0 :: (load 4 from @b, !tbaa !0)
+    %0 = SUB_R killed %6, killed %3, 0
+    SFSUB_F_RI_LO %0, 0, implicit-def %sr
+    BRCC %bb.3.if.end, 10, implicit %sr
+    BT %bb.1.if.then
+  
+  bb.1.if.then:
+    successors: %bb.2.while.body
+  
+    ADJCALLSTACKDOWN 0, implicit-def dead %sp, implicit %sp
+    CALL @g, csr, implicit-def dead %rca, implicit %sp, implicit-def %sp, implicit-def %rv
+    ADJCALLSTACKUP 0, 0, implicit-def dead %sp, implicit %sp
+  
+  bb.2.while.body:
+    successors: %bb.2.while.body
+  
+    BT %bb.2.while.body
+  
+  bb.3.if.end:
+    successors: %bb.4.if.then4, %bb.6.if.end7
+    liveins: %sr
+  
+    BRCC %bb.6.if.end7, 14, implicit %sr
+    BT %bb.4.if.then4
+  
+  bb.4.if.then4:
+    successors: %bb.5.while.body6
+  
+    ADJCALLSTACKDOWN 0, implicit-def dead %sp, implicit %sp
+    CALL @g, csr, implicit-def dead %rca, implicit %sp, implicit-def %sp, implicit-def %rv
+    ADJCALLSTACKUP 0, 0, implicit-def dead %sp, implicit %sp
+  
+  bb.5.while.body6:
+    successors: %bb.5.while.body6
+  
+    BT %bb.5.while.body6
+  
+  bb.6.if.end7:
+    RET implicit %rca
+
+...

Modified: llvm/trunk/test/MC/Lanai/v11.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/Lanai/v11.s?rev=274807&r1=274806&r2=274807&view=diff
==============================================================================
--- llvm/trunk/test/MC/Lanai/v11.s (original)
+++ llvm/trunk/test/MC/Lanai/v11.s Thu Jul  7 18:36:04 2016
@@ -12,13 +12,13 @@ add.f %r17, 0x00001234, %r21
 ! CHECK: 0x0a,0xc6,0x12,0x34
 add.f %r17, 0x12340000, %r21
 ! CHECK: 0x0a,0xc7,0x12,0x34
-add %r17, %r18, %r21
+add.t %r17, %r18, %r21
 ! CHECK: 0xca,0xc4,0x90,0x00
-add.f %r17, %r18, %r21
+add.f.t %r17, %r18, %r21
 ! CHECK: 0xca,0xc6,0x90,0x00
-addc %r17, %r18, %r21
+addc.t %r17, %r18, %r21
 ! CHECK: 0xca,0xc4,0x91,0x00
-addc.f %r17, %r18, %r21
+addc.f.t %r17, %r18, %r21
 ! CHECK: 0xca,0xc6,0x91,0x00
 addc %r17, 0, %r21
 ! CHECK: 0x1a,0xc4,0x00,0x00
@@ -40,9 +40,9 @@ and.f %r17, 0xffff1234, %r21
 ! CHECK: 0x4a,0xc6,0x12,0x34
 and.f %r17, 0x1234ffff, %r21
 ! CHECK: 0x4a,0xc7,0x12,0x34
-and %r17, %r18, %r21
+and.t %r17, %r18, %r21
 ! CHECK: 0xca,0xc4,0x94,0x00
-and.f %r17, %r18, %r21
+and.f.t %r17, %r18, %r21
 ! CHECK: 0xca,0xc6,0x94,0x00
 bt 0x123454
 ! CHECK: 0xe0,0x12,0x34,0x54
@@ -418,9 +418,9 @@ or.f %r17, 0x00001234, %r21
 ! CHECK: 0x5a,0xc6,0x12,0x34
 or.f %r17, 0x12340000, %r21
 ! CHECK: 0x5a,0xc7,0x12,0x34
-or %r17, %r18, %r21
+or.t %r17, %r18, %r21
 ! CHECK: 0xca,0xc4,0x95,0x00
-or.f %r17, %r18, %r21
+or.f.t %r17, %r18, %r21
 ! CHECK: 0xca,0xc6,0x95,0x00
 popc %r17, %r21
 ! CHECK: 0xda,0xc4,0x00,0x01
@@ -790,9 +790,9 @@ sub.f %r17, 0x00001234, %r21
 ! CHECK: 0x2a,0xc6,0x12,0x34
 sub.f %r17, 0x12340000, %r21
 ! CHECK: 0x2a,0xc7,0x12,0x34
-sub %r17, %r18, %r21
+sub.t %r17, %r18, %r21
 ! CHECK: 0xca,0xc4,0x92,0x00
-sub.f %r17, %r18, %r21
+sub.f.t %r17, %r18, %r21
 ! CHECK: 0xca,0xc6,0x92,0x00
 subb %r17, 0, %r21
 ! CHECK: 0x3a,0xc4,0x00,0x00
@@ -806,9 +806,9 @@ subb.f %r17, 0x00001234, %r21
 ! CHECK: 0x3a,0xc6,0x12,0x34
 subb.f %r17, 0x12340000, %r21
 ! CHECK: 0x3a,0xc7,0x12,0x34
-subb %r17, %r18, %r21
+subb.t %r17, %r18, %r21
 ! CHECK: 0xca,0xc4,0x93,0x00
-subb.f %r17, %r18, %r21
+subb.f.t %r17, %r18, %r21
 ! CHECK: 0xca,0xc6,0x93,0x00
 xor %r17, 0, %r21
 ! CHECK: 0x6a,0xc4,0x00,0x00
@@ -822,9 +822,21 @@ xor.f %r17, 0x00001234, %r21
 ! CHECK: 0x6a,0xc6,0x12,0x34
 xor.f %r17, 0x12340000, %r21
 ! CHECK: 0x6a,0xc7,0x12,0x34
-xor %r17, %r18, %r21
+xor.t %r17, %r18, %r21
 ! CHECK: 0xca,0xc4,0x96,0x00
-xor.f %r17, %r18, %r21
+xor.f.t %r17, %r18, %r21
 ! CHECK: 0xca,0xc6,0x96,0x00
-
-
+sel.ne %r9, %r15, %r12
+! CHECK: 0xc6,0x24,0x7f,0x03
+sel.gt %r9, %r15, %r12
+! CHECK: 0xc6,0x24,0x7f,0x07
+xor.lt %r17, %r18, %r21
+! CHECK: 0xca,0xc5,0x96,0x06
+xor.f.eq %r17, %r18, %r21
+! CHECK: 0xca,0xc7,0x96,0x03
+add.ge %r13, %r14, %r18
+! CHECK: 0xc9,0x34,0x70,0x06
+spl %r19
+! CHECK: 0xea,0x4c,0x00,0x02
+bt 0x1234
+! CHECK: 0xe0,0x00,0x12,0x34




More information about the llvm-commits mailing list