[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