diff --git a/llvm/lib/Target/VE/VEISelDAGToDAG.cpp b/llvm/lib/Target/VE/VEISelDAGToDAG.cpp --- a/llvm/lib/Target/VE/VEISelDAGToDAG.cpp +++ b/llvm/lib/Target/VE/VEISelDAGToDAG.cpp @@ -44,6 +44,7 @@ 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 @@ }; } // 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(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.h b/llvm/lib/Target/VE/VEISelLowering.h --- a/llvm/lib/Target/VE/VEISelLowering.h +++ b/llvm/lib/Target/VE/VEISelLowering.h @@ -71,6 +71,7 @@ /// 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/VEISelLowering.cpp b/llvm/lib/Target/VE/VEISelLowering.cpp --- a/llvm/lib/Target/VE/VEISelLowering.cpp +++ b/llvm/lib/Target/VE/VEISelLowering.cpp @@ -497,8 +497,9 @@ 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 @@ return DAG.getTargetGlobalAddress(GA->getGlobal(), SDLoc(GA), GA->getValueType(0), GA->getOffset(), TF); + if (const BlockAddressSDNode *BA = dyn_cast(Op)) + return DAG.getTargetBlockAddress(BA->getBlockAddress(), Op.getValueType(), + 0, TF); + llvm_unreachable("Unhandled address SDNode"); } @@ -594,10 +599,17 @@ 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/VEInstrInfo.h b/llvm/lib/Target/VE/VEInstrInfo.h --- a/llvm/lib/Target/VE/VEInstrInfo.h +++ b/llvm/lib/Target/VE/VEInstrInfo.h @@ -37,6 +37,25 @@ /// const VERegisterInfo &getRegisterInfo() const { return RI; } + + /// Branch Analysis & Modification { + bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl &Cond, + bool AllowModify = false) const override; + + unsigned removeBranch(MachineBasicBlock &MBB, + int *BytesRemoved = nullptr) const override; + + unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, ArrayRef Cond, + const DebugLoc &DL, + int *BytesAdded = nullptr) const override; + + bool + reverseBranchCondition(SmallVectorImpl &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.cpp b/llvm/lib/Target/VE/VEInstrInfo.cpp --- a/llvm/lib/Target/VE/VEInstrInfo.cpp +++ b/llvm/lib/Target/VE/VEInstrInfo.cpp @@ -38,6 +38,243 @@ : 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 &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 &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 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 &Cond) const { + VECC::CondCodes CC = static_cast(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.td b/llvm/lib/Target/VE/VEInstrInfo.td --- a/llvm/lib/Target/VE/VEInstrInfo.td +++ b/llvm/lib/Target/VE/VEInstrInfo.td @@ -131,9 +131,15 @@ }]>; // Addressing modes. +def ADDRrr : ComplexPattern; def ADDRri : ComplexPattern; // ASX format of memory address +def MEMrr : Operand { + let PrintMethod = "printMemASXOperand"; + let MIOperandInfo = (ops ptr_rc, ptr_rc); +} + def MEMri : Operand { let PrintMethod = "printMemASXOperand"; let MIOperandInfo = (ops ptr_rc, i64imm); @@ -539,6 +545,55 @@ 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 : 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 @@ // 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 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 --- /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@lo +; CHECK-NEXT: and %s0, %s0, (32)0 +; CHECK-NEXT: lea.sl %s12, ret@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@lo +; CHECK-NEXT: and %s0, %s0, (32)0 +; CHECK-NEXT: lea.sl %s12, ret@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@lo +; CHECK-NEXT: and %s0, %s0, (32)0 +; CHECK-NEXT: lea.sl %s12, ret@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@lo +; CHECK-NEXT: and %s0, %s0, (32)0 +; CHECK-NEXT: lea.sl %s12, ret@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@lo +; CHECK-NEXT: and %s0, %s0, (32)0 +; CHECK-NEXT: lea.sl %s12, ret@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@lo +; CHECK-NEXT: and %s0, %s0, (32)0 +; CHECK-NEXT: lea.sl %s12, ret@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@lo +; CHECK-NEXT: and %s0, %s0, (32)0 +; CHECK-NEXT: lea.sl %s12, ret@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@lo +; CHECK-NEXT: and %s0, %s0, (32)0 +; CHECK-NEXT: lea.sl %s12, ret@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@lo +; CHECK-NEXT: and %s0, %s0, (32)0 +; CHECK-NEXT: lea.sl %s12, ret@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@lo +; CHECK-NEXT: and %s0, %s0, (32)0 +; CHECK-NEXT: lea.sl %s12, ret@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 +}