diff --git a/llvm/lib/Target/ARM/ARM.h b/llvm/lib/Target/ARM/ARM.h index 3847f4e966afe..dd5cfb7a8a062 100644 --- a/llvm/lib/Target/ARM/ARM.h +++ b/llvm/lib/Target/ARM/ARM.h @@ -35,6 +35,7 @@ Pass *createMVETailPredicationPass(); FunctionPass *createARMLowOverheadLoopsPass(); FunctionPass *createARMBlockPlacementPass(); Pass *createARMParallelDSPPass(); +FunctionPass *createARMConditionOptimizerPass(); FunctionPass *createARMISelDag(ARMBaseTargetMachine &TM, CodeGenOptLevel OptLevel); FunctionPass *createA15SDOptimizerPass(); @@ -64,6 +65,7 @@ void LowerARMMachineInstrToMCInst(const MachineInstr *MI, MCInst &OutMI, void initializeARMAsmPrinterPass(PassRegistry &); void initializeARMBlockPlacementPass(PassRegistry &); void initializeARMBranchTargetsPass(PassRegistry &); +void initializeARMConditionOptimizerPass(PassRegistry &); void initializeARMConstantIslandsPass(PassRegistry &); void initializeARMDAGToDAGISelLegacyPass(PassRegistry &); void initializeARMExpandPseudoPass(PassRegistry &); diff --git a/llvm/lib/Target/ARM/ARMConditionOptimizer.cpp b/llvm/lib/Target/ARM/ARMConditionOptimizer.cpp new file mode 100644 index 0000000000000..70d5b06da61a5 --- /dev/null +++ b/llvm/lib/Target/ARM/ARMConditionOptimizer.cpp @@ -0,0 +1,514 @@ +//=- ARMConditionOptimizer.cpp - Remove useless comparisons for ARM -=// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This pass tries to make consecutive compares of values use same operands to +// allow CSE pass to remove duplicated instructions. For this it analyzes +// branches and adjusts comparisons with immediate values by converting: +// * GE -> GT +// * GT -> GE +// * LT -> LE +// * LE -> LT +// and adjusting immediate values appropriately. It basically corrects two +// immediate values towards each other to make them equal. +// +// Consider the following example in C: +// +// if ((a < 5 && ...) || (a > 5 && ...)) { +// ~~~~~ ~~~~~ +// ^ ^ +// x y +// +// Here both "x" and "y" expressions compare "a" with "5". When "x" evaluates +// to "false", "y" can just check flags set by the first comparison. As a +// result of the canonicalization employed by +// SelectionDAGBuilder::visitSwitchCase, DAGCombine, and other target-specific +// code, assembly ends up in the form that is not CSE friendly: +// +// ... +// cmp r8, #4 +// bgt .LBB0_3 +// ... +// .LBB0_3: +// cmp r8, #6 +// blt .LBB0_6 +// ... +// +// Same assembly after the pass: +// +// ... +// cmp r8, #5 +// bge .LBB0_3 +// ... +// .LBB0_3: +// cmp r8, #5 // <-- CSE pass removes this instruction +// ble .LBB0_6 +// ... +// +// Currently only CMP and CMN followed by branches are supported. +// +// TODO: maybe deal with predicated instructions +// +//===----------------------------------------------------------------------===// + +#include "ARM.h" +#include "ARMSubtarget.h" +#include "MCTargetDesc/ARMAddressingModes.h" +#include "Utils/ARMBaseInfo.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DepthFirstIterator.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineDominators.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineOperand.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/TargetInstrInfo.h" +#include "llvm/CodeGen/TargetSubtargetInfo.h" +#include "llvm/InitializePasses.h" +#include "llvm/Pass.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include +#include +#include + +using namespace llvm; + +#define DEBUG_TYPE "arm-condopt" + +STATISTIC(NumConditionsAdjusted, "Number of conditions adjusted"); + +namespace { + +class ARMConditionOptimizer : public MachineFunctionPass { + const TargetInstrInfo *TII; + MachineDominatorTree *DomTree; + const MachineRegisterInfo *MRI; + +public: + // Stores immediate, compare instruction opcode and branch condition (in this + // order) of adjusted comparison. + using CmpInfo = std::tuple; + + static char ID; + + ARMConditionOptimizer() : MachineFunctionPass(ID) {} + + void getAnalysisUsage(AnalysisUsage &AU) const override; + MachineInstr *findSuitableCompare(MachineBasicBlock *MBB); + CmpInfo adjustCmp(MachineInstr *CmpMI, ARMCC::CondCodes Cmp); + void modifyCmp(MachineInstr *CmpMI, const CmpInfo &Info); + bool adjustTo(MachineInstr *CmpMI, ARMCC::CondCodes Cmp, MachineInstr *To, + int ToImm); + bool runOnMachineFunction(MachineFunction &MF) override; + + StringRef getPassName() const override { return "ARM Condition Optimizer"; } +}; + +} // end anonymous namespace + +char ARMConditionOptimizer::ID = 0; + +INITIALIZE_PASS_BEGIN(ARMConditionOptimizer, "ARM-condopt", "ARM CondOpt Pass", + false, false) +INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass) +INITIALIZE_PASS_END(ARMConditionOptimizer, "ARM-condopt", "ARM CondOpt Pass", + false, false) + +FunctionPass *llvm::createARMConditionOptimizerPass() { + return new ARMConditionOptimizer(); +} + +void ARMConditionOptimizer::getAnalysisUsage(AnalysisUsage &AU) const { + AU.addRequired(); + AU.addPreserved(); + MachineFunctionPass::getAnalysisUsage(AU); +} + +// Finds compare instruction that corresponds to supported types of branching. +// Returns the instruction or nullptr on failures or detecting unsupported +// instructions. +MachineInstr * +ARMConditionOptimizer::findSuitableCompare(MachineBasicBlock *MBB) { + MachineBasicBlock::iterator Term = MBB->getFirstTerminator(); + if (Term == MBB->end()) + return nullptr; + + // Accept ARM, Thumb, and Thumb2 conditional branches + if (Term->getOpcode() != ARM::Bcc && Term->getOpcode() != ARM::tBcc && + Term->getOpcode() != ARM::t2Bcc) + return nullptr; + + // Since we may modify cmp of this MBB, make sure NZCV does not live out. + for (auto *SuccBB : MBB->successors()) + if (SuccBB->isLiveIn(ARM::CPSR)) + return nullptr; + + // Now find the instruction controlling the terminator. + for (MachineBasicBlock::iterator B = MBB->begin(), It = Term; It != B;) { + It = prev_nodbg(It, B); + MachineInstr &I = *It; + assert(!I.isTerminator() && "Spurious terminator"); + // Check if there is any use of CPSR between CMP and Bcc. + if (I.readsRegister(ARM::CPSR, /*TRI=*/nullptr)) + return nullptr; + switch (I.getOpcode()) { + // Thumb-1, Thumb-2, and ARM CMP instructions - immediate variants only + case ARM::tCMPi8: + case ARM::t2CMPri: + case ARM::t2CMNri: + case ARM::CMPri: + case ARM::CMNri: + // Only handle unpredicated CMP/CMN instructions + // ARM and Thumb2 instructions can be predicated, Thumb-1 cannot. + if (I.getOpcode() != ARM::tCMPi8) { + int PIdx = I.findFirstPredOperandIdx(); + if (PIdx != -1 && I.getOperand(PIdx).getImm() != (int64_t)ARMCC::AL) { + LLVM_DEBUG(dbgs() + << "Skipping predicated instruction: " << I << '\n'); + return nullptr; + } + } + + // Check that the immediate operand is valid + if (!I.getOperand(1).isImm()) { + LLVM_DEBUG(dbgs() << "Immediate of cmp/cmn is symbolic, " << I << '\n'); + return nullptr; + } + return &I; + default: + if (I.modifiesRegister(ARM::CPSR, /*TRI=*/nullptr)) + return nullptr; + } + } + LLVM_DEBUG(dbgs() << "Flags not defined in " << printMBBReference(*MBB) + << '\n'); + return nullptr; +} + +// Changes opcode cmp <-> cmn considering register operand width. +static int getComplementOpc(int Opc) { + switch (Opc) { + // ARM CMN/CMP immediate instructions + case ARM::CMNri: + return ARM::CMPri; + case ARM::CMPri: + return ARM::CMNri; + // Thumb CMP immediate instructions - NOTE: Thumb1 doesn't have CMN! + case ARM::tCMPi8: + return ARM::INSTRUCTION_LIST_END; // No complement for Thumb1 + // Thumb2 CMN/CMP immediate instructions + case ARM::t2CMPri: + return ARM::t2CMNri; + case ARM::t2CMNri: + return ARM::t2CMPri; + default: + llvm_unreachable("Unexpected opcode"); + } +} + +// Changes form of comparison inclusive <-> exclusive. +static ARMCC::CondCodes getAdjustedCmp(ARMCC::CondCodes Cmp) { + switch (Cmp) { + case ARMCC::GT: + return ARMCC::GE; + case ARMCC::GE: + return ARMCC::GT; + case ARMCC::LT: + return ARMCC::LE; + case ARMCC::LE: + return ARMCC::LT; + case ARMCC::HI: + return ARMCC::HS; + case ARMCC::HS: + return ARMCC::HI; + case ARMCC::LO: + return ARMCC::LS; + case ARMCC::LS: + return ARMCC::LO; + default: + llvm_unreachable("Unexpected condition code"); + } +} + +// Transforms GT -> GE, GE -> GT, LT -> LE, LE -> LT by updating comparison +// operator and condition code. +ARMConditionOptimizer::CmpInfo +ARMConditionOptimizer::adjustCmp(MachineInstr *CmpMI, ARMCC::CondCodes Cmp) { + unsigned Opc = CmpMI->getOpcode(); + unsigned OldOpc = Opc; + + bool IsSigned = Cmp == ARMCC::GT || Cmp == ARMCC::GE || Cmp == ARMCC::LT || + Cmp == ARMCC::LE; + + // CMN (compare with negative immediate) is an alias to ADDS (as + // "operand - negative" == "operand + positive") + bool Negative = (Opc == ARM::CMNri || Opc == ARM::t2CMNri); + + int Correction = (Cmp == ARMCC::GT || Cmp == ARMCC::HI) ? 1 : -1; + // Negate Correction value for comparison with negative immediate (CMN). + if (Negative) { + Correction = -Correction; + } + + const int OldImm = (int)CmpMI->getOperand(1).getImm(); + const int NewImm = std::abs(OldImm + Correction); + + // Handle cmn 1 -> cmp 0, transitions by adjusting compare instruction opcode. + if (OldImm == 1 && Negative && Correction == -1) { + // If we are adjusting from -1 to 0, we need to change the opcode. + Opc = getComplementOpc(Opc); + } + + // Handle +0 -> -1 transitions by adjusting compare instruction opcode. + if (OldImm == 0 && Correction == -1) { + Opc = getComplementOpc(Opc); + } + + // If we change opcodes, this means we did an unsigned wrap, so return the old + // cmp for unsigned comparisons. + + // If we have an invalid value, return the old cmp + if (Opc == ARM::INSTRUCTION_LIST_END || (!IsSigned && Opc != OldOpc)) + return CmpInfo(OldImm, OldOpc, Cmp); + + return CmpInfo(NewImm, Opc, getAdjustedCmp(Cmp)); +} + +// Applies changes to comparison instruction suggested by adjustCmp(). +void ARMConditionOptimizer::modifyCmp(MachineInstr *CmpMI, + const CmpInfo &Info) { + int Imm; + unsigned Opc; + ARMCC::CondCodes Cmp; + std::tie(Imm, Opc, Cmp) = Info; + if (Imm == 0) { + if (Cmp == ARMCC::GE) + Cmp = ARMCC::PL; + if (Cmp == ARMCC::LT) + Cmp = ARMCC::MI; + } + + MachineBasicBlock *const MBB = CmpMI->getParent(); + + // Build the new instruction with the correct format for the target opcode. + MachineInstrBuilder MIB = BuildMI(*MBB, CmpMI, CmpMI->getDebugLoc(), + TII->get(Opc)) + .add(CmpMI->getOperand(0)) // Rn + .addImm(Imm); // Immediate + + // Add predicate operands for all CMP/CMN instructions. + // Even Thumb-1 CMP instructions have predicate operands. + MIB.add(predOps(ARMCC::AL)); + + CmpMI->eraseFromParent(); + + // The fact that this comparison was picked ensures that it's related to the + // first terminator instruction. + MachineInstr &BrMI = *MBB->getFirstTerminator(); + + // Change condition in branch instruction. + // Rebuild the branch instruction correctly for all subtargets. + unsigned BranchOpc = BrMI.getOpcode(); + MachineInstrBuilder BranchMIB = + BuildMI(*MBB, BrMI, BrMI.getDebugLoc(), TII->get(BranchOpc)) + .add(BrMI.getOperand(0)); // Target MBB + + // Add the new condition code. + BranchMIB.addImm(Cmp); + + // Add the predicate register operand for all branch types. + // All ARM/Thumb/Thumb2 conditional branches need this. + BranchMIB.add(BrMI.getOperand(2)); + + BrMI.eraseFromParent(); + + ++NumConditionsAdjusted; +} + +// Parse a condition code returned by analyzeBranch, and compute the CondCode +// corresponding to TBB. +// Returns true if parsing was successful, otherwise false is returned. +static bool parseCond(ArrayRef Cond, ARMCC::CondCodes &CC) { + // A normal br.cond simply has the condition code (size == 2 for ARM/Thumb) + if (Cond.size() == 2 && Cond[0].isImm()) { + CC = (ARMCC::CondCodes)(int)Cond[0].getImm(); + return true; + } + return false; +} + +// Adjusts one cmp instruction to another one if result of adjustment will allow +// CSE. Returns true if compare instruction was changed, otherwise false is +// returned. +bool ARMConditionOptimizer::adjustTo(MachineInstr *CmpMI, ARMCC::CondCodes Cmp, + MachineInstr *To, int ToImm) { + CmpInfo Info = adjustCmp(CmpMI, Cmp); + if (std::get<0>(Info) == ToImm && std::get<1>(Info) == To->getOpcode()) { + modifyCmp(CmpMI, Info); + return true; + } + return false; +} + +static bool isGreaterThan(ARMCC::CondCodes Cmp) { + return Cmp == ARMCC::GT || Cmp == ARMCC::HI; +} + +static bool isLessThan(ARMCC::CondCodes Cmp) { + return Cmp == ARMCC::LT || Cmp == ARMCC::LO; +} + +bool ARMConditionOptimizer::runOnMachineFunction(MachineFunction &MF) { + LLVM_DEBUG(dbgs() << "********** ARM Conditional Compares **********\n" + << "********** Function: " << MF.getName() << '\n'); + if (skipFunction(MF.getFunction())) + return false; + + TII = MF.getSubtarget().getInstrInfo(); + DomTree = &getAnalysis().getDomTree(); + MRI = &MF.getRegInfo(); + + bool Changed = false; + + // Visit blocks in dominator tree pre-order. The pre-order enables multiple + // cmp-conversions from the same head block. + // Note that updateDomTree() modifies the children of the DomTree node + // currently being visited. The df_iterator supports that; it doesn't look at + // child_begin() / child_end() until after a node has been visited. + for (MachineDomTreeNode *I : depth_first(DomTree)) { + MachineBasicBlock *HBB = I->getBlock(); + + SmallVector HeadCond; + MachineBasicBlock *TBB = nullptr, *FBB = nullptr; + if (TII->analyzeBranch(*HBB, TBB, FBB, HeadCond)) { + continue; + } + + // Equivalence check is to skip loops. + if (!TBB || TBB == HBB) { + continue; + } + + SmallVector TrueCond; + MachineBasicBlock *TBB_TBB = nullptr, *TBB_FBB = nullptr; + if (TII->analyzeBranch(*TBB, TBB_TBB, TBB_FBB, TrueCond)) { + continue; + } + + MachineInstr *HeadCmpMI = findSuitableCompare(HBB); + if (!HeadCmpMI) { + continue; + } + + ARMCC::CondCodes HeadCmp; + if (HeadCond.empty() || !parseCond(HeadCond, HeadCmp)) { + continue; + } + + ARMCC::CondCodes TrueCmp; + if (TrueCond.empty() || !parseCond(TrueCond, TrueCmp)) { + continue; + } + + const int HeadImm = (int)HeadCmpMI->getOperand(1).getImm(); + + // Convert PL/MI to GE/LT for comparisons with 0. + if (HeadImm == 0) { + if (HeadCmp == ARMCC::PL) + HeadCmp = ARMCC::GE; + if (HeadCmp == ARMCC::MI) + HeadCmp = ARMCC::LT; + } + + int HeadImmTrueValue = HeadImm; + + unsigned HeadOpc = HeadCmpMI->getOpcode(); + if (HeadOpc == ARM::CMNri || HeadOpc == ARM::t2CMNri) + HeadImmTrueValue = -HeadImmTrueValue; + + // Try to find a suitable compare in TBB, but don't require it yet + MachineInstr *TrueCmpMI = findSuitableCompare(TBB); + + // If we have a suitable compare in TBB, try the optimization + if (TrueCmpMI) { + const int TrueImm = (int)TrueCmpMI->getOperand(1).getImm(); + + // Special Case 0. + if (TrueImm == 0) { + if (TrueCmp == ARMCC::PL) + TrueCmp = ARMCC::GE; + if (TrueCmp == ARMCC::MI) + TrueCmp = ARMCC::LT; + } + + int TrueImmTrueValue = TrueImm; + + unsigned TrueOpc = TrueCmpMI->getOpcode(); + if (TrueOpc == ARM::CMNri || TrueOpc == ARM::t2CMNri) + TrueImmTrueValue = -TrueImmTrueValue; + + if (((isGreaterThan(HeadCmp) && isLessThan(TrueCmp)) || + (isLessThan(HeadCmp) && isGreaterThan(TrueCmp))) && + std::abs(TrueImmTrueValue - HeadImmTrueValue) == 2) { + // This branch transforms machine instructions that correspond to + // + // 1) (a > {TrueImm} && ...) || (a < {HeadImm} && ...) + // 2) (a < {TrueImm} && ...) || (a > {HeadImm} && ...) + // + // into + // + // 1) (a >= {NewImm} && ...) || (a <= {NewImm} && ...) + // 2) (a <= {NewImm} && ...) || (a >= {NewImm} && ...) + + CmpInfo HeadCmpInfo = adjustCmp(HeadCmpMI, HeadCmp); + CmpInfo TrueCmpInfo = adjustCmp(TrueCmpMI, TrueCmp); + if (std::get<0>(HeadCmpInfo) == std::get<0>(TrueCmpInfo) && + std::get<1>(HeadCmpInfo) == std::get<1>(TrueCmpInfo)) { + modifyCmp(HeadCmpMI, HeadCmpInfo); + modifyCmp(TrueCmpMI, TrueCmpInfo); + Changed = true; + } + } else if (((isGreaterThan(HeadCmp) && isGreaterThan(TrueCmp)) || + (isLessThan(HeadCmp) && isLessThan(TrueCmp))) && + std::abs(TrueImmTrueValue - HeadImmTrueValue) == 1) { + // This branch transforms machine instructions that correspond to + // + // 1) (a > {TrueImm} && ...) || (a > {HeadImm} && ...) + // 2) (a < {TrueImm} && ...) || (a < {HeadImm} && ...) + // + // into + // + // 1) (a <= {NewImm} && ...) || (a > {NewImm} && ...) + // 2) (a < {NewImm} && ...) || (a >= {NewImm} && ...) + + // GT -> GE transformation increases immediate value, so picking the + // smaller one; LT -> LE decreases immediate value so invert the choice. + bool adjustHeadCond = (HeadImmTrueValue < TrueImmTrueValue); + if (isLessThan(HeadCmp)) { + adjustHeadCond = !adjustHeadCond; + } + + if (adjustHeadCond) { + Changed |= adjustTo(HeadCmpMI, HeadCmp, TrueCmpMI, TrueImm); + } else { + Changed |= adjustTo(TrueCmpMI, TrueCmp, HeadCmpMI, HeadImm); + } + } + } + // Other transformation cases almost never occur due to generation of < or > + // comparisons instead of <= and >=. + } + + return Changed; +} diff --git a/llvm/lib/Target/ARM/ARMTargetMachine.cpp b/llvm/lib/Target/ARM/ARMTargetMachine.cpp index 86740a92b32c5..534fda012b20c 100644 --- a/llvm/lib/Target/ARM/ARMTargetMachine.cpp +++ b/llvm/lib/Target/ARM/ARMTargetMachine.cpp @@ -79,6 +79,11 @@ static cl::opt EnableGlobalMerge("arm-global-merge", cl::Hidden, cl::desc("Enable the global merge pass")); +static cl::opt + EnableCondOpt("arm-enable-condopt", + cl::desc("Enable the condition optimizer pass"), + cl::init(true), cl::Hidden); + namespace llvm { void initializeARMExecutionDomainFixPass(PassRegistry&); } @@ -98,6 +103,7 @@ extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void LLVMInitializeARMTarget() { initializeARMParallelDSPPass(Registry); initializeARMBranchTargetsPass(Registry); initializeARMConstantIslandsPass(Registry); + initializeARMConditionOptimizerPass(Registry); initializeARMExecutionDomainFixPass(Registry); initializeARMExpandPseudoPass(Registry); initializeThumb2SizeReducePass(Registry); @@ -308,6 +314,7 @@ class ARMPassConfig : public TargetPassConfig { void addIRPasses() override; void addCodeGenPrepare() override; bool addPreISel() override; + bool addILPOpts() override; bool addInstSelector() override; bool addIRTranslator() override; bool addLegalizeMachineIR() override; @@ -432,6 +439,12 @@ bool ARMPassConfig::addPreISel() { return false; } +bool ARMPassConfig::addILPOpts() { + if (EnableCondOpt) + addPass(createARMConditionOptimizerPass()); + return false; +} + bool ARMPassConfig::addInstSelector() { addPass(createARMISelDag(getARMTargetMachine(), getOptLevel())); return false; diff --git a/llvm/lib/Target/ARM/CMakeLists.txt b/llvm/lib/Target/ARM/CMakeLists.txt index fa778cad4af8e..7bcfc89ccfba6 100644 --- a/llvm/lib/Target/ARM/CMakeLists.txt +++ b/llvm/lib/Target/ARM/CMakeLists.txt @@ -29,6 +29,7 @@ add_llvm_target(ARMCodeGen ARMBranchTargets.cpp ARMCallingConv.cpp ARMCallLowering.cpp + ARMConditionOptimizer.cpp ARMConstantIslandPass.cpp ARMConstantPoolValue.cpp ARMExpandPseudoInsts.cpp diff --git a/llvm/test/CodeGen/ARM/O3-pipeline.ll b/llvm/test/CodeGen/ARM/O3-pipeline.ll index 9601a2e4e3d12..039cfb78b342b 100644 --- a/llvm/test/CodeGen/ARM/O3-pipeline.ll +++ b/llvm/test/CodeGen/ARM/O3-pipeline.ll @@ -92,6 +92,7 @@ ; CHECK-NEXT: Local Stack Slot Allocation ; CHECK-NEXT: Remove dead machine instructions ; CHECK-NEXT: MachineDominator Tree Construction +; CHECK-NEXT: ARM Condition Optimizer ; CHECK-NEXT: Machine Natural Loop Construction ; CHECK-NEXT: Machine Block Frequency Analysis ; CHECK-NEXT: Early Machine Loop Invariant Code Motion diff --git a/llvm/test/CodeGen/ARM/combine-comparisons-by-cse.ll b/llvm/test/CodeGen/ARM/combine-comparisons-by-cse.ll new file mode 100644 index 0000000000000..b97b0bd0a7eef --- /dev/null +++ b/llvm/test/CodeGen/ARM/combine-comparisons-by-cse.ll @@ -0,0 +1,3184 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=armv7a < %s | FileCheck %s --check-prefix=ARM +; RUN: llc -mtriple=armv6m < %s | FileCheck %s --check-prefix=THUMB +; RUN: llc -mtriple=armv7m < %s | FileCheck %s --check-prefix=THUMB2 +; RUN: llc -mtriple=thumbv8.1m.main < %s | FileCheck %s --check-prefix=THUMBV8 + +; marked as external to prevent possible optimizations +@a = external global i32 +@b = external global i32 +@c = external global i32 +@d = external global i32 + +; (a > 10 && b == c) || (a >= 10 && b == d) +define i32 @combine_gt_ge_10() #0 { +; ARM-LABEL: combine_gt_ge_10: +; ARM: @ %bb.0: @ %entry +; ARM-NEXT: movw r0, :lower16:a +; ARM-NEXT: movw r1, :lower16:b +; ARM-NEXT: movt r0, :upper16:a +; ARM-NEXT: movt r1, :upper16:b +; ARM-NEXT: ldr r0, [r0] +; ARM-NEXT: cmp r0, #10 +; ARM-NEXT: ble .LBB0_2 +; ARM-NEXT: @ %bb.1: @ %land.lhs.true +; ARM-NEXT: movw r0, :lower16:c +; ARM-NEXT: ldr r3, [r1] +; ARM-NEXT: movt r0, :upper16:c +; ARM-NEXT: ldr r2, [r0] +; ARM-NEXT: mov r0, #1 +; ARM-NEXT: cmp r3, r2 +; ARM-NEXT: bxeq lr +; ARM-NEXT: b .LBB0_3 +; ARM-NEXT: .LBB0_2: @ %lor.lhs.false +; ARM-NEXT: blt .LBB0_4 +; ARM-NEXT: .LBB0_3: @ %land.lhs.true3 +; ARM-NEXT: movw r0, :lower16:d +; ARM-NEXT: ldr r1, [r1] +; ARM-NEXT: movt r0, :upper16:d +; ARM-NEXT: ldr r2, [r0] +; ARM-NEXT: mov r0, #1 +; ARM-NEXT: cmp r1, r2 +; ARM-NEXT: movne r0, #0 +; ARM-NEXT: bx lr +; ARM-NEXT: .LBB0_4: @ %if.end +; ARM-NEXT: mov r0, #0 +; ARM-NEXT: bx lr +; +; THUMB-LABEL: combine_gt_ge_10: +; THUMB: @ %bb.0: @ %entry +; THUMB-NEXT: ldr r0, .LCPI0_0 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: cmp r0, #10 +; THUMB-NEXT: ble .LBB0_3 +; THUMB-NEXT: @ %bb.1: @ %land.lhs.true +; THUMB-NEXT: ldr r0, .LCPI0_1 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: ldr r1, .LCPI0_2 +; THUMB-NEXT: ldr r1, [r1] +; THUMB-NEXT: cmp r1, r0 +; THUMB-NEXT: bne .LBB0_4 +; THUMB-NEXT: @ %bb.2: +; THUMB-NEXT: movs r0, #1 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .LBB0_3: @ %lor.lhs.false +; THUMB-NEXT: blt .LBB0_6 +; THUMB-NEXT: .LBB0_4: @ %land.lhs.true3 +; THUMB-NEXT: ldr r0, .LCPI0_3 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: ldr r1, .LCPI0_2 +; THUMB-NEXT: ldr r1, [r1] +; THUMB-NEXT: cmp r1, r0 +; THUMB-NEXT: bne .LBB0_6 +; THUMB-NEXT: @ %bb.5: +; THUMB-NEXT: movs r0, #1 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .LBB0_6: @ %if.end +; THUMB-NEXT: movs r0, #0 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .p2align 2 +; THUMB-NEXT: @ %bb.7: +; THUMB-NEXT: .LCPI0_0: +; THUMB-NEXT: .long a +; THUMB-NEXT: .LCPI0_1: +; THUMB-NEXT: .long c +; THUMB-NEXT: .LCPI0_2: +; THUMB-NEXT: .long b +; THUMB-NEXT: .LCPI0_3: +; THUMB-NEXT: .long d +; +; THUMB2-LABEL: combine_gt_ge_10: +; THUMB2: @ %bb.0: @ %entry +; THUMB2-NEXT: movw r0, :lower16:a +; THUMB2-NEXT: movt r0, :upper16:a +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: cmp r0, #10 +; THUMB2-NEXT: movw r0, :lower16:b +; THUMB2-NEXT: movt r0, :upper16:b +; THUMB2-NEXT: ble .LBB0_2 +; THUMB2-NEXT: @ %bb.1: @ %land.lhs.true +; THUMB2-NEXT: movw r1, :lower16:c +; THUMB2-NEXT: ldr r2, [r0] +; THUMB2-NEXT: movt r1, :upper16:c +; THUMB2-NEXT: ldr r1, [r1] +; THUMB2-NEXT: cmp r2, r1 +; THUMB2-NEXT: itt eq +; THUMB2-NEXT: moveq r0, #1 +; THUMB2-NEXT: bxeq lr +; THUMB2-NEXT: b .LBB0_3 +; THUMB2-NEXT: .LBB0_2: @ %lor.lhs.false +; THUMB2-NEXT: blt .LBB0_4 +; THUMB2-NEXT: .LBB0_3: @ %land.lhs.true3 +; THUMB2-NEXT: movw r1, :lower16:d +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: movt r1, :upper16:d +; THUMB2-NEXT: ldr r1, [r1] +; THUMB2-NEXT: cmp r0, r1 +; THUMB2-NEXT: itt eq +; THUMB2-NEXT: moveq r0, #1 +; THUMB2-NEXT: bxeq lr +; THUMB2-NEXT: .LBB0_4: @ %if.end +; THUMB2-NEXT: movs r0, #0 +; THUMB2-NEXT: bx lr +; +; THUMBV8-LABEL: combine_gt_ge_10: +; THUMBV8: @ %bb.0: @ %entry +; THUMBV8-NEXT: movw r0, :lower16:a +; THUMBV8-NEXT: movt r0, :upper16:a +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: cmp r0, #10 +; THUMBV8-NEXT: movw r0, :lower16:b +; THUMBV8-NEXT: movt r0, :upper16:b +; THUMBV8-NEXT: ble .LBB0_2 +; THUMBV8-NEXT: @ %bb.1: @ %land.lhs.true +; THUMBV8-NEXT: movw r1, :lower16:c +; THUMBV8-NEXT: ldr r2, [r0] +; THUMBV8-NEXT: movt r1, :upper16:c +; THUMBV8-NEXT: ldr r1, [r1] +; THUMBV8-NEXT: cmp r2, r1 +; THUMBV8-NEXT: itt eq +; THUMBV8-NEXT: moveq r0, #1 +; THUMBV8-NEXT: bxeq lr +; THUMBV8-NEXT: b .LBB0_3 +; THUMBV8-NEXT: .LBB0_2: @ %lor.lhs.false +; THUMBV8-NEXT: blt .LBB0_4 +; THUMBV8-NEXT: .LBB0_3: @ %land.lhs.true3 +; THUMBV8-NEXT: movw r1, :lower16:d +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: movt r1, :upper16:d +; THUMBV8-NEXT: ldr r1, [r1] +; THUMBV8-NEXT: cmp r0, r1 +; THUMBV8-NEXT: itt eq +; THUMBV8-NEXT: moveq r0, #1 +; THUMBV8-NEXT: bxeq lr +; THUMBV8-NEXT: .LBB0_4: @ %if.end +; THUMBV8-NEXT: movs r0, #0 +; THUMBV8-NEXT: bx lr +entry: + %0 = load i32, ptr @a, align 4 + %cmp = icmp sgt i32 %0, 10 + br i1 %cmp, label %land.lhs.true, label %lor.lhs.false + +land.lhs.true: ; preds = %entry + %1 = load i32, ptr @b, align 4 + %2 = load i32, ptr @c, align 4 + %cmp1 = icmp eq i32 %1, %2 + br i1 %cmp1, label %return, label %land.lhs.true3 + +lor.lhs.false: ; preds = %entry + %cmp2 = icmp sgt i32 %0, 9 + br i1 %cmp2, label %land.lhs.true3, label %if.end + +land.lhs.true3: ; preds = %lor.lhs.false, %land.lhs.true + %3 = load i32, ptr @b, align 4 + %4 = load i32, ptr @d, align 4 + %cmp4 = icmp eq i32 %3, %4 + br i1 %cmp4, label %return, label %if.end + +if.end: ; preds = %land.lhs.true3, %lor.lhs.false + br label %return + +return: ; preds = %if.end, %land.lhs.true3, %land.lhs.true + %retval.0 = phi i32 [ 0, %if.end ], [ 1, %land.lhs.true3 ], [ 1, %land.lhs.true ] + ret i32 %retval.0 +} + +; (a > 5 && b == c) || (a < 5 && b == d) +define i32 @combine_gt_lt_5() #0 { +; ARM-LABEL: combine_gt_lt_5: +; ARM: @ %bb.0: @ %entry +; ARM-NEXT: movw r0, :lower16:a +; ARM-NEXT: movt r0, :upper16:a +; ARM-NEXT: ldr r0, [r0] +; ARM-NEXT: cmp r0, #5 +; ARM-NEXT: ble .LBB1_2 +; ARM-NEXT: @ %bb.1: @ %land.lhs.true +; ARM-NEXT: movw r0, :lower16:c +; ARM-NEXT: movt r0, :upper16:c +; ARM-NEXT: b .LBB1_4 +; ARM-NEXT: .LBB1_2: @ %lor.lhs.false +; ARM-NEXT: bge .LBB1_5 +; ARM-NEXT: @ %bb.3: @ %land.lhs.true3 +; ARM-NEXT: movw r0, :lower16:d +; ARM-NEXT: movt r0, :upper16:d +; ARM-NEXT: .LBB1_4: @ %land.lhs.true3 +; ARM-NEXT: ldr r1, [r0] +; ARM-NEXT: movw r0, :lower16:b +; ARM-NEXT: movt r0, :upper16:b +; ARM-NEXT: ldr r2, [r0] +; ARM-NEXT: mov r0, #1 +; ARM-NEXT: cmp r2, r1 +; ARM-NEXT: movne r0, #0 +; ARM-NEXT: bx lr +; ARM-NEXT: .LBB1_5: @ %if.end +; ARM-NEXT: mov r0, #0 +; ARM-NEXT: bx lr +; +; THUMB-LABEL: combine_gt_lt_5: +; THUMB: @ %bb.0: @ %entry +; THUMB-NEXT: ldr r0, .LCPI1_0 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: cmp r0, #5 +; THUMB-NEXT: ble .LBB1_3 +; THUMB-NEXT: @ %bb.1: @ %land.lhs.true +; THUMB-NEXT: ldr r0, .LCPI1_3 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: ldr r1, .LCPI1_2 +; THUMB-NEXT: ldr r1, [r1] +; THUMB-NEXT: cmp r1, r0 +; THUMB-NEXT: bne .LBB1_6 +; THUMB-NEXT: @ %bb.2: +; THUMB-NEXT: movs r0, #1 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .LBB1_3: @ %lor.lhs.false +; THUMB-NEXT: bge .LBB1_6 +; THUMB-NEXT: @ %bb.4: @ %land.lhs.true3 +; THUMB-NEXT: ldr r0, .LCPI1_1 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: ldr r1, .LCPI1_2 +; THUMB-NEXT: ldr r1, [r1] +; THUMB-NEXT: cmp r1, r0 +; THUMB-NEXT: bne .LBB1_6 +; THUMB-NEXT: @ %bb.5: +; THUMB-NEXT: movs r0, #1 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .LBB1_6: @ %if.end +; THUMB-NEXT: movs r0, #0 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .p2align 2 +; THUMB-NEXT: @ %bb.7: +; THUMB-NEXT: .LCPI1_0: +; THUMB-NEXT: .long a +; THUMB-NEXT: .LCPI1_1: +; THUMB-NEXT: .long d +; THUMB-NEXT: .LCPI1_2: +; THUMB-NEXT: .long b +; THUMB-NEXT: .LCPI1_3: +; THUMB-NEXT: .long c +; +; THUMB2-LABEL: combine_gt_lt_5: +; THUMB2: @ %bb.0: @ %entry +; THUMB2-NEXT: movw r0, :lower16:a +; THUMB2-NEXT: movt r0, :upper16:a +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: cmp r0, #5 +; THUMB2-NEXT: ble .LBB1_2 +; THUMB2-NEXT: @ %bb.1: @ %land.lhs.true +; THUMB2-NEXT: movw r0, :lower16:c +; THUMB2-NEXT: movw r1, :lower16:b +; THUMB2-NEXT: movt r0, :upper16:c +; THUMB2-NEXT: movt r1, :upper16:b +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: ldr r1, [r1] +; THUMB2-NEXT: cmp r1, r0 +; THUMB2-NEXT: itt eq +; THUMB2-NEXT: moveq r0, #1 +; THUMB2-NEXT: bxeq lr +; THUMB2-NEXT: b .LBB1_4 +; THUMB2-NEXT: .LBB1_2: @ %lor.lhs.false +; THUMB2-NEXT: bge .LBB1_4 +; THUMB2-NEXT: @ %bb.3: @ %land.lhs.true3 +; THUMB2-NEXT: movw r0, :lower16:d +; THUMB2-NEXT: movw r1, :lower16:b +; THUMB2-NEXT: movt r0, :upper16:d +; THUMB2-NEXT: movt r1, :upper16:b +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: ldr r1, [r1] +; THUMB2-NEXT: cmp r1, r0 +; THUMB2-NEXT: itt eq +; THUMB2-NEXT: moveq r0, #1 +; THUMB2-NEXT: bxeq lr +; THUMB2-NEXT: .LBB1_4: @ %if.end +; THUMB2-NEXT: movs r0, #0 +; THUMB2-NEXT: bx lr +; +; THUMBV8-LABEL: combine_gt_lt_5: +; THUMBV8: @ %bb.0: @ %entry +; THUMBV8-NEXT: movw r0, :lower16:a +; THUMBV8-NEXT: movt r0, :upper16:a +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: cmp r0, #5 +; THUMBV8-NEXT: ble .LBB1_2 +; THUMBV8-NEXT: @ %bb.1: @ %land.lhs.true +; THUMBV8-NEXT: movw r0, :lower16:c +; THUMBV8-NEXT: movw r1, :lower16:b +; THUMBV8-NEXT: movt r0, :upper16:c +; THUMBV8-NEXT: movt r1, :upper16:b +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: ldr r1, [r1] +; THUMBV8-NEXT: cmp r1, r0 +; THUMBV8-NEXT: itt eq +; THUMBV8-NEXT: moveq r0, #1 +; THUMBV8-NEXT: bxeq lr +; THUMBV8-NEXT: b .LBB1_4 +; THUMBV8-NEXT: .LBB1_2: @ %lor.lhs.false +; THUMBV8-NEXT: bge .LBB1_4 +; THUMBV8-NEXT: @ %bb.3: @ %land.lhs.true3 +; THUMBV8-NEXT: movw r0, :lower16:d +; THUMBV8-NEXT: movw r1, :lower16:b +; THUMBV8-NEXT: movt r0, :upper16:d +; THUMBV8-NEXT: movt r1, :upper16:b +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: ldr r1, [r1] +; THUMBV8-NEXT: cmp r1, r0 +; THUMBV8-NEXT: itt eq +; THUMBV8-NEXT: moveq r0, #1 +; THUMBV8-NEXT: bxeq lr +; THUMBV8-NEXT: .LBB1_4: @ %if.end +; THUMBV8-NEXT: movs r0, #0 +; THUMBV8-NEXT: bx lr +entry: + %0 = load i32, ptr @a, align 4 + %cmp = icmp sgt i32 %0, 5 + br i1 %cmp, label %land.lhs.true, label %lor.lhs.false + +land.lhs.true: ; preds = %entry + %1 = load i32, ptr @b, align 4 + %2 = load i32, ptr @c, align 4 + %cmp1 = icmp eq i32 %1, %2 + br i1 %cmp1, label %return, label %if.end + +lor.lhs.false: ; preds = %entry + %cmp2 = icmp slt i32 %0, 5 + br i1 %cmp2, label %land.lhs.true3, label %if.end + +land.lhs.true3: ; preds = %lor.lhs.false + %3 = load i32, ptr @b, align 4 + %4 = load i32, ptr @d, align 4 + %cmp4 = icmp eq i32 %3, %4 + br i1 %cmp4, label %return, label %if.end + +if.end: ; preds = %land.lhs.true3, %lor.lhs.false, %land.lhs.true + br label %return + +return: ; preds = %if.end, %land.lhs.true3, %land.lhs.true + %retval.0 = phi i32 [ 0, %if.end ], [ 1, %land.lhs.true3 ], [ 1, %land.lhs.true ] + ret i32 %retval.0 +} + +; (a < 5 && b == c) || (a <= 5 && b == d) +define i32 @combine_lt_ge_5() #0 { +; ARM-LABEL: combine_lt_ge_5: +; ARM: @ %bb.0: @ %entry +; ARM-NEXT: movw r0, :lower16:a +; ARM-NEXT: movw r1, :lower16:b +; ARM-NEXT: movt r0, :upper16:a +; ARM-NEXT: movt r1, :upper16:b +; ARM-NEXT: ldr r0, [r0] +; ARM-NEXT: cmp r0, #5 +; ARM-NEXT: bge .LBB2_2 +; ARM-NEXT: @ %bb.1: @ %land.lhs.true +; ARM-NEXT: movw r0, :lower16:c +; ARM-NEXT: ldr r3, [r1] +; ARM-NEXT: movt r0, :upper16:c +; ARM-NEXT: ldr r2, [r0] +; ARM-NEXT: mov r0, #1 +; ARM-NEXT: cmp r3, r2 +; ARM-NEXT: bxeq lr +; ARM-NEXT: b .LBB2_3 +; ARM-NEXT: .LBB2_2: @ %lor.lhs.false +; ARM-NEXT: bgt .LBB2_4 +; ARM-NEXT: .LBB2_3: @ %land.lhs.true3 +; ARM-NEXT: movw r0, :lower16:d +; ARM-NEXT: ldr r1, [r1] +; ARM-NEXT: movt r0, :upper16:d +; ARM-NEXT: ldr r2, [r0] +; ARM-NEXT: mov r0, #1 +; ARM-NEXT: cmp r1, r2 +; ARM-NEXT: movne r0, #0 +; ARM-NEXT: bx lr +; ARM-NEXT: .LBB2_4: @ %if.end +; ARM-NEXT: mov r0, #0 +; ARM-NEXT: bx lr +; +; THUMB-LABEL: combine_lt_ge_5: +; THUMB: @ %bb.0: @ %entry +; THUMB-NEXT: ldr r0, .LCPI2_0 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: cmp r0, #5 +; THUMB-NEXT: bge .LBB2_3 +; THUMB-NEXT: @ %bb.1: @ %land.lhs.true +; THUMB-NEXT: ldr r0, .LCPI2_1 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: ldr r1, .LCPI2_2 +; THUMB-NEXT: ldr r1, [r1] +; THUMB-NEXT: cmp r1, r0 +; THUMB-NEXT: bne .LBB2_4 +; THUMB-NEXT: @ %bb.2: +; THUMB-NEXT: movs r0, #1 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .LBB2_3: @ %lor.lhs.false +; THUMB-NEXT: bgt .LBB2_6 +; THUMB-NEXT: .LBB2_4: @ %land.lhs.true3 +; THUMB-NEXT: ldr r0, .LCPI2_3 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: ldr r1, .LCPI2_2 +; THUMB-NEXT: ldr r1, [r1] +; THUMB-NEXT: cmp r1, r0 +; THUMB-NEXT: bne .LBB2_6 +; THUMB-NEXT: @ %bb.5: +; THUMB-NEXT: movs r0, #1 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .LBB2_6: @ %if.end +; THUMB-NEXT: movs r0, #0 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .p2align 2 +; THUMB-NEXT: @ %bb.7: +; THUMB-NEXT: .LCPI2_0: +; THUMB-NEXT: .long a +; THUMB-NEXT: .LCPI2_1: +; THUMB-NEXT: .long c +; THUMB-NEXT: .LCPI2_2: +; THUMB-NEXT: .long b +; THUMB-NEXT: .LCPI2_3: +; THUMB-NEXT: .long d +; +; THUMB2-LABEL: combine_lt_ge_5: +; THUMB2: @ %bb.0: @ %entry +; THUMB2-NEXT: movw r0, :lower16:a +; THUMB2-NEXT: movt r0, :upper16:a +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: cmp r0, #5 +; THUMB2-NEXT: movw r0, :lower16:b +; THUMB2-NEXT: movt r0, :upper16:b +; THUMB2-NEXT: bge .LBB2_2 +; THUMB2-NEXT: @ %bb.1: @ %land.lhs.true +; THUMB2-NEXT: movw r1, :lower16:c +; THUMB2-NEXT: ldr r2, [r0] +; THUMB2-NEXT: movt r1, :upper16:c +; THUMB2-NEXT: ldr r1, [r1] +; THUMB2-NEXT: cmp r2, r1 +; THUMB2-NEXT: itt eq +; THUMB2-NEXT: moveq r0, #1 +; THUMB2-NEXT: bxeq lr +; THUMB2-NEXT: b .LBB2_3 +; THUMB2-NEXT: .LBB2_2: @ %lor.lhs.false +; THUMB2-NEXT: bgt .LBB2_4 +; THUMB2-NEXT: .LBB2_3: @ %land.lhs.true3 +; THUMB2-NEXT: movw r1, :lower16:d +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: movt r1, :upper16:d +; THUMB2-NEXT: ldr r1, [r1] +; THUMB2-NEXT: cmp r0, r1 +; THUMB2-NEXT: itt eq +; THUMB2-NEXT: moveq r0, #1 +; THUMB2-NEXT: bxeq lr +; THUMB2-NEXT: .LBB2_4: @ %if.end +; THUMB2-NEXT: movs r0, #0 +; THUMB2-NEXT: bx lr +; +; THUMBV8-LABEL: combine_lt_ge_5: +; THUMBV8: @ %bb.0: @ %entry +; THUMBV8-NEXT: movw r0, :lower16:a +; THUMBV8-NEXT: movt r0, :upper16:a +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: cmp r0, #5 +; THUMBV8-NEXT: movw r0, :lower16:b +; THUMBV8-NEXT: movt r0, :upper16:b +; THUMBV8-NEXT: bge .LBB2_2 +; THUMBV8-NEXT: @ %bb.1: @ %land.lhs.true +; THUMBV8-NEXT: movw r1, :lower16:c +; THUMBV8-NEXT: ldr r2, [r0] +; THUMBV8-NEXT: movt r1, :upper16:c +; THUMBV8-NEXT: ldr r1, [r1] +; THUMBV8-NEXT: cmp r2, r1 +; THUMBV8-NEXT: itt eq +; THUMBV8-NEXT: moveq r0, #1 +; THUMBV8-NEXT: bxeq lr +; THUMBV8-NEXT: b .LBB2_3 +; THUMBV8-NEXT: .LBB2_2: @ %lor.lhs.false +; THUMBV8-NEXT: bgt .LBB2_4 +; THUMBV8-NEXT: .LBB2_3: @ %land.lhs.true3 +; THUMBV8-NEXT: movw r1, :lower16:d +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: movt r1, :upper16:d +; THUMBV8-NEXT: ldr r1, [r1] +; THUMBV8-NEXT: cmp r0, r1 +; THUMBV8-NEXT: itt eq +; THUMBV8-NEXT: moveq r0, #1 +; THUMBV8-NEXT: bxeq lr +; THUMBV8-NEXT: .LBB2_4: @ %if.end +; THUMBV8-NEXT: movs r0, #0 +; THUMBV8-NEXT: bx lr +entry: + %0 = load i32, ptr @a, align 4 + %cmp = icmp slt i32 %0, 5 + br i1 %cmp, label %land.lhs.true, label %lor.lhs.false + +land.lhs.true: ; preds = %entry + %1 = load i32, ptr @b, align 4 + %2 = load i32, ptr @c, align 4 + %cmp1 = icmp eq i32 %1, %2 + br i1 %cmp1, label %return, label %land.lhs.true3 + +lor.lhs.false: ; preds = %entry + %cmp2 = icmp slt i32 %0, 6 + br i1 %cmp2, label %land.lhs.true3, label %if.end + +land.lhs.true3: ; preds = %lor.lhs.false, %land.lhs.true + %3 = load i32, ptr @b, align 4 + %4 = load i32, ptr @d, align 4 + %cmp4 = icmp eq i32 %3, %4 + br i1 %cmp4, label %return, label %if.end + +if.end: ; preds = %land.lhs.true3, %lor.lhs.false + br label %return + +return: ; preds = %if.end, %land.lhs.true3, %land.lhs.true + %retval.0 = phi i32 [ 0, %if.end ], [ 1, %land.lhs.true3 ], [ 1, %land.lhs.true ] + ret i32 %retval.0 +} + +; (a < 5 && b == c) || (a > 5 && b == d) +define i32 @combine_lt_gt_5() #0 { +; ARM-LABEL: combine_lt_gt_5: +; ARM: @ %bb.0: @ %entry +; ARM-NEXT: movw r0, :lower16:a +; ARM-NEXT: movt r0, :upper16:a +; ARM-NEXT: ldr r0, [r0] +; ARM-NEXT: cmp r0, #5 +; ARM-NEXT: bge .LBB3_2 +; ARM-NEXT: @ %bb.1: @ %land.lhs.true +; ARM-NEXT: movw r0, :lower16:c +; ARM-NEXT: movt r0, :upper16:c +; ARM-NEXT: b .LBB3_4 +; ARM-NEXT: .LBB3_2: @ %lor.lhs.false +; ARM-NEXT: ble .LBB3_5 +; ARM-NEXT: @ %bb.3: @ %land.lhs.true3 +; ARM-NEXT: movw r0, :lower16:d +; ARM-NEXT: movt r0, :upper16:d +; ARM-NEXT: .LBB3_4: @ %land.lhs.true3 +; ARM-NEXT: ldr r1, [r0] +; ARM-NEXT: movw r0, :lower16:b +; ARM-NEXT: movt r0, :upper16:b +; ARM-NEXT: ldr r2, [r0] +; ARM-NEXT: mov r0, #1 +; ARM-NEXT: cmp r2, r1 +; ARM-NEXT: movne r0, #0 +; ARM-NEXT: bx lr +; ARM-NEXT: .LBB3_5: @ %if.end +; ARM-NEXT: mov r0, #0 +; ARM-NEXT: bx lr +; +; THUMB-LABEL: combine_lt_gt_5: +; THUMB: @ %bb.0: @ %entry +; THUMB-NEXT: ldr r0, .LCPI3_0 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: cmp r0, #5 +; THUMB-NEXT: bge .LBB3_3 +; THUMB-NEXT: @ %bb.1: @ %land.lhs.true +; THUMB-NEXT: ldr r0, .LCPI3_3 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: ldr r1, .LCPI3_2 +; THUMB-NEXT: ldr r1, [r1] +; THUMB-NEXT: cmp r1, r0 +; THUMB-NEXT: bne .LBB3_6 +; THUMB-NEXT: @ %bb.2: +; THUMB-NEXT: movs r0, #1 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .LBB3_3: @ %lor.lhs.false +; THUMB-NEXT: ble .LBB3_6 +; THUMB-NEXT: @ %bb.4: @ %land.lhs.true3 +; THUMB-NEXT: ldr r0, .LCPI3_1 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: ldr r1, .LCPI3_2 +; THUMB-NEXT: ldr r1, [r1] +; THUMB-NEXT: cmp r1, r0 +; THUMB-NEXT: bne .LBB3_6 +; THUMB-NEXT: @ %bb.5: +; THUMB-NEXT: movs r0, #1 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .LBB3_6: @ %if.end +; THUMB-NEXT: movs r0, #0 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .p2align 2 +; THUMB-NEXT: @ %bb.7: +; THUMB-NEXT: .LCPI3_0: +; THUMB-NEXT: .long a +; THUMB-NEXT: .LCPI3_1: +; THUMB-NEXT: .long d +; THUMB-NEXT: .LCPI3_2: +; THUMB-NEXT: .long b +; THUMB-NEXT: .LCPI3_3: +; THUMB-NEXT: .long c +; +; THUMB2-LABEL: combine_lt_gt_5: +; THUMB2: @ %bb.0: @ %entry +; THUMB2-NEXT: movw r0, :lower16:a +; THUMB2-NEXT: movt r0, :upper16:a +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: cmp r0, #5 +; THUMB2-NEXT: bge .LBB3_2 +; THUMB2-NEXT: @ %bb.1: @ %land.lhs.true +; THUMB2-NEXT: movw r0, :lower16:c +; THUMB2-NEXT: movw r1, :lower16:b +; THUMB2-NEXT: movt r0, :upper16:c +; THUMB2-NEXT: movt r1, :upper16:b +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: ldr r1, [r1] +; THUMB2-NEXT: cmp r1, r0 +; THUMB2-NEXT: itt eq +; THUMB2-NEXT: moveq r0, #1 +; THUMB2-NEXT: bxeq lr +; THUMB2-NEXT: b .LBB3_4 +; THUMB2-NEXT: .LBB3_2: @ %lor.lhs.false +; THUMB2-NEXT: ble .LBB3_4 +; THUMB2-NEXT: @ %bb.3: @ %land.lhs.true3 +; THUMB2-NEXT: movw r0, :lower16:d +; THUMB2-NEXT: movw r1, :lower16:b +; THUMB2-NEXT: movt r0, :upper16:d +; THUMB2-NEXT: movt r1, :upper16:b +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: ldr r1, [r1] +; THUMB2-NEXT: cmp r1, r0 +; THUMB2-NEXT: itt eq +; THUMB2-NEXT: moveq r0, #1 +; THUMB2-NEXT: bxeq lr +; THUMB2-NEXT: .LBB3_4: @ %if.end +; THUMB2-NEXT: movs r0, #0 +; THUMB2-NEXT: bx lr +; +; THUMBV8-LABEL: combine_lt_gt_5: +; THUMBV8: @ %bb.0: @ %entry +; THUMBV8-NEXT: movw r0, :lower16:a +; THUMBV8-NEXT: movt r0, :upper16:a +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: cmp r0, #5 +; THUMBV8-NEXT: bge .LBB3_2 +; THUMBV8-NEXT: @ %bb.1: @ %land.lhs.true +; THUMBV8-NEXT: movw r0, :lower16:c +; THUMBV8-NEXT: movw r1, :lower16:b +; THUMBV8-NEXT: movt r0, :upper16:c +; THUMBV8-NEXT: movt r1, :upper16:b +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: ldr r1, [r1] +; THUMBV8-NEXT: cmp r1, r0 +; THUMBV8-NEXT: itt eq +; THUMBV8-NEXT: moveq r0, #1 +; THUMBV8-NEXT: bxeq lr +; THUMBV8-NEXT: b .LBB3_4 +; THUMBV8-NEXT: .LBB3_2: @ %lor.lhs.false +; THUMBV8-NEXT: ble .LBB3_4 +; THUMBV8-NEXT: @ %bb.3: @ %land.lhs.true3 +; THUMBV8-NEXT: movw r0, :lower16:d +; THUMBV8-NEXT: movw r1, :lower16:b +; THUMBV8-NEXT: movt r0, :upper16:d +; THUMBV8-NEXT: movt r1, :upper16:b +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: ldr r1, [r1] +; THUMBV8-NEXT: cmp r1, r0 +; THUMBV8-NEXT: itt eq +; THUMBV8-NEXT: moveq r0, #1 +; THUMBV8-NEXT: bxeq lr +; THUMBV8-NEXT: .LBB3_4: @ %if.end +; THUMBV8-NEXT: movs r0, #0 +; THUMBV8-NEXT: bx lr +entry: + %0 = load i32, ptr @a, align 4 + %cmp = icmp slt i32 %0, 5 + br i1 %cmp, label %land.lhs.true, label %lor.lhs.false + +land.lhs.true: ; preds = %entry + %1 = load i32, ptr @b, align 4 + %2 = load i32, ptr @c, align 4 + %cmp1 = icmp eq i32 %1, %2 + br i1 %cmp1, label %return, label %if.end + +lor.lhs.false: ; preds = %entry + %cmp2 = icmp sgt i32 %0, 5 + br i1 %cmp2, label %land.lhs.true3, label %if.end + +land.lhs.true3: ; preds = %lor.lhs.false + %3 = load i32, ptr @b, align 4 + %4 = load i32, ptr @d, align 4 + %cmp4 = icmp eq i32 %3, %4 + br i1 %cmp4, label %return, label %if.end + +if.end: ; preds = %land.lhs.true3, %lor.lhs.false, %land.lhs.true + br label %return + +return: ; preds = %if.end, %land.lhs.true3, %land.lhs.true + %retval.0 = phi i32 [ 0, %if.end ], [ 1, %land.lhs.true3 ], [ 1, %land.lhs.true ] + ret i32 %retval.0 +} + +; (a > -5 && b == c) || (a < -5 && b == d) +define i32 @combine_gt_lt_n5() #0 { +; ARM-LABEL: combine_gt_lt_n5: +; ARM: @ %bb.0: @ %entry +; ARM-NEXT: movw r0, :lower16:a +; ARM-NEXT: movt r0, :upper16:a +; ARM-NEXT: ldr r0, [r0] +; ARM-NEXT: cmn r0, #5 +; ARM-NEXT: ble .LBB4_2 +; ARM-NEXT: @ %bb.1: @ %land.lhs.true +; ARM-NEXT: movw r0, :lower16:c +; ARM-NEXT: movt r0, :upper16:c +; ARM-NEXT: b .LBB4_4 +; ARM-NEXT: .LBB4_2: @ %lor.lhs.false +; ARM-NEXT: bge .LBB4_5 +; ARM-NEXT: @ %bb.3: @ %land.lhs.true3 +; ARM-NEXT: movw r0, :lower16:d +; ARM-NEXT: movt r0, :upper16:d +; ARM-NEXT: .LBB4_4: @ %land.lhs.true3 +; ARM-NEXT: ldr r1, [r0] +; ARM-NEXT: movw r0, :lower16:b +; ARM-NEXT: movt r0, :upper16:b +; ARM-NEXT: ldr r2, [r0] +; ARM-NEXT: mov r0, #1 +; ARM-NEXT: cmp r2, r1 +; ARM-NEXT: movne r0, #0 +; ARM-NEXT: bx lr +; ARM-NEXT: .LBB4_5: @ %if.end +; ARM-NEXT: mov r0, #0 +; ARM-NEXT: bx lr +; +; THUMB-LABEL: combine_gt_lt_n5: +; THUMB: @ %bb.0: @ %entry +; THUMB-NEXT: ldr r0, .LCPI4_0 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: movs r1, #3 +; THUMB-NEXT: mvns r1, r1 +; THUMB-NEXT: cmp r0, r1 +; THUMB-NEXT: blt .LBB4_3 +; THUMB-NEXT: @ %bb.1: @ %land.lhs.true +; THUMB-NEXT: ldr r0, .LCPI4_3 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: ldr r1, .LCPI4_2 +; THUMB-NEXT: ldr r1, [r1] +; THUMB-NEXT: cmp r1, r0 +; THUMB-NEXT: bne .LBB4_6 +; THUMB-NEXT: @ %bb.2: +; THUMB-NEXT: movs r0, #1 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .LBB4_3: @ %lor.lhs.false +; THUMB-NEXT: movs r1, #5 +; THUMB-NEXT: mvns r1, r1 +; THUMB-NEXT: cmp r0, r1 +; THUMB-NEXT: bgt .LBB4_6 +; THUMB-NEXT: @ %bb.4: @ %land.lhs.true3 +; THUMB-NEXT: ldr r0, .LCPI4_1 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: ldr r1, .LCPI4_2 +; THUMB-NEXT: ldr r1, [r1] +; THUMB-NEXT: cmp r1, r0 +; THUMB-NEXT: bne .LBB4_6 +; THUMB-NEXT: @ %bb.5: +; THUMB-NEXT: movs r0, #1 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .LBB4_6: @ %if.end +; THUMB-NEXT: movs r0, #0 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .p2align 2 +; THUMB-NEXT: @ %bb.7: +; THUMB-NEXT: .LCPI4_0: +; THUMB-NEXT: .long a +; THUMB-NEXT: .LCPI4_1: +; THUMB-NEXT: .long d +; THUMB-NEXT: .LCPI4_2: +; THUMB-NEXT: .long b +; THUMB-NEXT: .LCPI4_3: +; THUMB-NEXT: .long c +; +; THUMB2-LABEL: combine_gt_lt_n5: +; THUMB2: @ %bb.0: @ %entry +; THUMB2-NEXT: movw r0, :lower16:a +; THUMB2-NEXT: movt r0, :upper16:a +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: cmn.w r0, #5 +; THUMB2-NEXT: ble .LBB4_2 +; THUMB2-NEXT: @ %bb.1: @ %land.lhs.true +; THUMB2-NEXT: movw r0, :lower16:c +; THUMB2-NEXT: movw r1, :lower16:b +; THUMB2-NEXT: movt r0, :upper16:c +; THUMB2-NEXT: movt r1, :upper16:b +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: ldr r1, [r1] +; THUMB2-NEXT: cmp r1, r0 +; THUMB2-NEXT: itt eq +; THUMB2-NEXT: moveq r0, #1 +; THUMB2-NEXT: bxeq lr +; THUMB2-NEXT: b .LBB4_4 +; THUMB2-NEXT: .LBB4_2: @ %lor.lhs.false +; THUMB2-NEXT: bge .LBB4_4 +; THUMB2-NEXT: @ %bb.3: @ %land.lhs.true3 +; THUMB2-NEXT: movw r0, :lower16:d +; THUMB2-NEXT: movw r1, :lower16:b +; THUMB2-NEXT: movt r0, :upper16:d +; THUMB2-NEXT: movt r1, :upper16:b +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: ldr r1, [r1] +; THUMB2-NEXT: cmp r1, r0 +; THUMB2-NEXT: itt eq +; THUMB2-NEXT: moveq r0, #1 +; THUMB2-NEXT: bxeq lr +; THUMB2-NEXT: .LBB4_4: @ %if.end +; THUMB2-NEXT: movs r0, #0 +; THUMB2-NEXT: bx lr +; +; THUMBV8-LABEL: combine_gt_lt_n5: +; THUMBV8: @ %bb.0: @ %entry +; THUMBV8-NEXT: movw r0, :lower16:a +; THUMBV8-NEXT: movt r0, :upper16:a +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: cmn.w r0, #5 +; THUMBV8-NEXT: ble .LBB4_2 +; THUMBV8-NEXT: @ %bb.1: @ %land.lhs.true +; THUMBV8-NEXT: movw r0, :lower16:c +; THUMBV8-NEXT: movw r1, :lower16:b +; THUMBV8-NEXT: movt r0, :upper16:c +; THUMBV8-NEXT: movt r1, :upper16:b +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: ldr r1, [r1] +; THUMBV8-NEXT: cmp r1, r0 +; THUMBV8-NEXT: itt eq +; THUMBV8-NEXT: moveq r0, #1 +; THUMBV8-NEXT: bxeq lr +; THUMBV8-NEXT: b .LBB4_4 +; THUMBV8-NEXT: .LBB4_2: @ %lor.lhs.false +; THUMBV8-NEXT: bge .LBB4_4 +; THUMBV8-NEXT: @ %bb.3: @ %land.lhs.true3 +; THUMBV8-NEXT: movw r0, :lower16:d +; THUMBV8-NEXT: movw r1, :lower16:b +; THUMBV8-NEXT: movt r0, :upper16:d +; THUMBV8-NEXT: movt r1, :upper16:b +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: ldr r1, [r1] +; THUMBV8-NEXT: cmp r1, r0 +; THUMBV8-NEXT: itt eq +; THUMBV8-NEXT: moveq r0, #1 +; THUMBV8-NEXT: bxeq lr +; THUMBV8-NEXT: .LBB4_4: @ %if.end +; THUMBV8-NEXT: movs r0, #0 +; THUMBV8-NEXT: bx lr +entry: + %0 = load i32, ptr @a, align 4 + %cmp = icmp sgt i32 %0, -5 + br i1 %cmp, label %land.lhs.true, label %lor.lhs.false + +land.lhs.true: ; preds = %entry + %1 = load i32, ptr @b, align 4 + %2 = load i32, ptr @c, align 4 + %cmp1 = icmp eq i32 %1, %2 + br i1 %cmp1, label %return, label %if.end + +lor.lhs.false: ; preds = %entry + %cmp2 = icmp slt i32 %0, -5 + br i1 %cmp2, label %land.lhs.true3, label %if.end + +land.lhs.true3: ; preds = %lor.lhs.false + %3 = load i32, ptr @b, align 4 + %4 = load i32, ptr @d, align 4 + %cmp4 = icmp eq i32 %3, %4 + br i1 %cmp4, label %return, label %if.end + +if.end: ; preds = %land.lhs.true3, %lor.lhs.false, %land.lhs.true + br label %return + +return: ; preds = %if.end, %land.lhs.true3, %land.lhs.true + %retval.0 = phi i32 [ 0, %if.end ], [ 1, %land.lhs.true3 ], [ 1, %land.lhs.true ] + ret i32 %retval.0 +} + +; (a < -5 && b == c) || (a > -5 && b == d) +define i32 @combine_lt_gt_n5() #0 { +; ARM-LABEL: combine_lt_gt_n5: +; ARM: @ %bb.0: @ %entry +; ARM-NEXT: movw r0, :lower16:a +; ARM-NEXT: movt r0, :upper16:a +; ARM-NEXT: ldr r0, [r0] +; ARM-NEXT: cmn r0, #5 +; ARM-NEXT: bge .LBB5_2 +; ARM-NEXT: @ %bb.1: @ %land.lhs.true +; ARM-NEXT: movw r0, :lower16:c +; ARM-NEXT: movt r0, :upper16:c +; ARM-NEXT: b .LBB5_4 +; ARM-NEXT: .LBB5_2: @ %lor.lhs.false +; ARM-NEXT: ble .LBB5_5 +; ARM-NEXT: @ %bb.3: @ %land.lhs.true3 +; ARM-NEXT: movw r0, :lower16:d +; ARM-NEXT: movt r0, :upper16:d +; ARM-NEXT: .LBB5_4: @ %land.lhs.true3 +; ARM-NEXT: ldr r1, [r0] +; ARM-NEXT: movw r0, :lower16:b +; ARM-NEXT: movt r0, :upper16:b +; ARM-NEXT: ldr r2, [r0] +; ARM-NEXT: mov r0, #1 +; ARM-NEXT: cmp r2, r1 +; ARM-NEXT: movne r0, #0 +; ARM-NEXT: bx lr +; ARM-NEXT: .LBB5_5: @ %if.end +; ARM-NEXT: mov r0, #0 +; ARM-NEXT: bx lr +; +; THUMB-LABEL: combine_lt_gt_n5: +; THUMB: @ %bb.0: @ %entry +; THUMB-NEXT: ldr r0, .LCPI5_0 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: movs r1, #5 +; THUMB-NEXT: mvns r1, r1 +; THUMB-NEXT: cmp r0, r1 +; THUMB-NEXT: bgt .LBB5_3 +; THUMB-NEXT: @ %bb.1: @ %land.lhs.true +; THUMB-NEXT: ldr r0, .LCPI5_3 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: ldr r1, .LCPI5_2 +; THUMB-NEXT: ldr r1, [r1] +; THUMB-NEXT: cmp r1, r0 +; THUMB-NEXT: bne .LBB5_6 +; THUMB-NEXT: @ %bb.2: +; THUMB-NEXT: movs r0, #1 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .LBB5_3: @ %lor.lhs.false +; THUMB-NEXT: movs r1, #3 +; THUMB-NEXT: mvns r1, r1 +; THUMB-NEXT: cmp r0, r1 +; THUMB-NEXT: blt .LBB5_6 +; THUMB-NEXT: @ %bb.4: @ %land.lhs.true3 +; THUMB-NEXT: ldr r0, .LCPI5_1 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: ldr r1, .LCPI5_2 +; THUMB-NEXT: ldr r1, [r1] +; THUMB-NEXT: cmp r1, r0 +; THUMB-NEXT: bne .LBB5_6 +; THUMB-NEXT: @ %bb.5: +; THUMB-NEXT: movs r0, #1 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .LBB5_6: @ %if.end +; THUMB-NEXT: movs r0, #0 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .p2align 2 +; THUMB-NEXT: @ %bb.7: +; THUMB-NEXT: .LCPI5_0: +; THUMB-NEXT: .long a +; THUMB-NEXT: .LCPI5_1: +; THUMB-NEXT: .long d +; THUMB-NEXT: .LCPI5_2: +; THUMB-NEXT: .long b +; THUMB-NEXT: .LCPI5_3: +; THUMB-NEXT: .long c +; +; THUMB2-LABEL: combine_lt_gt_n5: +; THUMB2: @ %bb.0: @ %entry +; THUMB2-NEXT: movw r0, :lower16:a +; THUMB2-NEXT: movt r0, :upper16:a +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: cmn.w r0, #5 +; THUMB2-NEXT: bge .LBB5_2 +; THUMB2-NEXT: @ %bb.1: @ %land.lhs.true +; THUMB2-NEXT: movw r0, :lower16:c +; THUMB2-NEXT: movw r1, :lower16:b +; THUMB2-NEXT: movt r0, :upper16:c +; THUMB2-NEXT: movt r1, :upper16:b +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: ldr r1, [r1] +; THUMB2-NEXT: cmp r1, r0 +; THUMB2-NEXT: itt eq +; THUMB2-NEXT: moveq r0, #1 +; THUMB2-NEXT: bxeq lr +; THUMB2-NEXT: b .LBB5_4 +; THUMB2-NEXT: .LBB5_2: @ %lor.lhs.false +; THUMB2-NEXT: ble .LBB5_4 +; THUMB2-NEXT: @ %bb.3: @ %land.lhs.true3 +; THUMB2-NEXT: movw r0, :lower16:d +; THUMB2-NEXT: movw r1, :lower16:b +; THUMB2-NEXT: movt r0, :upper16:d +; THUMB2-NEXT: movt r1, :upper16:b +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: ldr r1, [r1] +; THUMB2-NEXT: cmp r1, r0 +; THUMB2-NEXT: itt eq +; THUMB2-NEXT: moveq r0, #1 +; THUMB2-NEXT: bxeq lr +; THUMB2-NEXT: .LBB5_4: @ %if.end +; THUMB2-NEXT: movs r0, #0 +; THUMB2-NEXT: bx lr +; +; THUMBV8-LABEL: combine_lt_gt_n5: +; THUMBV8: @ %bb.0: @ %entry +; THUMBV8-NEXT: movw r0, :lower16:a +; THUMBV8-NEXT: movt r0, :upper16:a +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: cmn.w r0, #5 +; THUMBV8-NEXT: bge .LBB5_2 +; THUMBV8-NEXT: @ %bb.1: @ %land.lhs.true +; THUMBV8-NEXT: movw r0, :lower16:c +; THUMBV8-NEXT: movw r1, :lower16:b +; THUMBV8-NEXT: movt r0, :upper16:c +; THUMBV8-NEXT: movt r1, :upper16:b +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: ldr r1, [r1] +; THUMBV8-NEXT: cmp r1, r0 +; THUMBV8-NEXT: itt eq +; THUMBV8-NEXT: moveq r0, #1 +; THUMBV8-NEXT: bxeq lr +; THUMBV8-NEXT: b .LBB5_4 +; THUMBV8-NEXT: .LBB5_2: @ %lor.lhs.false +; THUMBV8-NEXT: ble .LBB5_4 +; THUMBV8-NEXT: @ %bb.3: @ %land.lhs.true3 +; THUMBV8-NEXT: movw r0, :lower16:d +; THUMBV8-NEXT: movw r1, :lower16:b +; THUMBV8-NEXT: movt r0, :upper16:d +; THUMBV8-NEXT: movt r1, :upper16:b +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: ldr r1, [r1] +; THUMBV8-NEXT: cmp r1, r0 +; THUMBV8-NEXT: itt eq +; THUMBV8-NEXT: moveq r0, #1 +; THUMBV8-NEXT: bxeq lr +; THUMBV8-NEXT: .LBB5_4: @ %if.end +; THUMBV8-NEXT: movs r0, #0 +; THUMBV8-NEXT: bx lr +entry: + %0 = load i32, ptr @a, align 4 + %cmp = icmp slt i32 %0, -5 + br i1 %cmp, label %land.lhs.true, label %lor.lhs.false + +land.lhs.true: ; preds = %entry + %1 = load i32, ptr @b, align 4 + %2 = load i32, ptr @c, align 4 + %cmp1 = icmp eq i32 %1, %2 + br i1 %cmp1, label %return, label %if.end + +lor.lhs.false: ; preds = %entry + %cmp2 = icmp sgt i32 %0, -5 + br i1 %cmp2, label %land.lhs.true3, label %if.end + +land.lhs.true3: ; preds = %lor.lhs.false + %3 = load i32, ptr @b, align 4 + %4 = load i32, ptr @d, align 4 + %cmp4 = icmp eq i32 %3, %4 + br i1 %cmp4, label %return, label %if.end + +if.end: ; preds = %land.lhs.true3, %lor.lhs.false, %land.lhs.true + br label %return + +return: ; preds = %if.end, %land.lhs.true3, %land.lhs.true + %retval.0 = phi i32 [ 0, %if.end ], [ 1, %land.lhs.true3 ], [ 1, %land.lhs.true ] + ret i32 %retval.0 +} + +%struct.Struct = type { i32, i32 } + +@glob = internal unnamed_addr global ptr null, align 8 + +declare ptr @Update(ptr) #1 + +; no checks for this case, it just should be processed without errors +define void @combine_non_adjacent_cmp_br(ptr nocapture readonly %hdCall) #0 { +; ARM-LABEL: combine_non_adjacent_cmp_br: +; ARM: @ %bb.0: @ %entry +; ARM-NEXT: push {r4, r5, r6, r7, r11, lr} +; ARM-NEXT: ldr r4, [r0] +; ARM-NEXT: movw r7, :lower16:glob +; ARM-NEXT: mov r6, #24 +; ARM-NEXT: movt r7, :upper16:glob +; ARM-NEXT: add r5, r4, #2 +; ARM-NEXT: .LBB6_1: @ %land.rhs +; ARM-NEXT: @ =>This Inner Loop Header: Depth=1 +; ARM-NEXT: ldr r0, [r6] +; ARM-NEXT: cmp r0, #1 +; ARM-NEXT: blt .LBB6_3 +; ARM-NEXT: @ %bb.2: @ %while.body +; ARM-NEXT: @ in Loop: Header=BB6_1 Depth=1 +; ARM-NEXT: ldr r0, [r7] +; ARM-NEXT: bl Update +; ARM-NEXT: sub r5, r5, #2 +; ARM-NEXT: cmp r4, r5 +; ARM-NEXT: blt .LBB6_1 +; ARM-NEXT: .LBB6_3: @ %while.end +; ARM-NEXT: pop {r4, r5, r6, r7, r11, pc} +; +; THUMB-LABEL: combine_non_adjacent_cmp_br: +; THUMB: @ %bb.0: @ %entry +; THUMB-NEXT: push {r4, r5, r6, lr} +; THUMB-NEXT: ldr r4, [r0] +; THUMB-NEXT: adds r5, r4, #2 +; THUMB-NEXT: ldr r6, .LCPI6_0 +; THUMB-NEXT: .LBB6_1: @ %land.rhs +; THUMB-NEXT: @ =>This Inner Loop Header: Depth=1 +; THUMB-NEXT: movs r0, #24 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: cmp r0, #1 +; THUMB-NEXT: blt .LBB6_3 +; THUMB-NEXT: @ %bb.2: @ %while.body +; THUMB-NEXT: @ in Loop: Header=BB6_1 Depth=1 +; THUMB-NEXT: ldr r0, [r6] +; THUMB-NEXT: bl Update +; THUMB-NEXT: subs r5, r5, #2 +; THUMB-NEXT: cmp r4, r5 +; THUMB-NEXT: blt .LBB6_1 +; THUMB-NEXT: .LBB6_3: @ %while.end +; THUMB-NEXT: pop {r4, r5, r6, pc} +; THUMB-NEXT: .p2align 2 +; THUMB-NEXT: @ %bb.4: +; THUMB-NEXT: .LCPI6_0: +; THUMB-NEXT: .long glob +; +; THUMB2-LABEL: combine_non_adjacent_cmp_br: +; THUMB2: @ %bb.0: @ %entry +; THUMB2-NEXT: push {r4, r5, r6, r7, lr} +; THUMB2-NEXT: sub sp, #4 +; THUMB2-NEXT: ldr r4, [r0] +; THUMB2-NEXT: movw r7, :lower16:glob +; THUMB2-NEXT: movs r6, #24 +; THUMB2-NEXT: movt r7, :upper16:glob +; THUMB2-NEXT: adds r5, r4, #2 +; THUMB2-NEXT: .LBB6_1: @ %land.rhs +; THUMB2-NEXT: @ =>This Inner Loop Header: Depth=1 +; THUMB2-NEXT: ldr r0, [r6] +; THUMB2-NEXT: cmp r0, #1 +; THUMB2-NEXT: blt .LBB6_3 +; THUMB2-NEXT: @ %bb.2: @ %while.body +; THUMB2-NEXT: @ in Loop: Header=BB6_1 Depth=1 +; THUMB2-NEXT: ldr r0, [r7] +; THUMB2-NEXT: bl Update +; THUMB2-NEXT: subs r5, #2 +; THUMB2-NEXT: cmp r4, r5 +; THUMB2-NEXT: blt .LBB6_1 +; THUMB2-NEXT: .LBB6_3: @ %while.end +; THUMB2-NEXT: add sp, #4 +; THUMB2-NEXT: pop {r4, r5, r6, r7, pc} +; +; THUMBV8-LABEL: combine_non_adjacent_cmp_br: +; THUMBV8: @ %bb.0: @ %entry +; THUMBV8-NEXT: push {r4, r5, r6, r7, lr} +; THUMBV8-NEXT: sub sp, #4 +; THUMBV8-NEXT: ldr r4, [r0] +; THUMBV8-NEXT: movw r7, :lower16:glob +; THUMBV8-NEXT: movs r6, #24 +; THUMBV8-NEXT: movt r7, :upper16:glob +; THUMBV8-NEXT: adds r5, r4, #2 +; THUMBV8-NEXT: .LBB6_1: @ %land.rhs +; THUMBV8-NEXT: @ =>This Inner Loop Header: Depth=1 +; THUMBV8-NEXT: ldr r0, [r6] +; THUMBV8-NEXT: cmp r0, #1 +; THUMBV8-NEXT: blt .LBB6_3 +; THUMBV8-NEXT: @ %bb.2: @ %while.body +; THUMBV8-NEXT: @ in Loop: Header=BB6_1 Depth=1 +; THUMBV8-NEXT: ldr r0, [r7] +; THUMBV8-NEXT: bl Update +; THUMBV8-NEXT: subs r5, #2 +; THUMBV8-NEXT: cmp r4, r5 +; THUMBV8-NEXT: blt .LBB6_1 +; THUMBV8-NEXT: .LBB6_3: @ %while.end +; THUMBV8-NEXT: add sp, #4 +; THUMBV8-NEXT: pop {r4, r5, r6, r7, pc} +entry: + %0 = load i32, ptr %hdCall, align 8 + br label %land.rhs + +land.rhs: + %rp.06 = phi i32 [ %0, %entry ], [ %sub, %while.body ] + %1 = load i32, ptr inttoptr (i32 24 to ptr), align 8 + %cmp2 = icmp sgt i32 %1, 0 + br i1 %cmp2, label %while.body, label %while.end + +while.body: + %2 = load ptr, ptr @glob, align 8 + %call = tail call ptr @Update(ptr %2) #2 + %sub = add nsw i32 %rp.06, -2 + %cmp = icmp slt i32 %0, %rp.06 + br i1 %cmp, label %land.rhs, label %while.end + +while.end: + ret void +} + +; undefined external to prevent possible optimizations +declare void @do_something() #1 + +define i32 @do_nothing_if_resultant_opcodes_would_differ() #0 { +; ARM-LABEL: do_nothing_if_resultant_opcodes_would_differ: +; ARM: @ %bb.0: @ %entry +; ARM-NEXT: push {r4, r5, r11, lr} +; ARM-NEXT: movw r4, :lower16:a +; ARM-NEXT: movt r4, :upper16:a +; ARM-NEXT: ldr r0, [r4] +; ARM-NEXT: cmn r0, #2 +; ARM-NEXT: bgt .LBB7_4 +; ARM-NEXT: @ %bb.1: @ %while.body.preheader +; ARM-NEXT: sub r5, r0, #1 +; ARM-NEXT: .LBB7_2: @ %while.body +; ARM-NEXT: @ =>This Inner Loop Header: Depth=1 +; ARM-NEXT: bl do_something +; ARM-NEXT: adds r5, r5, #1 +; ARM-NEXT: bmi .LBB7_2 +; ARM-NEXT: @ %bb.3: @ %while.cond.while.end_crit_edge +; ARM-NEXT: ldr r0, [r4] +; ARM-NEXT: .LBB7_4: @ %while.end +; ARM-NEXT: cmp r0, #1 +; ARM-NEXT: bgt .LBB7_6 +; ARM-NEXT: @ %bb.5: @ %land.lhs.true +; ARM-NEXT: movw r0, :lower16:d +; ARM-NEXT: movt r0, :upper16:d +; ARM-NEXT: ldr r1, [r0] +; ARM-NEXT: movw r0, :lower16:b +; ARM-NEXT: movt r0, :upper16:b +; ARM-NEXT: ldr r2, [r0] +; ARM-NEXT: mov r0, #123 +; ARM-NEXT: cmp r2, r1 +; ARM-NEXT: movne r0, #0 +; ARM-NEXT: pop {r4, r5, r11, pc} +; ARM-NEXT: .LBB7_6: @ %if.end +; ARM-NEXT: mov r0, #0 +; ARM-NEXT: pop {r4, r5, r11, pc} +; +; THUMB-LABEL: do_nothing_if_resultant_opcodes_would_differ: +; THUMB: @ %bb.0: @ %entry +; THUMB-NEXT: push {r4, r5, r7, lr} +; THUMB-NEXT: ldr r4, .LCPI7_0 +; THUMB-NEXT: ldr r0, [r4] +; THUMB-NEXT: movs r1, #1 +; THUMB-NEXT: mvns r1, r1 +; THUMB-NEXT: cmp r0, r1 +; THUMB-NEXT: bgt .LBB7_4 +; THUMB-NEXT: @ %bb.1: @ %while.body.preheader +; THUMB-NEXT: subs r5, r0, #1 +; THUMB-NEXT: .LBB7_2: @ %while.body +; THUMB-NEXT: @ =>This Inner Loop Header: Depth=1 +; THUMB-NEXT: bl do_something +; THUMB-NEXT: adds r5, r5, #1 +; THUMB-NEXT: bmi .LBB7_2 +; THUMB-NEXT: @ %bb.3: @ %while.cond.while.end_crit_edge +; THUMB-NEXT: ldr r0, [r4] +; THUMB-NEXT: .LBB7_4: @ %while.end +; THUMB-NEXT: cmp r0, #1 +; THUMB-NEXT: bgt .LBB7_7 +; THUMB-NEXT: @ %bb.5: @ %land.lhs.true +; THUMB-NEXT: ldr r0, .LCPI7_1 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: ldr r1, .LCPI7_2 +; THUMB-NEXT: ldr r1, [r1] +; THUMB-NEXT: cmp r1, r0 +; THUMB-NEXT: bne .LBB7_7 +; THUMB-NEXT: @ %bb.6: +; THUMB-NEXT: movs r0, #123 +; THUMB-NEXT: pop {r4, r5, r7, pc} +; THUMB-NEXT: .LBB7_7: @ %if.end +; THUMB-NEXT: movs r0, #0 +; THUMB-NEXT: pop {r4, r5, r7, pc} +; THUMB-NEXT: .p2align 2 +; THUMB-NEXT: @ %bb.8: +; THUMB-NEXT: .LCPI7_0: +; THUMB-NEXT: .long a +; THUMB-NEXT: .LCPI7_1: +; THUMB-NEXT: .long d +; THUMB-NEXT: .LCPI7_2: +; THUMB-NEXT: .long b +; +; THUMB2-LABEL: do_nothing_if_resultant_opcodes_would_differ: +; THUMB2: @ %bb.0: @ %entry +; THUMB2-NEXT: push {r4, r5, r7, lr} +; THUMB2-NEXT: movw r4, :lower16:a +; THUMB2-NEXT: movt r4, :upper16:a +; THUMB2-NEXT: ldr r0, [r4] +; THUMB2-NEXT: cmn.w r0, #2 +; THUMB2-NEXT: bgt .LBB7_4 +; THUMB2-NEXT: @ %bb.1: @ %while.body.preheader +; THUMB2-NEXT: subs r5, r0, #1 +; THUMB2-NEXT: .LBB7_2: @ %while.body +; THUMB2-NEXT: @ =>This Inner Loop Header: Depth=1 +; THUMB2-NEXT: bl do_something +; THUMB2-NEXT: adds r5, #1 +; THUMB2-NEXT: bmi .LBB7_2 +; THUMB2-NEXT: @ %bb.3: @ %while.cond.while.end_crit_edge +; THUMB2-NEXT: ldr r0, [r4] +; THUMB2-NEXT: .LBB7_4: @ %while.end +; THUMB2-NEXT: cmp r0, #1 +; THUMB2-NEXT: bgt .LBB7_7 +; THUMB2-NEXT: @ %bb.5: @ %land.lhs.true +; THUMB2-NEXT: movw r0, :lower16:d +; THUMB2-NEXT: movw r1, :lower16:b +; THUMB2-NEXT: movt r0, :upper16:d +; THUMB2-NEXT: movt r1, :upper16:b +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: ldr r1, [r1] +; THUMB2-NEXT: cmp r1, r0 +; THUMB2-NEXT: bne .LBB7_7 +; THUMB2-NEXT: @ %bb.6: +; THUMB2-NEXT: movs r0, #123 +; THUMB2-NEXT: pop {r4, r5, r7, pc} +; THUMB2-NEXT: .LBB7_7: @ %if.end +; THUMB2-NEXT: movs r0, #0 +; THUMB2-NEXT: pop {r4, r5, r7, pc} +; +; THUMBV8-LABEL: do_nothing_if_resultant_opcodes_would_differ: +; THUMBV8: @ %bb.0: @ %entry +; THUMBV8-NEXT: push {r4, r5, r7, lr} +; THUMBV8-NEXT: movw r4, :lower16:a +; THUMBV8-NEXT: movt r4, :upper16:a +; THUMBV8-NEXT: ldr r0, [r4] +; THUMBV8-NEXT: cmn.w r0, #2 +; THUMBV8-NEXT: bgt .LBB7_4 +; THUMBV8-NEXT: @ %bb.1: @ %while.body.preheader +; THUMBV8-NEXT: subs r5, r0, #1 +; THUMBV8-NEXT: .LBB7_2: @ %while.body +; THUMBV8-NEXT: @ =>This Inner Loop Header: Depth=1 +; THUMBV8-NEXT: bl do_something +; THUMBV8-NEXT: adds r5, #1 +; THUMBV8-NEXT: bmi .LBB7_2 +; THUMBV8-NEXT: @ %bb.3: @ %while.cond.while.end_crit_edge +; THUMBV8-NEXT: ldr r0, [r4] +; THUMBV8-NEXT: .LBB7_4: @ %while.end +; THUMBV8-NEXT: cmp r0, #1 +; THUMBV8-NEXT: bgt .LBB7_7 +; THUMBV8-NEXT: @ %bb.5: @ %land.lhs.true +; THUMBV8-NEXT: movw r0, :lower16:d +; THUMBV8-NEXT: movw r1, :lower16:b +; THUMBV8-NEXT: movt r0, :upper16:d +; THUMBV8-NEXT: movt r1, :upper16:b +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: ldr r1, [r1] +; THUMBV8-NEXT: cmp r1, r0 +; THUMBV8-NEXT: bne .LBB7_7 +; THUMBV8-NEXT: @ %bb.6: +; THUMBV8-NEXT: movs r0, #123 +; THUMBV8-NEXT: pop {r4, r5, r7, pc} +; THUMBV8-NEXT: .LBB7_7: @ %if.end +; THUMBV8-NEXT: movs r0, #0 +; THUMBV8-NEXT: pop {r4, r5, r7, pc} +entry: + %0 = load i32, ptr @a, align 4 + %cmp4 = icmp slt i32 %0, -1 + br i1 %cmp4, label %while.body.preheader, label %while.end + +while.body.preheader: ; preds = %entry + br label %while.body + +while.body: ; preds = %while.body, %while.body.preheader + %i.05 = phi i32 [ %inc, %while.body ], [ %0, %while.body.preheader ] + tail call void @do_something() #2 + %inc = add nsw i32 %i.05, 1 + %cmp = icmp slt i32 %i.05, 0 + br i1 %cmp, label %while.body, label %while.cond.while.end_crit_edge + +while.cond.while.end_crit_edge: ; preds = %while.body + %.pre = load i32, ptr @a, align 4 + br label %while.end + +while.end: ; preds = %while.cond.while.end_crit_edge, %entry + %1 = phi i32 [ %.pre, %while.cond.while.end_crit_edge ], [ %0, %entry ] + %cmp1 = icmp slt i32 %1, 2 + br i1 %cmp1, label %land.lhs.true, label %if.end + +land.lhs.true: ; preds = %while.end + %2 = load i32, ptr @b, align 4 + %3 = load i32, ptr @d, align 4 + %cmp2 = icmp eq i32 %2, %3 + br i1 %cmp2, label %return, label %if.end + +if.end: ; preds = %land.lhs.true, %while.end + br label %return + +return: ; preds = %if.end, %land.lhs.true + %retval.0 = phi i32 [ 0, %if.end ], [ 123, %land.lhs.true ] + ret i32 %retval.0 +} + +define i32 @do_nothing_if_compares_can_not_be_adjusted_to_each_other() #0 { +; ARM-LABEL: do_nothing_if_compares_can_not_be_adjusted_to_each_other: +; ARM: @ %bb.0: @ %entry +; ARM-NEXT: push {r4, lr} +; ARM-NEXT: movw r0, :lower16:a +; ARM-NEXT: movt r0, :upper16:a +; ARM-NEXT: ldr r0, [r0] +; ARM-NEXT: cmp r0, #0 +; ARM-NEXT: bgt .LBB8_3 +; ARM-NEXT: @ %bb.1: @ %while.body.preheader +; ARM-NEXT: sub r4, r0, #1 +; ARM-NEXT: .LBB8_2: @ %while.body +; ARM-NEXT: @ =>This Inner Loop Header: Depth=1 +; ARM-NEXT: bl do_something +; ARM-NEXT: adds r4, r4, #1 +; ARM-NEXT: bmi .LBB8_2 +; ARM-NEXT: .LBB8_3: @ %while.end +; ARM-NEXT: movw r0, :lower16:c +; ARM-NEXT: movt r0, :upper16:c +; ARM-NEXT: ldr r0, [r0] +; ARM-NEXT: cmn r0, #2 +; ARM-NEXT: blt .LBB8_5 +; ARM-NEXT: @ %bb.4: @ %land.lhs.true +; ARM-NEXT: movw r0, :lower16:d +; ARM-NEXT: movt r0, :upper16:d +; ARM-NEXT: ldr r1, [r0] +; ARM-NEXT: movw r0, :lower16:b +; ARM-NEXT: movt r0, :upper16:b +; ARM-NEXT: ldr r2, [r0] +; ARM-NEXT: mov r0, #123 +; ARM-NEXT: cmp r2, r1 +; ARM-NEXT: movne r0, #0 +; ARM-NEXT: pop {r4, pc} +; ARM-NEXT: .LBB8_5: @ %if.end +; ARM-NEXT: mov r0, #0 +; ARM-NEXT: pop {r4, pc} +; +; THUMB-LABEL: do_nothing_if_compares_can_not_be_adjusted_to_each_other: +; THUMB: @ %bb.0: @ %entry +; THUMB-NEXT: push {r4, lr} +; THUMB-NEXT: ldr r0, .LCPI8_0 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: cmp r0, #0 +; THUMB-NEXT: bgt .LBB8_3 +; THUMB-NEXT: @ %bb.1: @ %while.body.preheader +; THUMB-NEXT: subs r4, r0, #1 +; THUMB-NEXT: .LBB8_2: @ %while.body +; THUMB-NEXT: @ =>This Inner Loop Header: Depth=1 +; THUMB-NEXT: bl do_something +; THUMB-NEXT: adds r4, r4, #1 +; THUMB-NEXT: bmi .LBB8_2 +; THUMB-NEXT: .LBB8_3: @ %while.end +; THUMB-NEXT: movs r0, #1 +; THUMB-NEXT: mvns r0, r0 +; THUMB-NEXT: ldr r1, .LCPI8_1 +; THUMB-NEXT: ldr r1, [r1] +; THUMB-NEXT: cmp r1, r0 +; THUMB-NEXT: blt .LBB8_6 +; THUMB-NEXT: @ %bb.4: @ %land.lhs.true +; THUMB-NEXT: ldr r0, .LCPI8_2 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: ldr r1, .LCPI8_3 +; THUMB-NEXT: ldr r1, [r1] +; THUMB-NEXT: cmp r1, r0 +; THUMB-NEXT: bne .LBB8_6 +; THUMB-NEXT: @ %bb.5: +; THUMB-NEXT: movs r0, #123 +; THUMB-NEXT: pop {r4, pc} +; THUMB-NEXT: .LBB8_6: @ %if.end +; THUMB-NEXT: movs r0, #0 +; THUMB-NEXT: pop {r4, pc} +; THUMB-NEXT: .p2align 2 +; THUMB-NEXT: @ %bb.7: +; THUMB-NEXT: .LCPI8_0: +; THUMB-NEXT: .long a +; THUMB-NEXT: .LCPI8_1: +; THUMB-NEXT: .long c +; THUMB-NEXT: .LCPI8_2: +; THUMB-NEXT: .long d +; THUMB-NEXT: .LCPI8_3: +; THUMB-NEXT: .long b +; +; THUMB2-LABEL: do_nothing_if_compares_can_not_be_adjusted_to_each_other: +; THUMB2: @ %bb.0: @ %entry +; THUMB2-NEXT: push {r4, lr} +; THUMB2-NEXT: movw r0, :lower16:a +; THUMB2-NEXT: movt r0, :upper16:a +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: cmp r0, #0 +; THUMB2-NEXT: bgt .LBB8_3 +; THUMB2-NEXT: @ %bb.1: @ %while.body.preheader +; THUMB2-NEXT: subs r4, r0, #1 +; THUMB2-NEXT: .LBB8_2: @ %while.body +; THUMB2-NEXT: @ =>This Inner Loop Header: Depth=1 +; THUMB2-NEXT: bl do_something +; THUMB2-NEXT: adds r4, #1 +; THUMB2-NEXT: bmi .LBB8_2 +; THUMB2-NEXT: .LBB8_3: @ %while.end +; THUMB2-NEXT: movw r0, :lower16:c +; THUMB2-NEXT: movt r0, :upper16:c +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: cmn.w r0, #2 +; THUMB2-NEXT: blt .LBB8_5 +; THUMB2-NEXT: @ %bb.4: @ %land.lhs.true +; THUMB2-NEXT: movw r0, :lower16:d +; THUMB2-NEXT: movw r1, :lower16:b +; THUMB2-NEXT: movt r0, :upper16:d +; THUMB2-NEXT: movt r1, :upper16:b +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: ldr r1, [r1] +; THUMB2-NEXT: cmp r1, r0 +; THUMB2-NEXT: itt eq +; THUMB2-NEXT: moveq r0, #123 +; THUMB2-NEXT: popeq {r4, pc} +; THUMB2-NEXT: .LBB8_5: @ %if.end +; THUMB2-NEXT: movs r0, #0 +; THUMB2-NEXT: pop {r4, pc} +; +; THUMBV8-LABEL: do_nothing_if_compares_can_not_be_adjusted_to_each_other: +; THUMBV8: @ %bb.0: @ %entry +; THUMBV8-NEXT: push {r4, lr} +; THUMBV8-NEXT: movw r0, :lower16:a +; THUMBV8-NEXT: movt r0, :upper16:a +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: cmp r0, #0 +; THUMBV8-NEXT: bgt .LBB8_3 +; THUMBV8-NEXT: @ %bb.1: @ %while.body.preheader +; THUMBV8-NEXT: subs r4, r0, #1 +; THUMBV8-NEXT: .LBB8_2: @ %while.body +; THUMBV8-NEXT: @ =>This Inner Loop Header: Depth=1 +; THUMBV8-NEXT: bl do_something +; THUMBV8-NEXT: adds r4, #1 +; THUMBV8-NEXT: bmi .LBB8_2 +; THUMBV8-NEXT: .LBB8_3: @ %while.end +; THUMBV8-NEXT: movw r0, :lower16:c +; THUMBV8-NEXT: movt r0, :upper16:c +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: cmn.w r0, #2 +; THUMBV8-NEXT: blt .LBB8_5 +; THUMBV8-NEXT: @ %bb.4: @ %land.lhs.true +; THUMBV8-NEXT: movw r0, :lower16:d +; THUMBV8-NEXT: movw r1, :lower16:b +; THUMBV8-NEXT: movt r0, :upper16:d +; THUMBV8-NEXT: movt r1, :upper16:b +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: ldr r1, [r1] +; THUMBV8-NEXT: cmp r1, r0 +; THUMBV8-NEXT: itt eq +; THUMBV8-NEXT: moveq r0, #123 +; THUMBV8-NEXT: popeq {r4, pc} +; THUMBV8-NEXT: .LBB8_5: @ %if.end +; THUMBV8-NEXT: movs r0, #0 +; THUMBV8-NEXT: pop {r4, pc} +entry: + %0 = load i32, ptr @a, align 4 + %cmp4 = icmp slt i32 %0, 1 + br i1 %cmp4, label %while.body.preheader, label %while.end + +while.body.preheader: ; preds = %entry + br label %while.body + +while.body: ; preds = %while.body, %while.body.preheader + %i.05 = phi i32 [ %inc, %while.body ], [ %0, %while.body.preheader ] + tail call void @do_something() #2 + %inc = add nsw i32 %i.05, 1 + %cmp = icmp slt i32 %i.05, 0 + br i1 %cmp, label %while.body, label %while.end.loopexit + +while.end.loopexit: ; preds = %while.body + br label %while.end + +while.end: ; preds = %while.end.loopexit, %entry + %1 = load i32, ptr @c, align 4 + %cmp1 = icmp sgt i32 %1, -3 + br i1 %cmp1, label %land.lhs.true, label %if.end + +land.lhs.true: ; preds = %while.end + %2 = load i32, ptr @b, align 4 + %3 = load i32, ptr @d, align 4 + %cmp2 = icmp eq i32 %2, %3 + br i1 %cmp2, label %return, label %if.end + +if.end: ; preds = %land.lhs.true, %while.end + br label %return + +return: ; preds = %if.end, %land.lhs.true + %retval.0 = phi i32 [ 0, %if.end ], [ 123, %land.lhs.true ] + ret i32 %retval.0 +} + +define i32 @combine_gt_ge_sel(i32 %v, ptr %p) #0 { +; ARM-LABEL: combine_gt_ge_sel: +; ARM: @ %bb.0: @ %entry +; ARM-NEXT: movw r2, :lower16:a +; ARM-NEXT: movt r2, :upper16:a +; ARM-NEXT: ldr r2, [r2] +; ARM-NEXT: cmp r2, #0 +; ARM-NEXT: movle r0, #0 +; ARM-NEXT: str r0, [r1] +; ARM-NEXT: ble .LBB9_3 +; ARM-NEXT: @ %bb.1: @ %lor.lhs.false +; ARM-NEXT: cmp r2, #2 +; ARM-NEXT: bge .LBB9_4 +; ARM-NEXT: @ %bb.2: @ %if.end +; ARM-NEXT: mov r0, #0 +; ARM-NEXT: bx lr +; ARM-NEXT: .LBB9_3: @ %land.lhs.true +; ARM-NEXT: movw r0, :lower16:c +; ARM-NEXT: movt r0, :upper16:c +; ARM-NEXT: ldr r1, [r0] +; ARM-NEXT: movw r0, :lower16:b +; ARM-NEXT: movt r0, :upper16:b +; ARM-NEXT: ldr r2, [r0] +; ARM-NEXT: mov r0, #1 +; ARM-NEXT: cmp r2, r1 +; ARM-NEXT: bxeq lr +; ARM-NEXT: .LBB9_4: @ %land.lhs.true3 +; ARM-NEXT: movw r0, :lower16:d +; ARM-NEXT: movt r0, :upper16:d +; ARM-NEXT: ldr r1, [r0] +; ARM-NEXT: movw r0, :lower16:b +; ARM-NEXT: movt r0, :upper16:b +; ARM-NEXT: ldr r2, [r0] +; ARM-NEXT: mov r0, #1 +; ARM-NEXT: cmp r2, r1 +; ARM-NEXT: movne r0, #0 +; ARM-NEXT: bx lr +; +; THUMB-LABEL: combine_gt_ge_sel: +; THUMB: @ %bb.0: @ %entry +; THUMB-NEXT: ldr r2, .LCPI9_0 +; THUMB-NEXT: ldr r2, [r2] +; THUMB-NEXT: movs r3, #0 +; THUMB-NEXT: cmp r2, #0 +; THUMB-NEXT: bgt .LBB9_2 +; THUMB-NEXT: @ %bb.1: @ %entry +; THUMB-NEXT: mov r0, r3 +; THUMB-NEXT: .LBB9_2: @ %entry +; THUMB-NEXT: str r0, [r1] +; THUMB-NEXT: ble .LBB9_4 +; THUMB-NEXT: @ %bb.3: @ %lor.lhs.false +; THUMB-NEXT: cmp r2, #2 +; THUMB-NEXT: bge .LBB9_6 +; THUMB-NEXT: b .LBB9_8 +; THUMB-NEXT: .LBB9_4: @ %land.lhs.true +; THUMB-NEXT: ldr r0, .LCPI9_1 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: ldr r1, .LCPI9_2 +; THUMB-NEXT: ldr r1, [r1] +; THUMB-NEXT: cmp r1, r0 +; THUMB-NEXT: bne .LBB9_6 +; THUMB-NEXT: @ %bb.5: +; THUMB-NEXT: movs r0, #1 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .LBB9_6: @ %land.lhs.true3 +; THUMB-NEXT: ldr r0, .LCPI9_3 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: ldr r1, .LCPI9_2 +; THUMB-NEXT: ldr r1, [r1] +; THUMB-NEXT: cmp r1, r0 +; THUMB-NEXT: bne .LBB9_8 +; THUMB-NEXT: @ %bb.7: +; THUMB-NEXT: movs r0, #1 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .LBB9_8: @ %if.end +; THUMB-NEXT: movs r0, #0 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .p2align 2 +; THUMB-NEXT: @ %bb.9: +; THUMB-NEXT: .LCPI9_0: +; THUMB-NEXT: .long a +; THUMB-NEXT: .LCPI9_1: +; THUMB-NEXT: .long c +; THUMB-NEXT: .LCPI9_2: +; THUMB-NEXT: .long b +; THUMB-NEXT: .LCPI9_3: +; THUMB-NEXT: .long d +; +; THUMB2-LABEL: combine_gt_ge_sel: +; THUMB2: @ %bb.0: @ %entry +; THUMB2-NEXT: movw r2, :lower16:a +; THUMB2-NEXT: movt r2, :upper16:a +; THUMB2-NEXT: ldr r2, [r2] +; THUMB2-NEXT: cmp r2, #0 +; THUMB2-NEXT: it le +; THUMB2-NEXT: movle r0, #0 +; THUMB2-NEXT: str r0, [r1] +; THUMB2-NEXT: ble .LBB9_2 +; THUMB2-NEXT: @ %bb.1: @ %lor.lhs.false +; THUMB2-NEXT: cmp r2, #2 +; THUMB2-NEXT: bge .LBB9_3 +; THUMB2-NEXT: b .LBB9_4 +; THUMB2-NEXT: .LBB9_2: @ %land.lhs.true +; THUMB2-NEXT: movw r0, :lower16:c +; THUMB2-NEXT: movw r1, :lower16:b +; THUMB2-NEXT: movt r0, :upper16:c +; THUMB2-NEXT: movt r1, :upper16:b +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: ldr r1, [r1] +; THUMB2-NEXT: cmp r1, r0 +; THUMB2-NEXT: itt eq +; THUMB2-NEXT: moveq r0, #1 +; THUMB2-NEXT: bxeq lr +; THUMB2-NEXT: .LBB9_3: @ %land.lhs.true3 +; THUMB2-NEXT: movw r0, :lower16:d +; THUMB2-NEXT: movw r1, :lower16:b +; THUMB2-NEXT: movt r0, :upper16:d +; THUMB2-NEXT: movt r1, :upper16:b +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: ldr r1, [r1] +; THUMB2-NEXT: cmp r1, r0 +; THUMB2-NEXT: itt eq +; THUMB2-NEXT: moveq r0, #1 +; THUMB2-NEXT: bxeq lr +; THUMB2-NEXT: .LBB9_4: @ %if.end +; THUMB2-NEXT: movs r0, #0 +; THUMB2-NEXT: bx lr +; +; THUMBV8-LABEL: combine_gt_ge_sel: +; THUMBV8: @ %bb.0: @ %entry +; THUMBV8-NEXT: movw r2, :lower16:a +; THUMBV8-NEXT: movt r2, :upper16:a +; THUMBV8-NEXT: ldr r2, [r2] +; THUMBV8-NEXT: cmp r2, #0 +; THUMBV8-NEXT: it le +; THUMBV8-NEXT: movle r0, #0 +; THUMBV8-NEXT: str r0, [r1] +; THUMBV8-NEXT: ble .LBB9_2 +; THUMBV8-NEXT: @ %bb.1: @ %lor.lhs.false +; THUMBV8-NEXT: cmp r2, #2 +; THUMBV8-NEXT: bge .LBB9_3 +; THUMBV8-NEXT: b .LBB9_4 +; THUMBV8-NEXT: .LBB9_2: @ %land.lhs.true +; THUMBV8-NEXT: movw r0, :lower16:c +; THUMBV8-NEXT: movw r1, :lower16:b +; THUMBV8-NEXT: movt r0, :upper16:c +; THUMBV8-NEXT: movt r1, :upper16:b +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: ldr r1, [r1] +; THUMBV8-NEXT: cmp r1, r0 +; THUMBV8-NEXT: itt eq +; THUMBV8-NEXT: moveq r0, #1 +; THUMBV8-NEXT: bxeq lr +; THUMBV8-NEXT: .LBB9_3: @ %land.lhs.true3 +; THUMBV8-NEXT: movw r0, :lower16:d +; THUMBV8-NEXT: movw r1, :lower16:b +; THUMBV8-NEXT: movt r0, :upper16:d +; THUMBV8-NEXT: movt r1, :upper16:b +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: ldr r1, [r1] +; THUMBV8-NEXT: cmp r1, r0 +; THUMBV8-NEXT: itt eq +; THUMBV8-NEXT: moveq r0, #1 +; THUMBV8-NEXT: bxeq lr +; THUMBV8-NEXT: .LBB9_4: @ %if.end +; THUMBV8-NEXT: movs r0, #0 +; THUMBV8-NEXT: bx lr +entry: + %0 = load i32, ptr @a, align 4 + %cmp = icmp sgt i32 %0, 0 + %m = select i1 %cmp, i32 %v, i32 0 + store i32 %m, ptr %p + br i1 %cmp, label %lor.lhs.false, label %land.lhs.true + +land.lhs.true: ; preds = %entry + %1 = load i32, ptr @b, align 4 + %2 = load i32, ptr @c, align 4 + %cmp1 = icmp eq i32 %1, %2 + br i1 %cmp1, label %return, label %land.lhs.true3 + +lor.lhs.false: ; preds = %entry + %cmp2 = icmp sgt i32 %0, 1 + br i1 %cmp2, label %land.lhs.true3, label %if.end + +land.lhs.true3: ; preds = %lor.lhs.false, %land.lhs.true + %3 = load i32, ptr @b, align 4 + %4 = load i32, ptr @d, align 4 + %cmp4 = icmp eq i32 %3, %4 + br i1 %cmp4, label %return, label %if.end + +if.end: ; preds = %land.lhs.true3, %lor.lhs.false + br label %return + +return: ; preds = %if.end, %land.lhs.true3, %land.lhs.true + %retval.0 = phi i32 [ 0, %if.end ], [ 1, %land.lhs.true3 ], [ 1, %land.lhs.true ] + ret i32 %retval.0 +} + +; (a > 10 && b == c) || (a >= 10 && b == d) +define i32 @combine_ugt_uge_10() #0 { +; ARM-LABEL: combine_ugt_uge_10: +; ARM: @ %bb.0: @ %entry +; ARM-NEXT: movw r0, :lower16:a +; ARM-NEXT: movw r1, :lower16:b +; ARM-NEXT: movt r0, :upper16:a +; ARM-NEXT: movt r1, :upper16:b +; ARM-NEXT: ldr r0, [r0] +; ARM-NEXT: cmp r0, #10 +; ARM-NEXT: bls .LBB10_2 +; ARM-NEXT: @ %bb.1: @ %land.lhs.true +; ARM-NEXT: movw r0, :lower16:c +; ARM-NEXT: ldr r3, [r1] +; ARM-NEXT: movt r0, :upper16:c +; ARM-NEXT: ldr r2, [r0] +; ARM-NEXT: mov r0, #1 +; ARM-NEXT: cmp r3, r2 +; ARM-NEXT: bxeq lr +; ARM-NEXT: b .LBB10_3 +; ARM-NEXT: .LBB10_2: @ %lor.lhs.false +; ARM-NEXT: blo .LBB10_4 +; ARM-NEXT: .LBB10_3: @ %land.lhs.true3 +; ARM-NEXT: movw r0, :lower16:d +; ARM-NEXT: ldr r1, [r1] +; ARM-NEXT: movt r0, :upper16:d +; ARM-NEXT: ldr r2, [r0] +; ARM-NEXT: mov r0, #1 +; ARM-NEXT: cmp r1, r2 +; ARM-NEXT: movne r0, #0 +; ARM-NEXT: bx lr +; ARM-NEXT: .LBB10_4: @ %if.end +; ARM-NEXT: mov r0, #0 +; ARM-NEXT: bx lr +; +; THUMB-LABEL: combine_ugt_uge_10: +; THUMB: @ %bb.0: @ %entry +; THUMB-NEXT: ldr r0, .LCPI10_0 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: cmp r0, #10 +; THUMB-NEXT: bls .LBB10_3 +; THUMB-NEXT: @ %bb.1: @ %land.lhs.true +; THUMB-NEXT: ldr r0, .LCPI10_1 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: ldr r1, .LCPI10_2 +; THUMB-NEXT: ldr r1, [r1] +; THUMB-NEXT: cmp r1, r0 +; THUMB-NEXT: bne .LBB10_4 +; THUMB-NEXT: @ %bb.2: +; THUMB-NEXT: movs r0, #1 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .LBB10_3: @ %lor.lhs.false +; THUMB-NEXT: blo .LBB10_6 +; THUMB-NEXT: .LBB10_4: @ %land.lhs.true3 +; THUMB-NEXT: ldr r0, .LCPI10_3 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: ldr r1, .LCPI10_2 +; THUMB-NEXT: ldr r1, [r1] +; THUMB-NEXT: cmp r1, r0 +; THUMB-NEXT: bne .LBB10_6 +; THUMB-NEXT: @ %bb.5: +; THUMB-NEXT: movs r0, #1 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .LBB10_6: @ %if.end +; THUMB-NEXT: movs r0, #0 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .p2align 2 +; THUMB-NEXT: @ %bb.7: +; THUMB-NEXT: .LCPI10_0: +; THUMB-NEXT: .long a +; THUMB-NEXT: .LCPI10_1: +; THUMB-NEXT: .long c +; THUMB-NEXT: .LCPI10_2: +; THUMB-NEXT: .long b +; THUMB-NEXT: .LCPI10_3: +; THUMB-NEXT: .long d +; +; THUMB2-LABEL: combine_ugt_uge_10: +; THUMB2: @ %bb.0: @ %entry +; THUMB2-NEXT: movw r0, :lower16:a +; THUMB2-NEXT: movt r0, :upper16:a +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: cmp r0, #10 +; THUMB2-NEXT: movw r0, :lower16:b +; THUMB2-NEXT: movt r0, :upper16:b +; THUMB2-NEXT: bls .LBB10_2 +; THUMB2-NEXT: @ %bb.1: @ %land.lhs.true +; THUMB2-NEXT: movw r1, :lower16:c +; THUMB2-NEXT: ldr r2, [r0] +; THUMB2-NEXT: movt r1, :upper16:c +; THUMB2-NEXT: ldr r1, [r1] +; THUMB2-NEXT: cmp r2, r1 +; THUMB2-NEXT: itt eq +; THUMB2-NEXT: moveq r0, #1 +; THUMB2-NEXT: bxeq lr +; THUMB2-NEXT: b .LBB10_3 +; THUMB2-NEXT: .LBB10_2: @ %lor.lhs.false +; THUMB2-NEXT: blo .LBB10_4 +; THUMB2-NEXT: .LBB10_3: @ %land.lhs.true3 +; THUMB2-NEXT: movw r1, :lower16:d +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: movt r1, :upper16:d +; THUMB2-NEXT: ldr r1, [r1] +; THUMB2-NEXT: cmp r0, r1 +; THUMB2-NEXT: itt eq +; THUMB2-NEXT: moveq r0, #1 +; THUMB2-NEXT: bxeq lr +; THUMB2-NEXT: .LBB10_4: @ %if.end +; THUMB2-NEXT: movs r0, #0 +; THUMB2-NEXT: bx lr +; +; THUMBV8-LABEL: combine_ugt_uge_10: +; THUMBV8: @ %bb.0: @ %entry +; THUMBV8-NEXT: movw r0, :lower16:a +; THUMBV8-NEXT: movt r0, :upper16:a +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: cmp r0, #10 +; THUMBV8-NEXT: movw r0, :lower16:b +; THUMBV8-NEXT: movt r0, :upper16:b +; THUMBV8-NEXT: bls .LBB10_2 +; THUMBV8-NEXT: @ %bb.1: @ %land.lhs.true +; THUMBV8-NEXT: movw r1, :lower16:c +; THUMBV8-NEXT: ldr r2, [r0] +; THUMBV8-NEXT: movt r1, :upper16:c +; THUMBV8-NEXT: ldr r1, [r1] +; THUMBV8-NEXT: cmp r2, r1 +; THUMBV8-NEXT: itt eq +; THUMBV8-NEXT: moveq r0, #1 +; THUMBV8-NEXT: bxeq lr +; THUMBV8-NEXT: b .LBB10_3 +; THUMBV8-NEXT: .LBB10_2: @ %lor.lhs.false +; THUMBV8-NEXT: blo .LBB10_4 +; THUMBV8-NEXT: .LBB10_3: @ %land.lhs.true3 +; THUMBV8-NEXT: movw r1, :lower16:d +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: movt r1, :upper16:d +; THUMBV8-NEXT: ldr r1, [r1] +; THUMBV8-NEXT: cmp r0, r1 +; THUMBV8-NEXT: itt eq +; THUMBV8-NEXT: moveq r0, #1 +; THUMBV8-NEXT: bxeq lr +; THUMBV8-NEXT: .LBB10_4: @ %if.end +; THUMBV8-NEXT: movs r0, #0 +; THUMBV8-NEXT: bx lr +entry: + %0 = load i32, ptr @a, align 4 + %cmp = icmp ugt i32 %0, 10 + br i1 %cmp, label %land.lhs.true, label %lor.lhs.false + +land.lhs.true: ; preds = %entry + %1 = load i32, ptr @b, align 4 + %2 = load i32, ptr @c, align 4 + %cmp1 = icmp eq i32 %1, %2 + br i1 %cmp1, label %return, label %land.lhs.true3 + +lor.lhs.false: ; preds = %entry + %cmp2 = icmp ugt i32 %0, 9 + br i1 %cmp2, label %land.lhs.true3, label %if.end + +land.lhs.true3: ; preds = %lor.lhs.false, %land.lhs.true + %3 = load i32, ptr @b, align 4 + %4 = load i32, ptr @d, align 4 + %cmp4 = icmp eq i32 %3, %4 + br i1 %cmp4, label %return, label %if.end + +if.end: ; preds = %land.lhs.true3, %lor.lhs.false + br label %return + +return: ; preds = %if.end, %land.lhs.true3, %land.lhs.true + %retval.0 = phi i32 [ 0, %if.end ], [ 1, %land.lhs.true3 ], [ 1, %land.lhs.true ] + ret i32 %retval.0 +} + +; (a > 5 && b == c) || (a < 5 && b == d) +define i32 @combine_ugt_ult_5() #0 { +; ARM-LABEL: combine_ugt_ult_5: +; ARM: @ %bb.0: @ %entry +; ARM-NEXT: movw r0, :lower16:a +; ARM-NEXT: movt r0, :upper16:a +; ARM-NEXT: ldr r0, [r0] +; ARM-NEXT: cmp r0, #5 +; ARM-NEXT: bls .LBB11_2 +; ARM-NEXT: @ %bb.1: @ %land.lhs.true +; ARM-NEXT: movw r0, :lower16:c +; ARM-NEXT: movt r0, :upper16:c +; ARM-NEXT: b .LBB11_4 +; ARM-NEXT: .LBB11_2: @ %lor.lhs.false +; ARM-NEXT: bhs .LBB11_5 +; ARM-NEXT: @ %bb.3: @ %land.lhs.true3 +; ARM-NEXT: movw r0, :lower16:d +; ARM-NEXT: movt r0, :upper16:d +; ARM-NEXT: .LBB11_4: @ %land.lhs.true3 +; ARM-NEXT: ldr r1, [r0] +; ARM-NEXT: movw r0, :lower16:b +; ARM-NEXT: movt r0, :upper16:b +; ARM-NEXT: ldr r2, [r0] +; ARM-NEXT: mov r0, #1 +; ARM-NEXT: cmp r2, r1 +; ARM-NEXT: movne r0, #0 +; ARM-NEXT: bx lr +; ARM-NEXT: .LBB11_5: @ %if.end +; ARM-NEXT: mov r0, #0 +; ARM-NEXT: bx lr +; +; THUMB-LABEL: combine_ugt_ult_5: +; THUMB: @ %bb.0: @ %entry +; THUMB-NEXT: ldr r0, .LCPI11_0 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: cmp r0, #5 +; THUMB-NEXT: bls .LBB11_3 +; THUMB-NEXT: @ %bb.1: @ %land.lhs.true +; THUMB-NEXT: ldr r0, .LCPI11_3 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: ldr r1, .LCPI11_2 +; THUMB-NEXT: ldr r1, [r1] +; THUMB-NEXT: cmp r1, r0 +; THUMB-NEXT: bne .LBB11_6 +; THUMB-NEXT: @ %bb.2: +; THUMB-NEXT: movs r0, #1 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .LBB11_3: @ %lor.lhs.false +; THUMB-NEXT: bhs .LBB11_6 +; THUMB-NEXT: @ %bb.4: @ %land.lhs.true3 +; THUMB-NEXT: ldr r0, .LCPI11_1 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: ldr r1, .LCPI11_2 +; THUMB-NEXT: ldr r1, [r1] +; THUMB-NEXT: cmp r1, r0 +; THUMB-NEXT: bne .LBB11_6 +; THUMB-NEXT: @ %bb.5: +; THUMB-NEXT: movs r0, #1 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .LBB11_6: @ %if.end +; THUMB-NEXT: movs r0, #0 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .p2align 2 +; THUMB-NEXT: @ %bb.7: +; THUMB-NEXT: .LCPI11_0: +; THUMB-NEXT: .long a +; THUMB-NEXT: .LCPI11_1: +; THUMB-NEXT: .long d +; THUMB-NEXT: .LCPI11_2: +; THUMB-NEXT: .long b +; THUMB-NEXT: .LCPI11_3: +; THUMB-NEXT: .long c +; +; THUMB2-LABEL: combine_ugt_ult_5: +; THUMB2: @ %bb.0: @ %entry +; THUMB2-NEXT: movw r0, :lower16:a +; THUMB2-NEXT: movt r0, :upper16:a +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: cmp r0, #5 +; THUMB2-NEXT: bls .LBB11_2 +; THUMB2-NEXT: @ %bb.1: @ %land.lhs.true +; THUMB2-NEXT: movw r0, :lower16:c +; THUMB2-NEXT: movw r1, :lower16:b +; THUMB2-NEXT: movt r0, :upper16:c +; THUMB2-NEXT: movt r1, :upper16:b +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: ldr r1, [r1] +; THUMB2-NEXT: cmp r1, r0 +; THUMB2-NEXT: itt eq +; THUMB2-NEXT: moveq r0, #1 +; THUMB2-NEXT: bxeq lr +; THUMB2-NEXT: b .LBB11_4 +; THUMB2-NEXT: .LBB11_2: @ %lor.lhs.false +; THUMB2-NEXT: bhs .LBB11_4 +; THUMB2-NEXT: @ %bb.3: @ %land.lhs.true3 +; THUMB2-NEXT: movw r0, :lower16:d +; THUMB2-NEXT: movw r1, :lower16:b +; THUMB2-NEXT: movt r0, :upper16:d +; THUMB2-NEXT: movt r1, :upper16:b +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: ldr r1, [r1] +; THUMB2-NEXT: cmp r1, r0 +; THUMB2-NEXT: itt eq +; THUMB2-NEXT: moveq r0, #1 +; THUMB2-NEXT: bxeq lr +; THUMB2-NEXT: .LBB11_4: @ %if.end +; THUMB2-NEXT: movs r0, #0 +; THUMB2-NEXT: bx lr +; +; THUMBV8-LABEL: combine_ugt_ult_5: +; THUMBV8: @ %bb.0: @ %entry +; THUMBV8-NEXT: movw r0, :lower16:a +; THUMBV8-NEXT: movt r0, :upper16:a +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: cmp r0, #5 +; THUMBV8-NEXT: bls .LBB11_2 +; THUMBV8-NEXT: @ %bb.1: @ %land.lhs.true +; THUMBV8-NEXT: movw r0, :lower16:c +; THUMBV8-NEXT: movw r1, :lower16:b +; THUMBV8-NEXT: movt r0, :upper16:c +; THUMBV8-NEXT: movt r1, :upper16:b +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: ldr r1, [r1] +; THUMBV8-NEXT: cmp r1, r0 +; THUMBV8-NEXT: itt eq +; THUMBV8-NEXT: moveq r0, #1 +; THUMBV8-NEXT: bxeq lr +; THUMBV8-NEXT: b .LBB11_4 +; THUMBV8-NEXT: .LBB11_2: @ %lor.lhs.false +; THUMBV8-NEXT: bhs .LBB11_4 +; THUMBV8-NEXT: @ %bb.3: @ %land.lhs.true3 +; THUMBV8-NEXT: movw r0, :lower16:d +; THUMBV8-NEXT: movw r1, :lower16:b +; THUMBV8-NEXT: movt r0, :upper16:d +; THUMBV8-NEXT: movt r1, :upper16:b +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: ldr r1, [r1] +; THUMBV8-NEXT: cmp r1, r0 +; THUMBV8-NEXT: itt eq +; THUMBV8-NEXT: moveq r0, #1 +; THUMBV8-NEXT: bxeq lr +; THUMBV8-NEXT: .LBB11_4: @ %if.end +; THUMBV8-NEXT: movs r0, #0 +; THUMBV8-NEXT: bx lr +entry: + %0 = load i32, ptr @a, align 4 + %cmp = icmp ugt i32 %0, 5 + br i1 %cmp, label %land.lhs.true, label %lor.lhs.false + +land.lhs.true: ; preds = %entry + %1 = load i32, ptr @b, align 4 + %2 = load i32, ptr @c, align 4 + %cmp1 = icmp eq i32 %1, %2 + br i1 %cmp1, label %return, label %if.end + +lor.lhs.false: ; preds = %entry + %cmp2 = icmp ult i32 %0, 5 + br i1 %cmp2, label %land.lhs.true3, label %if.end + +land.lhs.true3: ; preds = %lor.lhs.false + %3 = load i32, ptr @b, align 4 + %4 = load i32, ptr @d, align 4 + %cmp4 = icmp eq i32 %3, %4 + br i1 %cmp4, label %return, label %if.end + +if.end: ; preds = %land.lhs.true3, %lor.lhs.false, %land.lhs.true + br label %return + +return: ; preds = %if.end, %land.lhs.true3, %land.lhs.true + %retval.0 = phi i32 [ 0, %if.end ], [ 1, %land.lhs.true3 ], [ 1, %land.lhs.true ] + ret i32 %retval.0 +} + +; (a < 5 && b == c) || (a <= 5 && b == d) +define i32 @combine_ult_uge_5() #0 { +; ARM-LABEL: combine_ult_uge_5: +; ARM: @ %bb.0: @ %entry +; ARM-NEXT: movw r0, :lower16:a +; ARM-NEXT: movw r1, :lower16:b +; ARM-NEXT: movt r0, :upper16:a +; ARM-NEXT: movt r1, :upper16:b +; ARM-NEXT: ldr r0, [r0] +; ARM-NEXT: cmp r0, #5 +; ARM-NEXT: bhs .LBB12_2 +; ARM-NEXT: @ %bb.1: @ %land.lhs.true +; ARM-NEXT: movw r0, :lower16:c +; ARM-NEXT: ldr r3, [r1] +; ARM-NEXT: movt r0, :upper16:c +; ARM-NEXT: ldr r2, [r0] +; ARM-NEXT: mov r0, #1 +; ARM-NEXT: cmp r3, r2 +; ARM-NEXT: bxeq lr +; ARM-NEXT: b .LBB12_3 +; ARM-NEXT: .LBB12_2: @ %lor.lhs.false +; ARM-NEXT: bhi .LBB12_4 +; ARM-NEXT: .LBB12_3: @ %land.lhs.true3 +; ARM-NEXT: movw r0, :lower16:d +; ARM-NEXT: ldr r1, [r1] +; ARM-NEXT: movt r0, :upper16:d +; ARM-NEXT: ldr r2, [r0] +; ARM-NEXT: mov r0, #1 +; ARM-NEXT: cmp r1, r2 +; ARM-NEXT: movne r0, #0 +; ARM-NEXT: bx lr +; ARM-NEXT: .LBB12_4: @ %if.end +; ARM-NEXT: mov r0, #0 +; ARM-NEXT: bx lr +; +; THUMB-LABEL: combine_ult_uge_5: +; THUMB: @ %bb.0: @ %entry +; THUMB-NEXT: ldr r0, .LCPI12_0 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: cmp r0, #5 +; THUMB-NEXT: bhs .LBB12_3 +; THUMB-NEXT: @ %bb.1: @ %land.lhs.true +; THUMB-NEXT: ldr r0, .LCPI12_1 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: ldr r1, .LCPI12_2 +; THUMB-NEXT: ldr r1, [r1] +; THUMB-NEXT: cmp r1, r0 +; THUMB-NEXT: bne .LBB12_4 +; THUMB-NEXT: @ %bb.2: +; THUMB-NEXT: movs r0, #1 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .LBB12_3: @ %lor.lhs.false +; THUMB-NEXT: bhi .LBB12_6 +; THUMB-NEXT: .LBB12_4: @ %land.lhs.true3 +; THUMB-NEXT: ldr r0, .LCPI12_3 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: ldr r1, .LCPI12_2 +; THUMB-NEXT: ldr r1, [r1] +; THUMB-NEXT: cmp r1, r0 +; THUMB-NEXT: bne .LBB12_6 +; THUMB-NEXT: @ %bb.5: +; THUMB-NEXT: movs r0, #1 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .LBB12_6: @ %if.end +; THUMB-NEXT: movs r0, #0 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .p2align 2 +; THUMB-NEXT: @ %bb.7: +; THUMB-NEXT: .LCPI12_0: +; THUMB-NEXT: .long a +; THUMB-NEXT: .LCPI12_1: +; THUMB-NEXT: .long c +; THUMB-NEXT: .LCPI12_2: +; THUMB-NEXT: .long b +; THUMB-NEXT: .LCPI12_3: +; THUMB-NEXT: .long d +; +; THUMB2-LABEL: combine_ult_uge_5: +; THUMB2: @ %bb.0: @ %entry +; THUMB2-NEXT: movw r0, :lower16:a +; THUMB2-NEXT: movt r0, :upper16:a +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: cmp r0, #5 +; THUMB2-NEXT: movw r0, :lower16:b +; THUMB2-NEXT: movt r0, :upper16:b +; THUMB2-NEXT: bhs .LBB12_2 +; THUMB2-NEXT: @ %bb.1: @ %land.lhs.true +; THUMB2-NEXT: movw r1, :lower16:c +; THUMB2-NEXT: ldr r2, [r0] +; THUMB2-NEXT: movt r1, :upper16:c +; THUMB2-NEXT: ldr r1, [r1] +; THUMB2-NEXT: cmp r2, r1 +; THUMB2-NEXT: itt eq +; THUMB2-NEXT: moveq r0, #1 +; THUMB2-NEXT: bxeq lr +; THUMB2-NEXT: b .LBB12_3 +; THUMB2-NEXT: .LBB12_2: @ %lor.lhs.false +; THUMB2-NEXT: bhi .LBB12_4 +; THUMB2-NEXT: .LBB12_3: @ %land.lhs.true3 +; THUMB2-NEXT: movw r1, :lower16:d +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: movt r1, :upper16:d +; THUMB2-NEXT: ldr r1, [r1] +; THUMB2-NEXT: cmp r0, r1 +; THUMB2-NEXT: itt eq +; THUMB2-NEXT: moveq r0, #1 +; THUMB2-NEXT: bxeq lr +; THUMB2-NEXT: .LBB12_4: @ %if.end +; THUMB2-NEXT: movs r0, #0 +; THUMB2-NEXT: bx lr +; +; THUMBV8-LABEL: combine_ult_uge_5: +; THUMBV8: @ %bb.0: @ %entry +; THUMBV8-NEXT: movw r0, :lower16:a +; THUMBV8-NEXT: movt r0, :upper16:a +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: cmp r0, #5 +; THUMBV8-NEXT: movw r0, :lower16:b +; THUMBV8-NEXT: movt r0, :upper16:b +; THUMBV8-NEXT: bhs .LBB12_2 +; THUMBV8-NEXT: @ %bb.1: @ %land.lhs.true +; THUMBV8-NEXT: movw r1, :lower16:c +; THUMBV8-NEXT: ldr r2, [r0] +; THUMBV8-NEXT: movt r1, :upper16:c +; THUMBV8-NEXT: ldr r1, [r1] +; THUMBV8-NEXT: cmp r2, r1 +; THUMBV8-NEXT: itt eq +; THUMBV8-NEXT: moveq r0, #1 +; THUMBV8-NEXT: bxeq lr +; THUMBV8-NEXT: b .LBB12_3 +; THUMBV8-NEXT: .LBB12_2: @ %lor.lhs.false +; THUMBV8-NEXT: bhi .LBB12_4 +; THUMBV8-NEXT: .LBB12_3: @ %land.lhs.true3 +; THUMBV8-NEXT: movw r1, :lower16:d +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: movt r1, :upper16:d +; THUMBV8-NEXT: ldr r1, [r1] +; THUMBV8-NEXT: cmp r0, r1 +; THUMBV8-NEXT: itt eq +; THUMBV8-NEXT: moveq r0, #1 +; THUMBV8-NEXT: bxeq lr +; THUMBV8-NEXT: .LBB12_4: @ %if.end +; THUMBV8-NEXT: movs r0, #0 +; THUMBV8-NEXT: bx lr +entry: + %0 = load i32, ptr @a, align 4 + %cmp = icmp ult i32 %0, 5 + br i1 %cmp, label %land.lhs.true, label %lor.lhs.false + +land.lhs.true: ; preds = %entry + %1 = load i32, ptr @b, align 4 + %2 = load i32, ptr @c, align 4 + %cmp1 = icmp eq i32 %1, %2 + br i1 %cmp1, label %return, label %land.lhs.true3 + +lor.lhs.false: ; preds = %entry + %cmp2 = icmp ult i32 %0, 6 + br i1 %cmp2, label %land.lhs.true3, label %if.end + +land.lhs.true3: ; preds = %lor.lhs.false, %land.lhs.true + %3 = load i32, ptr @b, align 4 + %4 = load i32, ptr @d, align 4 + %cmp4 = icmp eq i32 %3, %4 + br i1 %cmp4, label %return, label %if.end + +if.end: ; preds = %land.lhs.true3, %lor.lhs.false + br label %return + +return: ; preds = %if.end, %land.lhs.true3, %land.lhs.true + %retval.0 = phi i32 [ 0, %if.end ], [ 1, %land.lhs.true3 ], [ 1, %land.lhs.true ] + ret i32 %retval.0 +} + +; (a < 5 && b == c) || (a > 5 && b == d) +define i32 @combine_ult_ugt_5() #0 { +; ARM-LABEL: combine_ult_ugt_5: +; ARM: @ %bb.0: @ %entry +; ARM-NEXT: movw r0, :lower16:a +; ARM-NEXT: movt r0, :upper16:a +; ARM-NEXT: ldr r0, [r0] +; ARM-NEXT: cmp r0, #5 +; ARM-NEXT: bhs .LBB13_2 +; ARM-NEXT: @ %bb.1: @ %land.lhs.true +; ARM-NEXT: movw r0, :lower16:c +; ARM-NEXT: movt r0, :upper16:c +; ARM-NEXT: b .LBB13_4 +; ARM-NEXT: .LBB13_2: @ %lor.lhs.false +; ARM-NEXT: bls .LBB13_5 +; ARM-NEXT: @ %bb.3: @ %land.lhs.true3 +; ARM-NEXT: movw r0, :lower16:d +; ARM-NEXT: movt r0, :upper16:d +; ARM-NEXT: .LBB13_4: @ %land.lhs.true3 +; ARM-NEXT: ldr r1, [r0] +; ARM-NEXT: movw r0, :lower16:b +; ARM-NEXT: movt r0, :upper16:b +; ARM-NEXT: ldr r2, [r0] +; ARM-NEXT: mov r0, #1 +; ARM-NEXT: cmp r2, r1 +; ARM-NEXT: movne r0, #0 +; ARM-NEXT: bx lr +; ARM-NEXT: .LBB13_5: @ %if.end +; ARM-NEXT: mov r0, #0 +; ARM-NEXT: bx lr +; +; THUMB-LABEL: combine_ult_ugt_5: +; THUMB: @ %bb.0: @ %entry +; THUMB-NEXT: ldr r0, .LCPI13_0 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: cmp r0, #5 +; THUMB-NEXT: bhs .LBB13_3 +; THUMB-NEXT: @ %bb.1: @ %land.lhs.true +; THUMB-NEXT: ldr r0, .LCPI13_3 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: ldr r1, .LCPI13_2 +; THUMB-NEXT: ldr r1, [r1] +; THUMB-NEXT: cmp r1, r0 +; THUMB-NEXT: bne .LBB13_6 +; THUMB-NEXT: @ %bb.2: +; THUMB-NEXT: movs r0, #1 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .LBB13_3: @ %lor.lhs.false +; THUMB-NEXT: bls .LBB13_6 +; THUMB-NEXT: @ %bb.4: @ %land.lhs.true3 +; THUMB-NEXT: ldr r0, .LCPI13_1 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: ldr r1, .LCPI13_2 +; THUMB-NEXT: ldr r1, [r1] +; THUMB-NEXT: cmp r1, r0 +; THUMB-NEXT: bne .LBB13_6 +; THUMB-NEXT: @ %bb.5: +; THUMB-NEXT: movs r0, #1 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .LBB13_6: @ %if.end +; THUMB-NEXT: movs r0, #0 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .p2align 2 +; THUMB-NEXT: @ %bb.7: +; THUMB-NEXT: .LCPI13_0: +; THUMB-NEXT: .long a +; THUMB-NEXT: .LCPI13_1: +; THUMB-NEXT: .long d +; THUMB-NEXT: .LCPI13_2: +; THUMB-NEXT: .long b +; THUMB-NEXT: .LCPI13_3: +; THUMB-NEXT: .long c +; +; THUMB2-LABEL: combine_ult_ugt_5: +; THUMB2: @ %bb.0: @ %entry +; THUMB2-NEXT: movw r0, :lower16:a +; THUMB2-NEXT: movt r0, :upper16:a +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: cmp r0, #5 +; THUMB2-NEXT: bhs .LBB13_2 +; THUMB2-NEXT: @ %bb.1: @ %land.lhs.true +; THUMB2-NEXT: movw r0, :lower16:c +; THUMB2-NEXT: movw r1, :lower16:b +; THUMB2-NEXT: movt r0, :upper16:c +; THUMB2-NEXT: movt r1, :upper16:b +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: ldr r1, [r1] +; THUMB2-NEXT: cmp r1, r0 +; THUMB2-NEXT: itt eq +; THUMB2-NEXT: moveq r0, #1 +; THUMB2-NEXT: bxeq lr +; THUMB2-NEXT: b .LBB13_4 +; THUMB2-NEXT: .LBB13_2: @ %lor.lhs.false +; THUMB2-NEXT: bls .LBB13_4 +; THUMB2-NEXT: @ %bb.3: @ %land.lhs.true3 +; THUMB2-NEXT: movw r0, :lower16:d +; THUMB2-NEXT: movw r1, :lower16:b +; THUMB2-NEXT: movt r0, :upper16:d +; THUMB2-NEXT: movt r1, :upper16:b +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: ldr r1, [r1] +; THUMB2-NEXT: cmp r1, r0 +; THUMB2-NEXT: itt eq +; THUMB2-NEXT: moveq r0, #1 +; THUMB2-NEXT: bxeq lr +; THUMB2-NEXT: .LBB13_4: @ %if.end +; THUMB2-NEXT: movs r0, #0 +; THUMB2-NEXT: bx lr +; +; THUMBV8-LABEL: combine_ult_ugt_5: +; THUMBV8: @ %bb.0: @ %entry +; THUMBV8-NEXT: movw r0, :lower16:a +; THUMBV8-NEXT: movt r0, :upper16:a +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: cmp r0, #5 +; THUMBV8-NEXT: bhs .LBB13_2 +; THUMBV8-NEXT: @ %bb.1: @ %land.lhs.true +; THUMBV8-NEXT: movw r0, :lower16:c +; THUMBV8-NEXT: movw r1, :lower16:b +; THUMBV8-NEXT: movt r0, :upper16:c +; THUMBV8-NEXT: movt r1, :upper16:b +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: ldr r1, [r1] +; THUMBV8-NEXT: cmp r1, r0 +; THUMBV8-NEXT: itt eq +; THUMBV8-NEXT: moveq r0, #1 +; THUMBV8-NEXT: bxeq lr +; THUMBV8-NEXT: b .LBB13_4 +; THUMBV8-NEXT: .LBB13_2: @ %lor.lhs.false +; THUMBV8-NEXT: bls .LBB13_4 +; THUMBV8-NEXT: @ %bb.3: @ %land.lhs.true3 +; THUMBV8-NEXT: movw r0, :lower16:d +; THUMBV8-NEXT: movw r1, :lower16:b +; THUMBV8-NEXT: movt r0, :upper16:d +; THUMBV8-NEXT: movt r1, :upper16:b +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: ldr r1, [r1] +; THUMBV8-NEXT: cmp r1, r0 +; THUMBV8-NEXT: itt eq +; THUMBV8-NEXT: moveq r0, #1 +; THUMBV8-NEXT: bxeq lr +; THUMBV8-NEXT: .LBB13_4: @ %if.end +; THUMBV8-NEXT: movs r0, #0 +; THUMBV8-NEXT: bx lr +entry: + %0 = load i32, ptr @a, align 4 + %cmp = icmp ult i32 %0, 5 + br i1 %cmp, label %land.lhs.true, label %lor.lhs.false + +land.lhs.true: ; preds = %entry + %1 = load i32, ptr @b, align 4 + %2 = load i32, ptr @c, align 4 + %cmp1 = icmp eq i32 %1, %2 + br i1 %cmp1, label %return, label %if.end + +lor.lhs.false: ; preds = %entry + %cmp2 = icmp ugt i32 %0, 5 + br i1 %cmp2, label %land.lhs.true3, label %if.end + +land.lhs.true3: ; preds = %lor.lhs.false + %3 = load i32, ptr @b, align 4 + %4 = load i32, ptr @d, align 4 + %cmp4 = icmp eq i32 %3, %4 + br i1 %cmp4, label %return, label %if.end + +if.end: ; preds = %land.lhs.true3, %lor.lhs.false, %land.lhs.true + br label %return + +return: ; preds = %if.end, %land.lhs.true3, %land.lhs.true + %retval.0 = phi i32 [ 0, %if.end ], [ 1, %land.lhs.true3 ], [ 1, %land.lhs.true ] + ret i32 %retval.0 +} + +; (a > -5 && b == c) || (a < -5 && b == d) +define i32 @combine_ugt_ult_n5() #0 { +; ARM-LABEL: combine_ugt_ult_n5: +; ARM: @ %bb.0: @ %entry +; ARM-NEXT: movw r0, :lower16:a +; ARM-NEXT: movt r0, :upper16:a +; ARM-NEXT: ldr r0, [r0] +; ARM-NEXT: cmn r0, #5 +; ARM-NEXT: bls .LBB14_2 +; ARM-NEXT: @ %bb.1: @ %land.lhs.true +; ARM-NEXT: movw r0, :lower16:c +; ARM-NEXT: movt r0, :upper16:c +; ARM-NEXT: b .LBB14_4 +; ARM-NEXT: .LBB14_2: @ %lor.lhs.false +; ARM-NEXT: bhs .LBB14_5 +; ARM-NEXT: @ %bb.3: @ %land.lhs.true3 +; ARM-NEXT: movw r0, :lower16:d +; ARM-NEXT: movt r0, :upper16:d +; ARM-NEXT: .LBB14_4: @ %land.lhs.true3 +; ARM-NEXT: ldr r1, [r0] +; ARM-NEXT: movw r0, :lower16:b +; ARM-NEXT: movt r0, :upper16:b +; ARM-NEXT: ldr r2, [r0] +; ARM-NEXT: mov r0, #1 +; ARM-NEXT: cmp r2, r1 +; ARM-NEXT: movne r0, #0 +; ARM-NEXT: bx lr +; ARM-NEXT: .LBB14_5: @ %if.end +; ARM-NEXT: mov r0, #0 +; ARM-NEXT: bx lr +; +; THUMB-LABEL: combine_ugt_ult_n5: +; THUMB: @ %bb.0: @ %entry +; THUMB-NEXT: ldr r0, .LCPI14_0 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: movs r1, #3 +; THUMB-NEXT: mvns r1, r1 +; THUMB-NEXT: cmp r0, r1 +; THUMB-NEXT: blo .LBB14_3 +; THUMB-NEXT: @ %bb.1: @ %land.lhs.true +; THUMB-NEXT: ldr r0, .LCPI14_3 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: ldr r1, .LCPI14_2 +; THUMB-NEXT: ldr r1, [r1] +; THUMB-NEXT: cmp r1, r0 +; THUMB-NEXT: bne .LBB14_6 +; THUMB-NEXT: @ %bb.2: +; THUMB-NEXT: movs r0, #1 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .LBB14_3: @ %lor.lhs.false +; THUMB-NEXT: movs r1, #5 +; THUMB-NEXT: mvns r1, r1 +; THUMB-NEXT: cmp r0, r1 +; THUMB-NEXT: bhi .LBB14_6 +; THUMB-NEXT: @ %bb.4: @ %land.lhs.true3 +; THUMB-NEXT: ldr r0, .LCPI14_1 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: ldr r1, .LCPI14_2 +; THUMB-NEXT: ldr r1, [r1] +; THUMB-NEXT: cmp r1, r0 +; THUMB-NEXT: bne .LBB14_6 +; THUMB-NEXT: @ %bb.5: +; THUMB-NEXT: movs r0, #1 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .LBB14_6: @ %if.end +; THUMB-NEXT: movs r0, #0 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .p2align 2 +; THUMB-NEXT: @ %bb.7: +; THUMB-NEXT: .LCPI14_0: +; THUMB-NEXT: .long a +; THUMB-NEXT: .LCPI14_1: +; THUMB-NEXT: .long d +; THUMB-NEXT: .LCPI14_2: +; THUMB-NEXT: .long b +; THUMB-NEXT: .LCPI14_3: +; THUMB-NEXT: .long c +; +; THUMB2-LABEL: combine_ugt_ult_n5: +; THUMB2: @ %bb.0: @ %entry +; THUMB2-NEXT: movw r0, :lower16:a +; THUMB2-NEXT: movt r0, :upper16:a +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: cmn.w r0, #5 +; THUMB2-NEXT: bls .LBB14_2 +; THUMB2-NEXT: @ %bb.1: @ %land.lhs.true +; THUMB2-NEXT: movw r0, :lower16:c +; THUMB2-NEXT: movw r1, :lower16:b +; THUMB2-NEXT: movt r0, :upper16:c +; THUMB2-NEXT: movt r1, :upper16:b +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: ldr r1, [r1] +; THUMB2-NEXT: cmp r1, r0 +; THUMB2-NEXT: itt eq +; THUMB2-NEXT: moveq r0, #1 +; THUMB2-NEXT: bxeq lr +; THUMB2-NEXT: b .LBB14_4 +; THUMB2-NEXT: .LBB14_2: @ %lor.lhs.false +; THUMB2-NEXT: bhs .LBB14_4 +; THUMB2-NEXT: @ %bb.3: @ %land.lhs.true3 +; THUMB2-NEXT: movw r0, :lower16:d +; THUMB2-NEXT: movw r1, :lower16:b +; THUMB2-NEXT: movt r0, :upper16:d +; THUMB2-NEXT: movt r1, :upper16:b +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: ldr r1, [r1] +; THUMB2-NEXT: cmp r1, r0 +; THUMB2-NEXT: itt eq +; THUMB2-NEXT: moveq r0, #1 +; THUMB2-NEXT: bxeq lr +; THUMB2-NEXT: .LBB14_4: @ %if.end +; THUMB2-NEXT: movs r0, #0 +; THUMB2-NEXT: bx lr +; +; THUMBV8-LABEL: combine_ugt_ult_n5: +; THUMBV8: @ %bb.0: @ %entry +; THUMBV8-NEXT: movw r0, :lower16:a +; THUMBV8-NEXT: movt r0, :upper16:a +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: cmn.w r0, #5 +; THUMBV8-NEXT: bls .LBB14_2 +; THUMBV8-NEXT: @ %bb.1: @ %land.lhs.true +; THUMBV8-NEXT: movw r0, :lower16:c +; THUMBV8-NEXT: movw r1, :lower16:b +; THUMBV8-NEXT: movt r0, :upper16:c +; THUMBV8-NEXT: movt r1, :upper16:b +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: ldr r1, [r1] +; THUMBV8-NEXT: cmp r1, r0 +; THUMBV8-NEXT: itt eq +; THUMBV8-NEXT: moveq r0, #1 +; THUMBV8-NEXT: bxeq lr +; THUMBV8-NEXT: b .LBB14_4 +; THUMBV8-NEXT: .LBB14_2: @ %lor.lhs.false +; THUMBV8-NEXT: bhs .LBB14_4 +; THUMBV8-NEXT: @ %bb.3: @ %land.lhs.true3 +; THUMBV8-NEXT: movw r0, :lower16:d +; THUMBV8-NEXT: movw r1, :lower16:b +; THUMBV8-NEXT: movt r0, :upper16:d +; THUMBV8-NEXT: movt r1, :upper16:b +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: ldr r1, [r1] +; THUMBV8-NEXT: cmp r1, r0 +; THUMBV8-NEXT: itt eq +; THUMBV8-NEXT: moveq r0, #1 +; THUMBV8-NEXT: bxeq lr +; THUMBV8-NEXT: .LBB14_4: @ %if.end +; THUMBV8-NEXT: movs r0, #0 +; THUMBV8-NEXT: bx lr +entry: + %0 = load i32, ptr @a, align 4 + %cmp = icmp ugt i32 %0, -5 + br i1 %cmp, label %land.lhs.true, label %lor.lhs.false + +land.lhs.true: ; preds = %entry + %1 = load i32, ptr @b, align 4 + %2 = load i32, ptr @c, align 4 + %cmp1 = icmp eq i32 %1, %2 + br i1 %cmp1, label %return, label %if.end + +lor.lhs.false: ; preds = %entry + %cmp2 = icmp ult i32 %0, -5 + br i1 %cmp2, label %land.lhs.true3, label %if.end + +land.lhs.true3: ; preds = %lor.lhs.false + %3 = load i32, ptr @b, align 4 + %4 = load i32, ptr @d, align 4 + %cmp4 = icmp eq i32 %3, %4 + br i1 %cmp4, label %return, label %if.end + +if.end: ; preds = %land.lhs.true3, %lor.lhs.false, %land.lhs.true + br label %return + +return: ; preds = %if.end, %land.lhs.true3, %land.lhs.true + %retval.0 = phi i32 [ 0, %if.end ], [ 1, %land.lhs.true3 ], [ 1, %land.lhs.true ] + ret i32 %retval.0 +} + +; (a < -5 && b == c) || (a > -5 && b == d) +define i32 @combine_ult_ugt_n5() #0 { +; ARM-LABEL: combine_ult_ugt_n5: +; ARM: @ %bb.0: @ %entry +; ARM-NEXT: movw r0, :lower16:a +; ARM-NEXT: movt r0, :upper16:a +; ARM-NEXT: ldr r0, [r0] +; ARM-NEXT: cmn r0, #5 +; ARM-NEXT: bhs .LBB15_2 +; ARM-NEXT: @ %bb.1: @ %land.lhs.true +; ARM-NEXT: movw r0, :lower16:c +; ARM-NEXT: movt r0, :upper16:c +; ARM-NEXT: b .LBB15_4 +; ARM-NEXT: .LBB15_2: @ %lor.lhs.false +; ARM-NEXT: bls .LBB15_5 +; ARM-NEXT: @ %bb.3: @ %land.lhs.true3 +; ARM-NEXT: movw r0, :lower16:d +; ARM-NEXT: movt r0, :upper16:d +; ARM-NEXT: .LBB15_4: @ %land.lhs.true3 +; ARM-NEXT: ldr r1, [r0] +; ARM-NEXT: movw r0, :lower16:b +; ARM-NEXT: movt r0, :upper16:b +; ARM-NEXT: ldr r2, [r0] +; ARM-NEXT: mov r0, #1 +; ARM-NEXT: cmp r2, r1 +; ARM-NEXT: movne r0, #0 +; ARM-NEXT: bx lr +; ARM-NEXT: .LBB15_5: @ %if.end +; ARM-NEXT: mov r0, #0 +; ARM-NEXT: bx lr +; +; THUMB-LABEL: combine_ult_ugt_n5: +; THUMB: @ %bb.0: @ %entry +; THUMB-NEXT: ldr r0, .LCPI15_0 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: movs r1, #5 +; THUMB-NEXT: mvns r1, r1 +; THUMB-NEXT: cmp r0, r1 +; THUMB-NEXT: bhi .LBB15_3 +; THUMB-NEXT: @ %bb.1: @ %land.lhs.true +; THUMB-NEXT: ldr r0, .LCPI15_3 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: ldr r1, .LCPI15_2 +; THUMB-NEXT: ldr r1, [r1] +; THUMB-NEXT: cmp r1, r0 +; THUMB-NEXT: bne .LBB15_6 +; THUMB-NEXT: @ %bb.2: +; THUMB-NEXT: movs r0, #1 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .LBB15_3: @ %lor.lhs.false +; THUMB-NEXT: movs r1, #3 +; THUMB-NEXT: mvns r1, r1 +; THUMB-NEXT: cmp r0, r1 +; THUMB-NEXT: blo .LBB15_6 +; THUMB-NEXT: @ %bb.4: @ %land.lhs.true3 +; THUMB-NEXT: ldr r0, .LCPI15_1 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: ldr r1, .LCPI15_2 +; THUMB-NEXT: ldr r1, [r1] +; THUMB-NEXT: cmp r1, r0 +; THUMB-NEXT: bne .LBB15_6 +; THUMB-NEXT: @ %bb.5: +; THUMB-NEXT: movs r0, #1 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .LBB15_6: @ %if.end +; THUMB-NEXT: movs r0, #0 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .p2align 2 +; THUMB-NEXT: @ %bb.7: +; THUMB-NEXT: .LCPI15_0: +; THUMB-NEXT: .long a +; THUMB-NEXT: .LCPI15_1: +; THUMB-NEXT: .long d +; THUMB-NEXT: .LCPI15_2: +; THUMB-NEXT: .long b +; THUMB-NEXT: .LCPI15_3: +; THUMB-NEXT: .long c +; +; THUMB2-LABEL: combine_ult_ugt_n5: +; THUMB2: @ %bb.0: @ %entry +; THUMB2-NEXT: movw r0, :lower16:a +; THUMB2-NEXT: movt r0, :upper16:a +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: cmn.w r0, #5 +; THUMB2-NEXT: bhs .LBB15_2 +; THUMB2-NEXT: @ %bb.1: @ %land.lhs.true +; THUMB2-NEXT: movw r0, :lower16:c +; THUMB2-NEXT: movw r1, :lower16:b +; THUMB2-NEXT: movt r0, :upper16:c +; THUMB2-NEXT: movt r1, :upper16:b +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: ldr r1, [r1] +; THUMB2-NEXT: cmp r1, r0 +; THUMB2-NEXT: itt eq +; THUMB2-NEXT: moveq r0, #1 +; THUMB2-NEXT: bxeq lr +; THUMB2-NEXT: b .LBB15_4 +; THUMB2-NEXT: .LBB15_2: @ %lor.lhs.false +; THUMB2-NEXT: bls .LBB15_4 +; THUMB2-NEXT: @ %bb.3: @ %land.lhs.true3 +; THUMB2-NEXT: movw r0, :lower16:d +; THUMB2-NEXT: movw r1, :lower16:b +; THUMB2-NEXT: movt r0, :upper16:d +; THUMB2-NEXT: movt r1, :upper16:b +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: ldr r1, [r1] +; THUMB2-NEXT: cmp r1, r0 +; THUMB2-NEXT: itt eq +; THUMB2-NEXT: moveq r0, #1 +; THUMB2-NEXT: bxeq lr +; THUMB2-NEXT: .LBB15_4: @ %if.end +; THUMB2-NEXT: movs r0, #0 +; THUMB2-NEXT: bx lr +; +; THUMBV8-LABEL: combine_ult_ugt_n5: +; THUMBV8: @ %bb.0: @ %entry +; THUMBV8-NEXT: movw r0, :lower16:a +; THUMBV8-NEXT: movt r0, :upper16:a +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: cmn.w r0, #5 +; THUMBV8-NEXT: bhs .LBB15_2 +; THUMBV8-NEXT: @ %bb.1: @ %land.lhs.true +; THUMBV8-NEXT: movw r0, :lower16:c +; THUMBV8-NEXT: movw r1, :lower16:b +; THUMBV8-NEXT: movt r0, :upper16:c +; THUMBV8-NEXT: movt r1, :upper16:b +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: ldr r1, [r1] +; THUMBV8-NEXT: cmp r1, r0 +; THUMBV8-NEXT: itt eq +; THUMBV8-NEXT: moveq r0, #1 +; THUMBV8-NEXT: bxeq lr +; THUMBV8-NEXT: b .LBB15_4 +; THUMBV8-NEXT: .LBB15_2: @ %lor.lhs.false +; THUMBV8-NEXT: bls .LBB15_4 +; THUMBV8-NEXT: @ %bb.3: @ %land.lhs.true3 +; THUMBV8-NEXT: movw r0, :lower16:d +; THUMBV8-NEXT: movw r1, :lower16:b +; THUMBV8-NEXT: movt r0, :upper16:d +; THUMBV8-NEXT: movt r1, :upper16:b +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: ldr r1, [r1] +; THUMBV8-NEXT: cmp r1, r0 +; THUMBV8-NEXT: itt eq +; THUMBV8-NEXT: moveq r0, #1 +; THUMBV8-NEXT: bxeq lr +; THUMBV8-NEXT: .LBB15_4: @ %if.end +; THUMBV8-NEXT: movs r0, #0 +; THUMBV8-NEXT: bx lr +entry: + %0 = load i32, ptr @a, align 4 + %cmp = icmp ult i32 %0, -5 + br i1 %cmp, label %land.lhs.true, label %lor.lhs.false + +land.lhs.true: ; preds = %entry + %1 = load i32, ptr @b, align 4 + %2 = load i32, ptr @c, align 4 + %cmp1 = icmp eq i32 %1, %2 + br i1 %cmp1, label %return, label %if.end + +lor.lhs.false: ; preds = %entry + %cmp2 = icmp ugt i32 %0, -5 + br i1 %cmp2, label %land.lhs.true3, label %if.end + +land.lhs.true3: ; preds = %lor.lhs.false + %3 = load i32, ptr @b, align 4 + %4 = load i32, ptr @d, align 4 + %cmp4 = icmp eq i32 %3, %4 + br i1 %cmp4, label %return, label %if.end + +if.end: ; preds = %land.lhs.true3, %lor.lhs.false, %land.lhs.true + br label %return + +return: ; preds = %if.end, %land.lhs.true3, %land.lhs.true + %retval.0 = phi i32 [ 0, %if.end ], [ 1, %land.lhs.true3 ], [ 1, %land.lhs.true ] + ret i32 %retval.0 +} + +; Yes, you can mix them too! +; (a < -5 && b == c) || (a u> -5 && b == d) +define i32 @combine_ult_gt_n5() #0 { +; ARM-LABEL: combine_ult_gt_n5: +; ARM: @ %bb.0: @ %entry +; ARM-NEXT: movw r0, :lower16:a +; ARM-NEXT: movt r0, :upper16:a +; ARM-NEXT: ldr r0, [r0] +; ARM-NEXT: cmn r0, #5 +; ARM-NEXT: bhs .LBB16_2 +; ARM-NEXT: @ %bb.1: @ %land.lhs.true +; ARM-NEXT: movw r0, :lower16:c +; ARM-NEXT: movt r0, :upper16:c +; ARM-NEXT: b .LBB16_4 +; ARM-NEXT: .LBB16_2: @ %lor.lhs.false +; ARM-NEXT: ble .LBB16_5 +; ARM-NEXT: @ %bb.3: @ %land.lhs.true3 +; ARM-NEXT: movw r0, :lower16:d +; ARM-NEXT: movt r0, :upper16:d +; ARM-NEXT: .LBB16_4: @ %land.lhs.true3 +; ARM-NEXT: ldr r1, [r0] +; ARM-NEXT: movw r0, :lower16:b +; ARM-NEXT: movt r0, :upper16:b +; ARM-NEXT: ldr r2, [r0] +; ARM-NEXT: mov r0, #1 +; ARM-NEXT: cmp r2, r1 +; ARM-NEXT: movne r0, #0 +; ARM-NEXT: bx lr +; ARM-NEXT: .LBB16_5: @ %if.end +; ARM-NEXT: mov r0, #0 +; ARM-NEXT: bx lr +; +; THUMB-LABEL: combine_ult_gt_n5: +; THUMB: @ %bb.0: @ %entry +; THUMB-NEXT: ldr r0, .LCPI16_0 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: movs r1, #5 +; THUMB-NEXT: mvns r1, r1 +; THUMB-NEXT: cmp r0, r1 +; THUMB-NEXT: bhi .LBB16_3 +; THUMB-NEXT: @ %bb.1: @ %land.lhs.true +; THUMB-NEXT: ldr r0, .LCPI16_3 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: ldr r1, .LCPI16_2 +; THUMB-NEXT: ldr r1, [r1] +; THUMB-NEXT: cmp r1, r0 +; THUMB-NEXT: bne .LBB16_6 +; THUMB-NEXT: @ %bb.2: +; THUMB-NEXT: movs r0, #1 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .LBB16_3: @ %lor.lhs.false +; THUMB-NEXT: movs r1, #3 +; THUMB-NEXT: mvns r1, r1 +; THUMB-NEXT: cmp r0, r1 +; THUMB-NEXT: blt .LBB16_6 +; THUMB-NEXT: @ %bb.4: @ %land.lhs.true3 +; THUMB-NEXT: ldr r0, .LCPI16_1 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: ldr r1, .LCPI16_2 +; THUMB-NEXT: ldr r1, [r1] +; THUMB-NEXT: cmp r1, r0 +; THUMB-NEXT: bne .LBB16_6 +; THUMB-NEXT: @ %bb.5: +; THUMB-NEXT: movs r0, #1 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .LBB16_6: @ %if.end +; THUMB-NEXT: movs r0, #0 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .p2align 2 +; THUMB-NEXT: @ %bb.7: +; THUMB-NEXT: .LCPI16_0: +; THUMB-NEXT: .long a +; THUMB-NEXT: .LCPI16_1: +; THUMB-NEXT: .long d +; THUMB-NEXT: .LCPI16_2: +; THUMB-NEXT: .long b +; THUMB-NEXT: .LCPI16_3: +; THUMB-NEXT: .long c +; +; THUMB2-LABEL: combine_ult_gt_n5: +; THUMB2: @ %bb.0: @ %entry +; THUMB2-NEXT: movw r0, :lower16:a +; THUMB2-NEXT: movt r0, :upper16:a +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: cmn.w r0, #5 +; THUMB2-NEXT: bhs .LBB16_2 +; THUMB2-NEXT: @ %bb.1: @ %land.lhs.true +; THUMB2-NEXT: movw r0, :lower16:c +; THUMB2-NEXT: movw r1, :lower16:b +; THUMB2-NEXT: movt r0, :upper16:c +; THUMB2-NEXT: movt r1, :upper16:b +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: ldr r1, [r1] +; THUMB2-NEXT: cmp r1, r0 +; THUMB2-NEXT: itt eq +; THUMB2-NEXT: moveq r0, #1 +; THUMB2-NEXT: bxeq lr +; THUMB2-NEXT: b .LBB16_4 +; THUMB2-NEXT: .LBB16_2: @ %lor.lhs.false +; THUMB2-NEXT: ble .LBB16_4 +; THUMB2-NEXT: @ %bb.3: @ %land.lhs.true3 +; THUMB2-NEXT: movw r0, :lower16:d +; THUMB2-NEXT: movw r1, :lower16:b +; THUMB2-NEXT: movt r0, :upper16:d +; THUMB2-NEXT: movt r1, :upper16:b +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: ldr r1, [r1] +; THUMB2-NEXT: cmp r1, r0 +; THUMB2-NEXT: itt eq +; THUMB2-NEXT: moveq r0, #1 +; THUMB2-NEXT: bxeq lr +; THUMB2-NEXT: .LBB16_4: @ %if.end +; THUMB2-NEXT: movs r0, #0 +; THUMB2-NEXT: bx lr +; +; THUMBV8-LABEL: combine_ult_gt_n5: +; THUMBV8: @ %bb.0: @ %entry +; THUMBV8-NEXT: movw r0, :lower16:a +; THUMBV8-NEXT: movt r0, :upper16:a +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: cmn.w r0, #5 +; THUMBV8-NEXT: bhs .LBB16_2 +; THUMBV8-NEXT: @ %bb.1: @ %land.lhs.true +; THUMBV8-NEXT: movw r0, :lower16:c +; THUMBV8-NEXT: movw r1, :lower16:b +; THUMBV8-NEXT: movt r0, :upper16:c +; THUMBV8-NEXT: movt r1, :upper16:b +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: ldr r1, [r1] +; THUMBV8-NEXT: cmp r1, r0 +; THUMBV8-NEXT: itt eq +; THUMBV8-NEXT: moveq r0, #1 +; THUMBV8-NEXT: bxeq lr +; THUMBV8-NEXT: b .LBB16_4 +; THUMBV8-NEXT: .LBB16_2: @ %lor.lhs.false +; THUMBV8-NEXT: ble .LBB16_4 +; THUMBV8-NEXT: @ %bb.3: @ %land.lhs.true3 +; THUMBV8-NEXT: movw r0, :lower16:d +; THUMBV8-NEXT: movw r1, :lower16:b +; THUMBV8-NEXT: movt r0, :upper16:d +; THUMBV8-NEXT: movt r1, :upper16:b +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: ldr r1, [r1] +; THUMBV8-NEXT: cmp r1, r0 +; THUMBV8-NEXT: itt eq +; THUMBV8-NEXT: moveq r0, #1 +; THUMBV8-NEXT: bxeq lr +; THUMBV8-NEXT: .LBB16_4: @ %if.end +; THUMBV8-NEXT: movs r0, #0 +; THUMBV8-NEXT: bx lr +entry: + %0 = load i32, ptr @a, align 4 + %cmp = icmp ult i32 %0, -5 + br i1 %cmp, label %land.lhs.true, label %lor.lhs.false + +land.lhs.true: ; preds = %entry + %1 = load i32, ptr @b, align 4 + %2 = load i32, ptr @c, align 4 + %cmp1 = icmp eq i32 %1, %2 + br i1 %cmp1, label %return, label %if.end + +lor.lhs.false: ; preds = %entry + %cmp2 = icmp sgt i32 %0, -5 + br i1 %cmp2, label %land.lhs.true3, label %if.end + +land.lhs.true3: ; preds = %lor.lhs.false + %3 = load i32, ptr @b, align 4 + %4 = load i32, ptr @d, align 4 + %cmp4 = icmp eq i32 %3, %4 + br i1 %cmp4, label %return, label %if.end + +if.end: ; preds = %land.lhs.true3, %lor.lhs.false, %land.lhs.true + br label %return + +return: ; preds = %if.end, %land.lhs.true3, %land.lhs.true + %retval.0 = phi i32 [ 0, %if.end ], [ 1, %land.lhs.true3 ], [ 1, %land.lhs.true ] + ret i32 %retval.0 +} + +define i32 @combine_ugt_uge_sel(i32 %v, ptr %p) #0 { +; ARM-LABEL: combine_ugt_uge_sel: +; ARM: @ %bb.0: @ %entry +; ARM-NEXT: movw r2, :lower16:a +; ARM-NEXT: movt r2, :upper16:a +; ARM-NEXT: ldr r2, [r2] +; ARM-NEXT: cmp r2, #0 +; ARM-NEXT: moveq r0, r2 +; ARM-NEXT: str r0, [r1] +; ARM-NEXT: movw r1, :lower16:b +; ARM-NEXT: movt r1, :upper16:b +; ARM-NEXT: beq .LBB17_3 +; ARM-NEXT: @ %bb.1: @ %lor.lhs.false +; ARM-NEXT: cmp r2, #2 +; ARM-NEXT: bhs .LBB17_4 +; ARM-NEXT: @ %bb.2: @ %if.end +; ARM-NEXT: mov r0, #0 +; ARM-NEXT: bx lr +; ARM-NEXT: .LBB17_3: @ %land.lhs.true +; ARM-NEXT: movw r0, :lower16:c +; ARM-NEXT: ldr r3, [r1] +; ARM-NEXT: movt r0, :upper16:c +; ARM-NEXT: ldr r2, [r0] +; ARM-NEXT: mov r0, #1 +; ARM-NEXT: cmp r3, r2 +; ARM-NEXT: bxeq lr +; ARM-NEXT: .LBB17_4: @ %land.lhs.true3 +; ARM-NEXT: movw r0, :lower16:d +; ARM-NEXT: ldr r1, [r1] +; ARM-NEXT: movt r0, :upper16:d +; ARM-NEXT: ldr r2, [r0] +; ARM-NEXT: mov r0, #1 +; ARM-NEXT: cmp r1, r2 +; ARM-NEXT: movne r0, #0 +; ARM-NEXT: bx lr +; +; THUMB-LABEL: combine_ugt_uge_sel: +; THUMB: @ %bb.0: @ %entry +; THUMB-NEXT: ldr r2, .LCPI17_0 +; THUMB-NEXT: ldr r2, [r2] +; THUMB-NEXT: cmp r2, #0 +; THUMB-NEXT: bne .LBB17_2 +; THUMB-NEXT: @ %bb.1: @ %entry +; THUMB-NEXT: mov r0, r2 +; THUMB-NEXT: .LBB17_2: @ %entry +; THUMB-NEXT: str r0, [r1] +; THUMB-NEXT: beq .LBB17_4 +; THUMB-NEXT: @ %bb.3: @ %lor.lhs.false +; THUMB-NEXT: cmp r2, #2 +; THUMB-NEXT: bhs .LBB17_6 +; THUMB-NEXT: b .LBB17_8 +; THUMB-NEXT: .LBB17_4: @ %land.lhs.true +; THUMB-NEXT: ldr r0, .LCPI17_1 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: ldr r1, .LCPI17_2 +; THUMB-NEXT: ldr r1, [r1] +; THUMB-NEXT: cmp r1, r0 +; THUMB-NEXT: bne .LBB17_6 +; THUMB-NEXT: @ %bb.5: +; THUMB-NEXT: movs r0, #1 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .LBB17_6: @ %land.lhs.true3 +; THUMB-NEXT: ldr r0, .LCPI17_3 +; THUMB-NEXT: ldr r0, [r0] +; THUMB-NEXT: ldr r1, .LCPI17_2 +; THUMB-NEXT: ldr r1, [r1] +; THUMB-NEXT: cmp r1, r0 +; THUMB-NEXT: bne .LBB17_8 +; THUMB-NEXT: @ %bb.7: +; THUMB-NEXT: movs r0, #1 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .LBB17_8: @ %if.end +; THUMB-NEXT: movs r0, #0 +; THUMB-NEXT: bx lr +; THUMB-NEXT: .p2align 2 +; THUMB-NEXT: @ %bb.9: +; THUMB-NEXT: .LCPI17_0: +; THUMB-NEXT: .long a +; THUMB-NEXT: .LCPI17_1: +; THUMB-NEXT: .long c +; THUMB-NEXT: .LCPI17_2: +; THUMB-NEXT: .long b +; THUMB-NEXT: .LCPI17_3: +; THUMB-NEXT: .long d +; +; THUMB2-LABEL: combine_ugt_uge_sel: +; THUMB2: @ %bb.0: @ %entry +; THUMB2-NEXT: movw r2, :lower16:a +; THUMB2-NEXT: movt r2, :upper16:a +; THUMB2-NEXT: ldr r2, [r2] +; THUMB2-NEXT: cmp r2, #0 +; THUMB2-NEXT: it eq +; THUMB2-NEXT: moveq r0, r2 +; THUMB2-NEXT: str r0, [r1] +; THUMB2-NEXT: movw r0, :lower16:b +; THUMB2-NEXT: movt r0, :upper16:b +; THUMB2-NEXT: beq .LBB17_2 +; THUMB2-NEXT: @ %bb.1: @ %lor.lhs.false +; THUMB2-NEXT: cmp r2, #2 +; THUMB2-NEXT: bhs .LBB17_3 +; THUMB2-NEXT: b .LBB17_4 +; THUMB2-NEXT: .LBB17_2: @ %land.lhs.true +; THUMB2-NEXT: movw r1, :lower16:c +; THUMB2-NEXT: ldr r2, [r0] +; THUMB2-NEXT: movt r1, :upper16:c +; THUMB2-NEXT: ldr r1, [r1] +; THUMB2-NEXT: cmp r2, r1 +; THUMB2-NEXT: itt eq +; THUMB2-NEXT: moveq r0, #1 +; THUMB2-NEXT: bxeq lr +; THUMB2-NEXT: .LBB17_3: @ %land.lhs.true3 +; THUMB2-NEXT: movw r1, :lower16:d +; THUMB2-NEXT: ldr r0, [r0] +; THUMB2-NEXT: movt r1, :upper16:d +; THUMB2-NEXT: ldr r1, [r1] +; THUMB2-NEXT: cmp r0, r1 +; THUMB2-NEXT: itt eq +; THUMB2-NEXT: moveq r0, #1 +; THUMB2-NEXT: bxeq lr +; THUMB2-NEXT: .LBB17_4: @ %if.end +; THUMB2-NEXT: movs r0, #0 +; THUMB2-NEXT: bx lr +; +; THUMBV8-LABEL: combine_ugt_uge_sel: +; THUMBV8: @ %bb.0: @ %entry +; THUMBV8-NEXT: movw r2, :lower16:a +; THUMBV8-NEXT: movt r2, :upper16:a +; THUMBV8-NEXT: ldr r2, [r2] +; THUMBV8-NEXT: cmp r2, #0 +; THUMBV8-NEXT: csel r0, r0, r2, ne +; THUMBV8-NEXT: str r0, [r1] +; THUMBV8-NEXT: movw r0, :lower16:b +; THUMBV8-NEXT: movt r0, :upper16:b +; THUMBV8-NEXT: beq .LBB17_2 +; THUMBV8-NEXT: @ %bb.1: @ %lor.lhs.false +; THUMBV8-NEXT: cmp r2, #2 +; THUMBV8-NEXT: bhs .LBB17_3 +; THUMBV8-NEXT: b .LBB17_4 +; THUMBV8-NEXT: .LBB17_2: @ %land.lhs.true +; THUMBV8-NEXT: movw r1, :lower16:c +; THUMBV8-NEXT: ldr r2, [r0] +; THUMBV8-NEXT: movt r1, :upper16:c +; THUMBV8-NEXT: ldr r1, [r1] +; THUMBV8-NEXT: cmp r2, r1 +; THUMBV8-NEXT: itt eq +; THUMBV8-NEXT: moveq r0, #1 +; THUMBV8-NEXT: bxeq lr +; THUMBV8-NEXT: .LBB17_3: @ %land.lhs.true3 +; THUMBV8-NEXT: movw r1, :lower16:d +; THUMBV8-NEXT: ldr r0, [r0] +; THUMBV8-NEXT: movt r1, :upper16:d +; THUMBV8-NEXT: ldr r1, [r1] +; THUMBV8-NEXT: cmp r0, r1 +; THUMBV8-NEXT: itt eq +; THUMBV8-NEXT: moveq r0, #1 +; THUMBV8-NEXT: bxeq lr +; THUMBV8-NEXT: .LBB17_4: @ %if.end +; THUMBV8-NEXT: movs r0, #0 +; THUMBV8-NEXT: bx lr +entry: + %0 = load i32, ptr @a, align 4 + %cmp = icmp ugt i32 %0, 0 + %m = select i1 %cmp, i32 %v, i32 0 + store i32 %m, ptr %p + br i1 %cmp, label %lor.lhs.false, label %land.lhs.true + +land.lhs.true: ; preds = %entry + %1 = load i32, ptr @b, align 4 + %2 = load i32, ptr @c, align 4 + %cmp1 = icmp eq i32 %1, %2 + br i1 %cmp1, label %return, label %land.lhs.true3 + +lor.lhs.false: ; preds = %entry + %cmp2 = icmp ugt i32 %0, 1 + br i1 %cmp2, label %land.lhs.true3, label %if.end + +land.lhs.true3: ; preds = %lor.lhs.false, %land.lhs.true + %3 = load i32, ptr @b, align 4 + %4 = load i32, ptr @d, align 4 + %cmp4 = icmp eq i32 %3, %4 + br i1 %cmp4, label %return, label %if.end + +if.end: ; preds = %land.lhs.true3, %lor.lhs.false + br label %return + +return: ; preds = %if.end, %land.lhs.true3, %land.lhs.true + %retval.0 = phi i32 [ 0, %if.end ], [ 1, %land.lhs.true3 ], [ 1, %land.lhs.true ] + ret i32 %retval.0 +} + +attributes #0 = { uwtable } diff --git a/llvm/test/CodeGen/ARM/fpclamptosat.ll b/llvm/test/CodeGen/ARM/fpclamptosat.ll index a6f0a03fc7e5b..6b0f0236cc4db 100644 --- a/llvm/test/CodeGen/ARM/fpclamptosat.ll +++ b/llvm/test/CodeGen/ARM/fpclamptosat.ll @@ -1862,8 +1862,8 @@ define i32 @ustest_f64i32_mm(double %x) { ; SOFT-NEXT: bl __aeabi_d2lz ; SOFT-NEXT: mov r2, r0 ; SOFT-NEXT: movs r0, #0 -; SOFT-NEXT: cmp r1, #1 -; SOFT-NEXT: blt .LBB29_2 +; SOFT-NEXT: cmp r1, #0 +; SOFT-NEXT: ble .LBB29_2 ; SOFT-NEXT: @ %bb.1: @ %entry ; SOFT-NEXT: mvns r2, r0 ; SOFT-NEXT: .LBB29_2: @ %entry @@ -1994,8 +1994,8 @@ define i32 @ustest_f32i32_mm(float %x) { ; SOFT-NEXT: bl __aeabi_f2lz ; SOFT-NEXT: mov r2, r0 ; SOFT-NEXT: movs r0, #0 -; SOFT-NEXT: cmp r1, #1 -; SOFT-NEXT: blt .LBB32_2 +; SOFT-NEXT: cmp r1, #0 +; SOFT-NEXT: ble .LBB32_2 ; SOFT-NEXT: @ %bb.1: @ %entry ; SOFT-NEXT: mvns r2, r0 ; SOFT-NEXT: .LBB32_2: @ %entry @@ -2140,8 +2140,8 @@ define i32 @ustest_f16i32_mm(half %x) { ; SOFT-NEXT: bl __aeabi_f2lz ; SOFT-NEXT: mov r2, r0 ; SOFT-NEXT: movs r0, #0 -; SOFT-NEXT: cmp r1, #1 -; SOFT-NEXT: blt .LBB35_2 +; SOFT-NEXT: cmp r1, #0 +; SOFT-NEXT: ble .LBB35_2 ; SOFT-NEXT: @ %bb.1: @ %entry ; SOFT-NEXT: mvns r2, r0 ; SOFT-NEXT: .LBB35_2: @ %entry diff --git a/llvm/test/CodeGen/Thumb/smul_fix_sat.ll b/llvm/test/CodeGen/Thumb/smul_fix_sat.ll index 24209b45e302d..bae539ec3bb95 100644 --- a/llvm/test/CodeGen/Thumb/smul_fix_sat.ll +++ b/llvm/test/CodeGen/Thumb/smul_fix_sat.ll @@ -104,9 +104,9 @@ define i64 @func2(i64 %x, i64 %y) nounwind { ; ARM-NEXT: mov r5, r4 ; ARM-NEXT: .LBB1_2: ; ARM-NEXT: ands r2, r5 -; ARM-NEXT: cmp r1, #0 +; ARM-NEXT: cmp r1, #1 ; ARM-NEXT: mov r5, r0 -; ARM-NEXT: bgt .LBB1_4 +; ARM-NEXT: bge .LBB1_4 ; ARM-NEXT: @ %bb.3: ; ARM-NEXT: mov r5, r4 ; ARM-NEXT: .LBB1_4: