[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
This commit is contained in:
Kazushi (Jam) Marukawa 2020-01-29 17:40:46 +01:00 committed by Simon Moll
parent b63629a58d
commit fef80a2946
7 changed files with 694 additions and 1 deletions

View File

@ -44,6 +44,7 @@ public:
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 @@ public:
};
} // 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);

View File

@ -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);
}

View File

@ -71,6 +71,7 @@ public:
/// 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

View File

@ -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) ||

View File

@ -37,6 +37,25 @@ public:
///
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;

View File

@ -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

View File

@ -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
}