[llvm] fef80a2 - [VE] (conditional) branch modification & isel patterns

Simon Moll via llvm-commits llvm-commits at lists.llvm.org
Wed Jan 29 08:41:29 PST 2020


Author: Kazushi (Jam) Marukawa
Date: 2020-01-29T17:40:57+01:00
New Revision: fef80a2946e5d910deea818ae6db3ef0c4845a5b

URL: https://github.com/llvm/llvm-project/commit/fef80a2946e5d910deea818ae6db3ef0c4845a5b
DIFF: https://github.com/llvm/llvm-project/commit/fef80a2946e5d910deea818ae6db3ef0c4845a5b.diff

LOG: [VE] (conditional) branch modification & isel patterns

Summary:
InstInfo for branch modification, (conditional) branch isel patterns and tests.

Reviewed By: arsenm

Differential Revision: https://reviews.llvm.org/D73632

Added: 
    llvm/test/CodeGen/VE/branch1.ll

Modified: 
    llvm/lib/Target/VE/VEISelDAGToDAG.cpp
    llvm/lib/Target/VE/VEISelLowering.cpp
    llvm/lib/Target/VE/VEISelLowering.h
    llvm/lib/Target/VE/VEInstrInfo.cpp
    llvm/lib/Target/VE/VEInstrInfo.h
    llvm/lib/Target/VE/VEInstrInfo.td

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/VE/VEISelDAGToDAG.cpp b/llvm/lib/Target/VE/VEISelDAGToDAG.cpp
index 236611d34dc0..bb7ab594ebc3 100644
--- a/llvm/lib/Target/VE/VEISelDAGToDAG.cpp
+++ b/llvm/lib/Target/VE/VEISelDAGToDAG.cpp
@@ -44,6 +44,7 @@ class VEDAGToDAGISel : public SelectionDAGISel {
   void Select(SDNode *N) override;
 
   // Complex Pattern Selectors.
+  bool SelectADDRrr(SDValue N, SDValue &R1, SDValue &R2);
   bool SelectADDRri(SDValue N, SDValue &Base, SDValue &Offset);
 
   StringRef getPassName() const override {
@@ -55,6 +56,29 @@ class VEDAGToDAGISel : public SelectionDAGISel {
 };
 } // end anonymous namespace
 
+bool VEDAGToDAGISel::SelectADDRrr(SDValue Addr, SDValue &R1, SDValue &R2) {
+  if (Addr.getOpcode() == ISD::FrameIndex)
+    return false;
+  if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
+      Addr.getOpcode() == ISD::TargetGlobalAddress ||
+      Addr.getOpcode() == ISD::TargetGlobalTLSAddress)
+    return false; // direct calls.
+
+  if (Addr.getOpcode() == ISD::ADD) {
+    if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
+      if (isInt<13>(CN->getSExtValue()))
+        return false; // Let the reg+imm pattern catch this!
+    if (Addr.getOperand(0).getOpcode() == VEISD::Lo ||
+        Addr.getOperand(1).getOpcode() == VEISD::Lo)
+      return false; // Let the reg+imm pattern catch this!
+    R1 = Addr.getOperand(0);
+    R2 = Addr.getOperand(1);
+    return true;
+  }
+
+  return false; // Let the reg+imm pattern catch this!
+}
+
 bool VEDAGToDAGISel::SelectADDRri(SDValue Addr, SDValue &Base,
                                   SDValue &Offset) {
   auto AddrTy = Addr->getValueType(0);

diff  --git a/llvm/lib/Target/VE/VEISelLowering.cpp b/llvm/lib/Target/VE/VEISelLowering.cpp
index eae71465b55c..8401e67f6f75 100644
--- a/llvm/lib/Target/VE/VEISelLowering.cpp
+++ b/llvm/lib/Target/VE/VEISelLowering.cpp
@@ -497,8 +497,9 @@ VETargetLowering::VETargetLowering(const TargetMachine &TM,
   addRegisterClass(MVT::f32, &VE::F32RegClass);
   addRegisterClass(MVT::f64, &VE::I64RegClass);
 
-  // Custom legalize GlobalAddress nodes into LO/HI parts.
+  // Custom legalize address nodes into LO/HI parts.
   MVT PtrVT = MVT::getIntegerVT(TM.getPointerSizeInBits(0));
+  setOperationAction(ISD::BlockAddress, PtrVT, Custom);
   setOperationAction(ISD::GlobalAddress, PtrVT, Custom);
 
   // VE has no REM or DIVREM operations.
@@ -554,6 +555,10 @@ SDValue VETargetLowering::withTargetFlags(SDValue Op, unsigned TF,
     return DAG.getTargetGlobalAddress(GA->getGlobal(), SDLoc(GA),
                                       GA->getValueType(0), GA->getOffset(), TF);
 
+  if (const BlockAddressSDNode *BA = dyn_cast<BlockAddressSDNode>(Op))
+    return DAG.getTargetBlockAddress(BA->getBlockAddress(), Op.getValueType(),
+                                     0, TF);
+
   llvm_unreachable("Unhandled address SDNode");
 }
 
@@ -594,10 +599,17 @@ SDValue VETargetLowering::LowerGlobalAddress(SDValue Op,
   return makeAddress(Op, DAG);
 }
 
+SDValue VETargetLowering::LowerBlockAddress(SDValue Op,
+                                            SelectionDAG &DAG) const {
+  return makeAddress(Op, DAG);
+}
+
 SDValue VETargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
   switch (Op.getOpcode()) {
   default:
     llvm_unreachable("Should not custom lower this!");
+  case ISD::BlockAddress:
+    return LowerBlockAddress(Op, DAG);
   case ISD::GlobalAddress:
     return LowerGlobalAddress(Op, DAG);
   }

diff  --git a/llvm/lib/Target/VE/VEISelLowering.h b/llvm/lib/Target/VE/VEISelLowering.h
index 8be851378d7a..df67380c5ac5 100644
--- a/llvm/lib/Target/VE/VEISelLowering.h
+++ b/llvm/lib/Target/VE/VEISelLowering.h
@@ -71,6 +71,7 @@ class VETargetLowering : public TargetLowering {
   /// Custom Lower {
   SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override;
 
+  SDValue LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const;
   /// } Custom Lower
 

diff  --git a/llvm/lib/Target/VE/VEInstrInfo.cpp b/llvm/lib/Target/VE/VEInstrInfo.cpp
index bbd68196ada2..6336ed224cbd 100644
--- a/llvm/lib/Target/VE/VEInstrInfo.cpp
+++ b/llvm/lib/Target/VE/VEInstrInfo.cpp
@@ -38,6 +38,243 @@ VEInstrInfo::VEInstrInfo(VESubtarget &ST)
     : VEGenInstrInfo(VE::ADJCALLSTACKDOWN, VE::ADJCALLSTACKUP), RI(),
       Subtarget(ST) {}
 
+static bool IsIntegerCC(unsigned CC) { return (CC < VECC::CC_AF); }
+
+static VECC::CondCodes GetOppositeBranchCondition(VECC::CondCodes CC) {
+  switch(CC) {
+  case VECC::CC_IG:     return VECC::CC_ILE;
+  case VECC::CC_IL:     return VECC::CC_IGE;
+  case VECC::CC_INE:    return VECC::CC_IEQ;
+  case VECC::CC_IEQ:    return VECC::CC_INE;
+  case VECC::CC_IGE:    return VECC::CC_IL;
+  case VECC::CC_ILE:    return VECC::CC_IG;
+  case VECC::CC_AF:     return VECC::CC_AT;
+  case VECC::CC_G:      return VECC::CC_LENAN;
+  case VECC::CC_L:      return VECC::CC_GENAN;
+  case VECC::CC_NE:     return VECC::CC_EQNAN;
+  case VECC::CC_EQ:     return VECC::CC_NENAN;
+  case VECC::CC_GE:     return VECC::CC_LNAN;
+  case VECC::CC_LE:     return VECC::CC_GNAN;
+  case VECC::CC_NUM:    return VECC::CC_NAN;
+  case VECC::CC_NAN:    return VECC::CC_NUM;
+  case VECC::CC_GNAN:   return VECC::CC_LE;
+  case VECC::CC_LNAN:   return VECC::CC_GE;
+  case VECC::CC_NENAN:  return VECC::CC_EQ;
+  case VECC::CC_EQNAN:  return VECC::CC_NE;
+  case VECC::CC_GENAN:  return VECC::CC_L;
+  case VECC::CC_LENAN:  return VECC::CC_G;
+  case VECC::CC_AT:     return VECC::CC_AF;
+  }
+  llvm_unreachable("Invalid cond code");
+}
+
+// Treat br.l [BCR AT] as unconditional branch
+static bool isUncondBranchOpcode(int Opc) {
+  return Opc == VE::BCRLa || Opc == VE::BCRWa ||
+         Opc == VE::BCRDa || Opc == VE::BCRSa;
+}
+
+static bool isCondBranchOpcode(int Opc) {
+  return Opc == VE::BCRLrr  || Opc == VE::BCRLir  ||
+         Opc == VE::BCRLrm0 || Opc == VE::BCRLrm1 ||
+         Opc == VE::BCRLim0 || Opc == VE::BCRLim1 ||
+         Opc == VE::BCRWrr  || Opc == VE::BCRWir  ||
+         Opc == VE::BCRWrm0 || Opc == VE::BCRWrm1 ||
+         Opc == VE::BCRWim0 || Opc == VE::BCRWim1 ||
+         Opc == VE::BCRDrr  || Opc == VE::BCRDir  ||
+         Opc == VE::BCRDrm0 || Opc == VE::BCRDrm1 ||
+         Opc == VE::BCRDim0 || Opc == VE::BCRDim1 ||
+         Opc == VE::BCRSrr  || Opc == VE::BCRSir  ||
+         Opc == VE::BCRSrm0 || Opc == VE::BCRSrm1 ||
+         Opc == VE::BCRSim0 || Opc == VE::BCRSim1;
+}
+
+static void parseCondBranch(MachineInstr *LastInst, MachineBasicBlock *&Target,
+                            SmallVectorImpl<MachineOperand> &Cond) {
+  Cond.push_back(MachineOperand::CreateImm(LastInst->getOperand(0).getImm()));
+  Cond.push_back(LastInst->getOperand(1));
+  Cond.push_back(LastInst->getOperand(2));
+  Target = LastInst->getOperand(3).getMBB();
+}
+
+bool VEInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
+                                   MachineBasicBlock *&TBB,
+                                   MachineBasicBlock *&FBB,
+                                   SmallVectorImpl<MachineOperand> &Cond,
+                                   bool AllowModify) const {
+  MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();
+  if (I == MBB.end())
+    return false;
+
+  if (!isUnpredicatedTerminator(*I))
+    return false;
+
+  // Get the last instruction in the block.
+  MachineInstr *LastInst = &*I;
+  unsigned LastOpc = LastInst->getOpcode();
+
+  // If there is only one terminator instruction, process it.
+  if (I == MBB.begin() || !isUnpredicatedTerminator(*--I)) {
+    if (isUncondBranchOpcode(LastOpc)) {
+      TBB = LastInst->getOperand(0).getMBB();
+      return false;
+    }
+    if (isCondBranchOpcode(LastOpc)) {
+      // Block ends with fall-through condbranch.
+      parseCondBranch(LastInst, TBB, Cond);
+      return false;
+    }
+    return true; // Can't handle indirect branch.
+  }
+
+  // Get the instruction before it if it is a terminator.
+  MachineInstr *SecondLastInst = &*I;
+  unsigned SecondLastOpc = SecondLastInst->getOpcode();
+
+  // If AllowModify is true and the block ends with two or more unconditional
+  // branches, delete all but the first unconditional branch.
+  if (AllowModify && isUncondBranchOpcode(LastOpc)) {
+    while (isUncondBranchOpcode(SecondLastOpc)) {
+      LastInst->eraseFromParent();
+      LastInst = SecondLastInst;
+      LastOpc = LastInst->getOpcode();
+      if (I == MBB.begin() || !isUnpredicatedTerminator(*--I)) {
+        // Return now the only terminator is an unconditional branch.
+        TBB = LastInst->getOperand(0).getMBB();
+        return false;
+      }
+      SecondLastInst = &*I;
+      SecondLastOpc = SecondLastInst->getOpcode();
+    }
+  }
+
+  // If there are three terminators, we don't know what sort of block this is.
+  if (SecondLastInst && I != MBB.begin() && isUnpredicatedTerminator(*--I))
+    return true;
+
+  // If the block ends with a B and a Bcc, handle it.
+  if (isCondBranchOpcode(SecondLastOpc) && isUncondBranchOpcode(LastOpc)) {
+    parseCondBranch(SecondLastInst, TBB, Cond);
+    FBB = LastInst->getOperand(0).getMBB();
+    return false;
+  }
+
+  // If the block ends with two unconditional branches, handle it.  The second
+  // one is not executed.
+  if (isUncondBranchOpcode(SecondLastOpc) && isUncondBranchOpcode(LastOpc)) {
+    TBB = SecondLastInst->getOperand(0).getMBB();
+    return false;
+  }
+
+  // TODO ...likewise if it ends with an indirect branch followed by an unconditional
+  // branch.
+  // if (isIndirectBranchOpcode(SecondLastOpc) && isUncondBranchOpcode(LastOpc)) {
+  //   I = LastInst;
+  //   if (AllowModify)
+  //     I->eraseFromParent();
+  //   return true;
+  // }
+
+  // Otherwise, can't handle this.
+  return true;
+}
+
+unsigned VEInstrInfo::insertBranch(MachineBasicBlock &MBB,
+                                      MachineBasicBlock *TBB,
+                                      MachineBasicBlock *FBB,
+                                      ArrayRef<MachineOperand> Cond,
+                                      const DebugLoc &DL,
+                                      int *BytesAdded) const {
+  assert(TBB && "insertBranch must not be told to insert a fallthrough");
+  assert((Cond.size() == 3 || Cond.size() == 0) &&
+         "VE branch conditions should have three component!");
+  assert(!BytesAdded && "code size not handled");
+  if (Cond.empty()) {
+    // Uncondition branch
+    assert(!FBB && "Unconditional branch with multiple successors!");
+    BuildMI(&MBB, DL, get(VE::BCRLa))
+        .addMBB(TBB);
+    return 1;
+  }
+
+  // Conditional branch
+  //   (BCRir CC sy sz addr)
+  assert(Cond[0].isImm() && Cond[2].isReg() && "not implemented");
+
+  unsigned opc[2];
+  const TargetRegisterInfo *TRI = &getRegisterInfo();
+  MachineFunction *MF = MBB.getParent();
+  const MachineRegisterInfo &MRI = MF->getRegInfo();
+  unsigned Reg = Cond[2].getReg();
+  if (IsIntegerCC(Cond[0].getImm())) {
+    if (TRI->getRegSizeInBits(Reg, MRI) == 32) {
+      opc[0] = VE::BCRWir;
+      opc[1] = VE::BCRWrr;
+    } else {
+      opc[0] = VE::BCRLir;
+      opc[1] = VE::BCRLrr;
+    }
+  } else {
+    if (TRI->getRegSizeInBits(Reg, MRI) == 32) {
+      opc[0] = VE::BCRSir;
+      opc[1] = VE::BCRSrr;
+    } else {
+      opc[0] = VE::BCRDir;
+      opc[1] = VE::BCRDrr;
+    }
+  }
+  if (Cond[1].isImm()) {
+      BuildMI(&MBB, DL, get(opc[0]))
+          .add(Cond[0]) // condition code
+          .add(Cond[1]) // lhs
+          .add(Cond[2]) // rhs
+          .addMBB(TBB);
+  } else {
+      BuildMI(&MBB, DL, get(opc[1]))
+          .add(Cond[0])
+          .add(Cond[1])
+          .add(Cond[2])
+          .addMBB(TBB);
+  }
+
+  if (!FBB)
+    return 1;
+
+  BuildMI(&MBB, DL, get(VE::BCRLa))
+      .addMBB(FBB);
+  return 2;
+}
+
+unsigned VEInstrInfo::removeBranch(MachineBasicBlock &MBB,
+                                   int *BytesRemoved) const {
+  assert(!BytesRemoved && "code size not handled");
+
+  MachineBasicBlock::iterator I = MBB.end();
+  unsigned Count = 0;
+  while (I != MBB.begin()) {
+    --I;
+
+    if (I->isDebugValue())
+      continue;
+
+    if (!isUncondBranchOpcode(I->getOpcode()) &&
+        !isCondBranchOpcode(I->getOpcode()))
+      break; // Not a branch
+
+    I->eraseFromParent();
+    I = MBB.end();
+    ++Count;
+  }
+  return Count;
+}
+
+bool VEInstrInfo::reverseBranchCondition(
+    SmallVectorImpl<MachineOperand> &Cond) const {
+  VECC::CondCodes CC = static_cast<VECC::CondCodes>(Cond[0].getImm());
+  Cond[0].setImm(GetOppositeBranchCondition(CC));
+  return false;
+}
+
 static bool IsAliasOfSX(Register Reg) {
   return VE::I8RegClass.contains(Reg) || VE::I16RegClass.contains(Reg) ||
          VE::I32RegClass.contains(Reg) || VE::I64RegClass.contains(Reg) ||

diff  --git a/llvm/lib/Target/VE/VEInstrInfo.h b/llvm/lib/Target/VE/VEInstrInfo.h
index 60fc8153c158..822ef5900824 100644
--- a/llvm/lib/Target/VE/VEInstrInfo.h
+++ b/llvm/lib/Target/VE/VEInstrInfo.h
@@ -37,6 +37,25 @@ class VEInstrInfo : public VEGenInstrInfo {
   ///
   const VERegisterInfo &getRegisterInfo() const { return RI; }
 
+
+  /// Branch Analysis & Modification {
+  bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB,
+                     MachineBasicBlock *&FBB,
+                     SmallVectorImpl<MachineOperand> &Cond,
+                     bool AllowModify = false) const override;
+
+  unsigned removeBranch(MachineBasicBlock &MBB,
+                        int *BytesRemoved = nullptr) const override;
+
+  unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
+                        MachineBasicBlock *FBB, ArrayRef<MachineOperand> Cond,
+                        const DebugLoc &DL,
+                        int *BytesAdded = nullptr) const override;
+
+  bool
+  reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override;
+  /// } Branch Analysis & Modification
+
   void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
                    const DebugLoc &DL, MCRegister DestReg, MCRegister SrcReg,
                    bool KillSrc) const override;

diff  --git a/llvm/lib/Target/VE/VEInstrInfo.td b/llvm/lib/Target/VE/VEInstrInfo.td
index ab995c8cb846..1cee47d87d73 100644
--- a/llvm/lib/Target/VE/VEInstrInfo.td
+++ b/llvm/lib/Target/VE/VEInstrInfo.td
@@ -131,9 +131,15 @@ def fcond2cc : SDNodeXForm<cond, [{
 }]>;
 
 // Addressing modes.
+def ADDRrr : ComplexPattern<iPTR, 2, "SelectADDRrr", [], []>;
 def ADDRri : ComplexPattern<iPTR, 2, "SelectADDRri", [frameindex], []>;
 
 // ASX format of memory address
+def MEMrr : Operand<iPTR> {
+  let PrintMethod = "printMemASXOperand";
+  let MIOperandInfo = (ops ptr_rc, ptr_rc);
+}
+
 def MEMri : Operand<iPTR> {
   let PrintMethod = "printMemASXOperand";
   let MIOperandInfo = (ops ptr_rc, i64imm);
@@ -539,6 +545,55 @@ multiclass BCRm<string opcStr, string opcStrAt, bits<8> opc,
     let cz = 1;
     let hasSideEffects = 0;
   }
+  def ir : CF<
+    opc, (outs),
+    (ins CCOp:$cf, immOp:$sy, RC:$sz, brtarget32:$imm32),
+    !strconcat(opcStr, " $sy, $sz, $imm32")> {
+    let cy = 0;
+    let cz = 1;
+    let hasSideEffects = 0;
+  }
+  def rm0 : CF<
+    opc, (outs), (ins CCOp:$cf, RC:$sy, immOp2:$sz, brtarget32:$imm32),
+    !strconcat(opcStr, " $sy, (${sz})0, $imm32"), []> {
+    let cy = 1;
+    let cz = 0;
+    let sz{6} = 1;
+    let hasSideEffects = 0;
+  }
+  def rm1 : CF<
+    opc, (outs), (ins CCOp:$cf, RC:$sy, immOp2:$sz, brtarget32:$imm32),
+    !strconcat(opcStr, " $sy, (${sz})1, $imm32"), []> {
+    let cy = 1;
+    let cz = 0;
+    let hasSideEffects = 0;
+  }
+  def im0 : CF<
+    opc, (outs), (ins CCOp:$cf, immOp:$sy, immOp2:$sz, brtarget32:$imm32),
+    !strconcat(opcStr, " $sy, (${sz})0, $imm32"), []> {
+    let cy = 0;
+    let cz = 0;
+    let sz{6} = 1;
+    let hasSideEffects = 0;
+  }
+  def im1 : CF<
+    opc, (outs), (ins CCOp:$cf, immOp:$sy, immOp2:$sz, brtarget32:$imm32),
+    !strconcat(opcStr, " $sy, (${sz})1, $imm32"), []> {
+    let cy = 0;
+    let cz = 0;
+    let hasSideEffects = 0;
+  }
+  def a : CF<
+    opc, (outs), (ins brtarget32:$imm32),
+    !strconcat(opcStrAt, " $imm32"), []> {
+    let cy = 0;
+    let sy = 0;
+    let cz = 0;
+    let sz = 0;
+    let cf = 15;  /* AT */
+    let isBarrier = 1;
+    let hasSideEffects = 0;
+  }
 }
 
 // Multiclass for floating point conversion instructions.
@@ -866,6 +921,39 @@ def ST1Bri : RM<
 def : Pat<(f64 (load ADDRri:$addr)), (LDSri ADDRri:$addr)>;
 def : Pat<(store f64:$sx, ADDRri:$addr), (STSri ADDRri:$addr, $sx)>;
 
+// Control-flow
+
+// Jump instruction
+let cx = 0, cx2 = 0, bpf = 0 /* NONE */, cy = 1, cz = 1,
+    isBranch = 1, isTerminator = 1, hasDelaySlot = 1, hasSideEffects = 0 in
+def BC : CF<
+    0x19, (outs), (ins CCOp:$cf, I64:$sy, brtarget32:$imm32),
+    "b.${cf}.l $sy, $imm32">;
+
+// Jump always instruction is treated as a special case of jump in order
+// to make finding unconditional jump easy.
+let cx = 0, cx2 = 0, bpf = 0 /* NONE */, cf = 15 /* AT */, cy = 0, sy = 0,
+    cz = 1,
+    isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 1,
+    hasDelaySlot = 1, isCodeGenOnly = 1, hasSideEffects = 0 in {
+def BArr : CF<
+    0x19, (outs), (ins MEMrr:$addr),
+    "b.l $addr",
+    [(brind ADDRrr:$addr)]>;
+def BAri : CF<
+    0x19, (outs), (ins MEMri:$addr),
+    "b.l $addr",
+    [(brind ADDRri:$addr)]>;
+}
+
+// Jump never instruction is also a special case of jump.
+let cx = 0, cx2 = 0, bpf = 0 /* NONE */, cf = 0 /* AF */, cy = 1, sy = 0,
+    cz = 1,
+    isBranch = 1, isTerminator = 1, hasDelaySlot = 1, hasSideEffects = 0 in
+def BN : CF<
+    0x19, (outs), (ins brtarget32:$imm32),
+    "b.af.l $imm32">;
+
 // Return instruction is also a special case of jump.
 let cx = 0, cx2 = 0, bpf = 0 /* NONE */, cf = 15 /* AT */, cy = 0, sy = 0,
     cz = 1, sz = 0x10 /* SX10 */, imm32 = 0, Uses = [SX10],
@@ -879,6 +967,12 @@ def RET : CF<
 // Branch instruction
 let cx = 0, cx2 = 0, bpf = 0 /* NONE */ in
 defm BCRL : BCRm<"br${cf}.l", "br.l", 0x18, I64, i64, simm7Op64, uimm6Op64>;
+let cx = 1, cx2 = 0, bpf = 0 /* NONE */ in
+defm BCRW : BCRm<"br${cf}.w", "br.w", 0x18, I32, i32, simm7Op32, uimm6Op32>;
+let cx = 0, cx2 = 1, bpf = 0 /* NONE */ in
+defm BCRD : BCRm<"br${cf}.d", "br.d", 0x18, I64, f64, simm7Op64, uimm6Op64>;
+let cx = 1, cx2 = 1, bpf = 0 /* NONE */ in
+defm BCRS : BCRm<"br${cf}.s", "br.s", 0x18, F32, f32, simm7Op32, uimm6Op32>;
 
 let cx = 0, cy = 0, cz = 1, hasSideEffects = 0 in {
 let sy = 3 in
@@ -1041,6 +1135,22 @@ def : Pat<(call tglobaladdr:$dst),
 def : Pat<(call i64:$dst),
           (CALLr i64:$dst)>;
 
+// Branches
+def : Pat<(br bb:$addr), (BCRLa bb:$addr)>;
+
+// brcc
+def : Pat<(brcc CCSIOp:$cond, i32:$l, i32:$r, bb:$addr),
+          (BCRWrr (icond2cc $cond), $l, $r, bb:$addr)>;
+def : Pat<(brcc CCUIOp:$cond, i32:$l, i32:$r, bb:$addr),
+          (BCRWir (icond2cc $cond), 0, (CMPUWrr $r, $l), bb:$addr)>;
+def : Pat<(brcc CCSIOp:$cond, i64:$l, i64:$r, bb:$addr),
+          (BCRLrr (icond2cc $cond), $l, $r, bb:$addr)>;
+def : Pat<(brcc CCUIOp:$cond, i64:$l, i64:$r, bb:$addr),
+          (BCRLir (icond2cc $cond), 0, (CMPrr $r, $l), bb:$addr)>;
+def : Pat<(brcc cond:$cond, f32:$l, f32:$r, bb:$addr),
+          (BCRSrr (fcond2cc $cond), $l, $r, bb:$addr)>;
+def : Pat<(brcc cond:$cond, f64:$l, f64:$r, bb:$addr),
+          (BCRDrr (fcond2cc $cond), $l, $r, bb:$addr)>;
 
 //===----------------------------------------------------------------------===//
 // Pseudo Instructions

diff  --git a/llvm/test/CodeGen/VE/branch1.ll b/llvm/test/CodeGen/VE/branch1.ll
new file mode 100644
index 000000000000..a6fab7ae0fc6
--- /dev/null
+++ b/llvm/test/CodeGen/VE/branch1.ll
@@ -0,0 +1,290 @@
+; RUN: llc < %s -mtriple=ve-unknown-unknown | FileCheck %s
+
+define signext i8 @func1(i8 signext %a, i8 signext %b) {
+; CHECK-LABEL: func1:
+; CHECK:       .LBB{{[0-9]+}}_5:
+; CHECK-NEXT:    brle.w %s0, %s1, .LBB0_1
+; CHECK-NEXT:  # %bb.2:
+; CHECK-NEXT:    lea %s0, ret at lo
+; CHECK-NEXT:    and %s0, %s0, (32)0
+; CHECK-NEXT:    lea.sl %s12, ret at hi(%s0)
+; CHECK-NEXT:    or %s0, 2, (0)1
+; CHECK-NEXT:    bsic %lr, (,%s12)
+; CHECK-NEXT:    br.l .LBB0_3
+; CHECK:       .LBB{{[0-9]+}}_1:
+; CHECK-NEXT:    or %s0, 0, (0)1
+; CHECK:       .LBB{{[0-9]+}}_3:
+; CHECK-NEXT:    sla.w.sx %s0, %s0, 24
+; CHECK-NEXT:    sra.w.sx %s0, %s0, 24
+; CHECK-NEXT:    or %s11, 0, %s9
+entry:
+  %cmp = icmp sgt i8 %a, %b
+  br i1 %cmp, label %on.true, label %join
+
+on.true:
+  %ret.val = tail call i32 @ret(i32 2)
+  %r8 = trunc i32 %ret.val to i8
+  br label %join
+
+join:
+  %r = phi i8 [ %r8, %on.true ], [ 0, %entry ]
+  ret i8 %r
+}
+
+declare i32 @ret(i32)
+
+define i32 @func2(i16 signext %a, i16 signext %b) {
+; CHECK-LABEL: func2:
+; CHECK:       .LBB{{[0-9]+}}_5:
+; CHECK-NEXT:    brle.w %s0, %s1, .LBB1_1
+; CHECK-NEXT:  # %bb.2:
+; CHECK-NEXT:    lea %s0, ret at lo
+; CHECK-NEXT:    and %s0, %s0, (32)0
+; CHECK-NEXT:    lea.sl %s12, ret at hi(%s0)
+; CHECK-NEXT:    or %s0, 2, (0)1
+; CHECK-NEXT:    bsic %lr, (,%s12)
+; CHECK-NEXT:    br.l .LBB1_3
+; CHECK:       .LBB{{[0-9]+}}_1:
+; CHECK-NEXT:    or %s0, 0, (0)1
+; CHECK:       .LBB{{[0-9]+}}_3:
+; CHECK-NEXT:    or %s11, 0, %s9
+entry:
+  %cmp = icmp sgt i16 %a, %b
+  br i1 %cmp, label %on.true, label %join
+
+on.true:
+  %ret.val = tail call i32 @ret(i32 2)
+  br label %join
+
+join:
+  %r = phi i32 [ %ret.val, %on.true ], [ 0, %entry ]
+  ret i32 %r
+}
+
+define i32 @func3(i32 %a, i32 %b) {
+; CHECK-LABEL: func3:
+; CHECK:       .LBB{{[0-9]+}}_5:
+; CHECK-NEXT:    brle.w %s0, %s1, .LBB2_1
+; CHECK-NEXT:  # %bb.2:
+; CHECK-NEXT:    lea %s0, ret at lo
+; CHECK-NEXT:    and %s0, %s0, (32)0
+; CHECK-NEXT:    lea.sl %s12, ret at hi(%s0)
+; CHECK-NEXT:    or %s0, 2, (0)1
+; CHECK-NEXT:    bsic %lr, (,%s12)
+; CHECK-NEXT:    br.l .LBB2_3
+; CHECK:       .LBB{{[0-9]+}}_1:
+; CHECK-NEXT:    or %s0, 0, (0)1
+; CHECK:       .LBB{{[0-9]+}}_3:
+; CHECK-NEXT:    or %s11, 0, %s9
+entry:
+  %cmp = icmp sgt i32 %a, %b
+  br i1 %cmp, label %on.true, label %join
+
+on.true:
+  %ret.val = tail call i32 @ret(i32 2)
+  br label %join
+
+join:
+  %r = phi i32 [ %ret.val, %on.true ], [ 0, %entry ]
+  ret i32 %r
+}
+
+define i32 @func4(i64 %a, i64 %b) {
+; CHECK-LABEL: func4:
+; CHECK:       .LBB{{[0-9]+}}_5:
+; CHECK-NEXT:    brle.l %s0, %s1, .LBB3_1
+; CHECK-NEXT:  # %bb.2:
+; CHECK-NEXT:    lea %s0, ret at lo
+; CHECK-NEXT:    and %s0, %s0, (32)0
+; CHECK-NEXT:    lea.sl %s12, ret at hi(%s0)
+; CHECK-NEXT:    or %s0, 2, (0)1
+; CHECK-NEXT:    bsic %lr, (,%s12)
+; CHECK-NEXT:    br.l .LBB3_3
+; CHECK:       .LBB{{[0-9]+}}_1:
+; CHECK-NEXT:    or %s0, 0, (0)1
+; CHECK:       .LBB{{[0-9]+}}_3:
+; CHECK-NEXT:    or %s11, 0, %s9
+entry:
+  %cmp = icmp sgt i64 %a, %b
+  br i1 %cmp, label %on.true, label %join
+
+on.true:
+  %ret.val = tail call i32 @ret(i32 2)
+  br label %join
+
+join:
+  %r = phi i32 [ %ret.val, %on.true ], [ 0, %entry ]
+  ret i32 %r
+}
+
+define i32 @func5(i8 zeroext %a, i8 zeroext %b) {
+; CHECK-LABEL: func5:
+; CHECK:       .LBB{{[0-9]+}}_5:
+; CHECK-NEXT:    cmpu.w %s0, %s1, %s0
+; CHECK-NEXT:    brle.w 0, %s0, .LBB4_1
+; CHECK-NEXT:  # %bb.2:
+; CHECK-NEXT:    lea %s0, ret at lo
+; CHECK-NEXT:    and %s0, %s0, (32)0
+; CHECK-NEXT:    lea.sl %s12, ret at hi(%s0)
+; CHECK-NEXT:    or %s0, 2, (0)1
+; CHECK-NEXT:    bsic %lr, (,%s12)
+; CHECK-NEXT:    br.l .LBB4_3
+; CHECK:       .LBB{{[0-9]+}}_1:
+; CHECK-NEXT:    or %s0, 0, (0)1
+; CHECK:       .LBB{{[0-9]+}}_3:
+; CHECK-NEXT:    or %s11, 0, %s9
+entry:
+  %cmp = icmp ugt i8 %a, %b
+  br i1 %cmp, label %on.true, label %join
+
+on.true:
+  %ret.val = tail call i32 @ret(i32 2)
+  br label %join
+
+join:
+  %r = phi i32 [ %ret.val, %on.true ], [ 0, %entry ]
+  ret i32 %r
+}
+
+define i32 @func6(i16 zeroext %a, i16 zeroext %b) {
+; CHECK-LABEL: func6:
+; CHECK:       .LBB{{[0-9]+}}_5:
+; CHECK-NEXT:    cmpu.w %s0, %s1, %s0
+; CHECK-NEXT:    brle.w 0, %s0, .LBB5_1
+; CHECK-NEXT:  # %bb.2:
+; CHECK-NEXT:    lea %s0, ret at lo
+; CHECK-NEXT:    and %s0, %s0, (32)0
+; CHECK-NEXT:    lea.sl %s12, ret at hi(%s0)
+; CHECK-NEXT:    or %s0, 2, (0)1
+; CHECK-NEXT:    bsic %lr, (,%s12)
+; CHECK-NEXT:    br.l .LBB5_3
+; CHECK:       .LBB{{[0-9]+}}_1:
+; CHECK-NEXT:    or %s0, 0, (0)1
+; CHECK:       .LBB{{[0-9]+}}_3:
+; CHECK-NEXT:    or %s11, 0, %s9
+entry:
+  %cmp = icmp ugt i16 %a, %b
+  br i1 %cmp, label %on.true, label %join
+
+on.true:
+  %ret.val = tail call i32 @ret(i32 2)
+  br label %join
+
+join:
+  %r = phi i32 [ %ret.val, %on.true ], [ 0, %entry ]
+  ret i32 %r
+}
+
+define i32 @func7(i32 %a, i32 %b) {
+; CHECK-LABEL: func7:
+; CHECK:       .LBB{{[0-9]+}}_5:
+; CHECK-NEXT:    cmpu.w %s0, %s1, %s0
+; CHECK-NEXT:    brle.w 0, %s0, .LBB6_1
+; CHECK-NEXT:  # %bb.2:
+; CHECK-NEXT:    lea %s0, ret at lo
+; CHECK-NEXT:    and %s0, %s0, (32)0
+; CHECK-NEXT:    lea.sl %s12, ret at hi(%s0)
+; CHECK-NEXT:    or %s0, 2, (0)1
+; CHECK-NEXT:    bsic %lr, (,%s12)
+; CHECK-NEXT:    br.l .LBB6_3
+; CHECK:       .LBB{{[0-9]+}}_1:
+; CHECK-NEXT:    or %s0, 0, (0)1
+; CHECK:       .LBB{{[0-9]+}}_3:
+; CHECK-NEXT:    or %s11, 0, %s9
+entry:
+  %cmp = icmp ugt i32 %a, %b
+  br i1 %cmp, label %on.true, label %join
+
+on.true:
+  %ret.val = tail call i32 @ret(i32 2)
+  br label %join
+
+join:
+  %r = phi i32 [ %ret.val, %on.true ], [ 0, %entry ]
+  ret i32 %r
+}
+
+define i32 @func8(float %a, float %b) {
+; CHECK-LABEL: func8:
+; CHECK:       .LBB{{[0-9]+}}_5:
+; CHECK-NEXT:    brlenan.s %s0, %s1, .LBB7_1
+; CHECK-NEXT:  # %bb.2:
+; CHECK-NEXT:    lea %s0, ret at lo
+; CHECK-NEXT:    and %s0, %s0, (32)0
+; CHECK-NEXT:    lea.sl %s12, ret at hi(%s0)
+; CHECK-NEXT:    or %s0, 2, (0)1
+; CHECK-NEXT:    bsic %lr, (,%s12)
+; CHECK-NEXT:    br.l .LBB7_3
+; CHECK:       .LBB{{[0-9]+}}_1:
+; CHECK-NEXT:    or %s0, 0, (0)1
+; CHECK:       .LBB{{[0-9]+}}_3:
+; CHECK-NEXT:    or %s11, 0, %s9
+entry:
+  %cmp = fcmp ogt float %a, %b
+  br i1 %cmp, label %on.true, label %join
+
+on.true:
+  %ret.val = tail call i32 @ret(i32 2)
+  br label %join
+
+join:
+  %r = phi i32 [ %ret.val, %on.true ], [ 0, %entry ]
+  ret i32 %r
+}
+
+define i32 @func9(double %a, double %b) {
+; CHECK-LABEL: func9:
+; CHECK:       .LBB{{[0-9]+}}_5:
+; CHECK-NEXT:    brlenan.d %s0, %s1, .LBB8_1
+; CHECK-NEXT:  # %bb.2:
+; CHECK-NEXT:    lea %s0, ret at lo
+; CHECK-NEXT:    and %s0, %s0, (32)0
+; CHECK-NEXT:    lea.sl %s12, ret at hi(%s0)
+; CHECK-NEXT:    or %s0, 2, (0)1
+; CHECK-NEXT:    bsic %lr, (,%s12)
+; CHECK-NEXT:    br.l .LBB8_3
+; CHECK:       .LBB{{[0-9]+}}_1:
+; CHECK-NEXT:    or %s0, 0, (0)1
+; CHECK:       .LBB{{[0-9]+}}_3:
+; CHECK-NEXT:    or %s11, 0, %s9
+entry:
+  %cmp = fcmp ogt double %a, %b
+  br i1 %cmp, label %on.true, label %join
+
+on.true:
+  %ret.val = tail call i32 @ret(i32 2)
+  br label %join
+
+join:
+  %r = phi i32 [ %ret.val, %on.true ], [ 0, %entry ]
+  ret i32 %r
+}
+
+define i32 @func10(double %a, double %b) {
+; CHECK-LABEL: func10:
+; CHECK:       .LBB{{[0-9]+}}_5:
+; CHECK-NEXT:    lea.sl %s1, 1075052544
+; CHECK-NEXT:    brlenan.d %s0, %s1, .LBB9_1
+; CHECK-NEXT:  # %bb.2:
+; CHECK-NEXT:    lea %s0, ret at lo
+; CHECK-NEXT:    and %s0, %s0, (32)0
+; CHECK-NEXT:    lea.sl %s12, ret at hi(%s0)
+; CHECK-NEXT:    or %s0, 2, (0)1
+; CHECK-NEXT:    bsic %lr, (,%s12)
+; CHECK-NEXT:    br.l .LBB9_3
+; CHECK:       .LBB{{[0-9]+}}_1:
+; CHECK-NEXT:    or %s0, 0, (0)1
+; CHECK:       .LBB{{[0-9]+}}_3:
+; CHECK-NEXT:    or %s11, 0, %s9
+entry:
+  %cmp = fcmp ogt double %a, 5.000000e+00
+  br i1 %cmp, label %on.true, label %join
+
+on.true:
+  %ret.val = tail call i32 @ret(i32 2)
+  br label %join
+
+join:
+  %r = phi i32 [ %ret.val, %on.true ], [ 0, %entry ]
+  ret i32 %r
+}


        


More information about the llvm-commits mailing list