Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -3436,7 +3436,9 @@ may be any of the :ref:`binary ` or :ref:`bitwise binary ` operations. The constraints on operands are the same as those for the corresponding instruction (e.g. no bitwise - operations on floating-point values are allowed). + operations on floating-point values are allowed). Constant expressions + never have undefined behavior; division operations that would have + undefined behavior instead produce poison. Other Values ============ Index: include/llvm/Analysis/ValueTracking.h =================================================================== --- include/llvm/Analysis/ValueTracking.h +++ include/llvm/Analysis/ValueTracking.h @@ -388,7 +388,7 @@ /// /// This method can return true for instructions that read memory; /// for such instructions, moving them may change the resulting value. - bool isSafeToSpeculativelyExecute(const Value *V, + bool isSafeToSpeculativelyExecute(const Instruction *I, const Instruction *CtxI = nullptr, const DominatorTree *DT = nullptr); Index: include/llvm/CodeGen/GlobalISel/IRTranslator.h =================================================================== --- include/llvm/CodeGen/GlobalISel/IRTranslator.h +++ include/llvm/CodeGen/GlobalISel/IRTranslator.h @@ -337,15 +337,27 @@ } bool translateUDiv(const User &U, MachineIRBuilder &MIRBuilder) { + // Non-trapping div for ConstantExpr not yet implemented. + if (isa(U)) + return false; return translateBinaryOp(TargetOpcode::G_UDIV, U, MIRBuilder); } bool translateSDiv(const User &U, MachineIRBuilder &MIRBuilder) { + // Non-trapping div for ConstantExpr not yet implemented. + if (isa(U)) + return false; return translateBinaryOp(TargetOpcode::G_SDIV, U, MIRBuilder); } bool translateURem(const User &U, MachineIRBuilder &MIRBuilder) { + // Non-trapping div for ConstantExpr not yet implemented. + if (isa(U)) + return false; return translateBinaryOp(TargetOpcode::G_UREM, U, MIRBuilder); } bool translateSRem(const User &U, MachineIRBuilder &MIRBuilder) { + // Non-trapping div for ConstantExpr not yet implemented. + if (isa(U)) + return false; return translateBinaryOp(TargetOpcode::G_SREM, U, MIRBuilder); } bool translateIntToPtr(const User &U, MachineIRBuilder &MIRBuilder) { Index: include/llvm/IR/Constant.h =================================================================== --- include/llvm/IR/Constant.h +++ include/llvm/IR/Constant.h @@ -94,10 +94,6 @@ /// expressions. bool containsConstantExpression() const; - /// Return true if evaluation of this constant could trap. This is true for - /// things like constant expressions that could divide by zero. - bool canTrap() const; - /// Return true if the value can vary between threads. bool isThreadDependent() const; Index: lib/Analysis/CodeMetrics.cpp =================================================================== --- lib/Analysis/CodeMetrics.cpp +++ lib/Analysis/CodeMetrics.cpp @@ -34,7 +34,8 @@ for (const Value *Operand : U->operands()) if (Visited.insert(Operand).second) - if (isSafeToSpeculativelyExecute(Operand)) + if (!isa(Operand) || + isSafeToSpeculativelyExecute(cast(Operand))) Worklist.push_back(Operand); } Index: lib/Analysis/ValueTracking.cpp =================================================================== --- lib/Analysis/ValueTracking.cpp +++ lib/Analysis/ValueTracking.cpp @@ -485,7 +485,8 @@ if (V == E) return true; - if (V == I || isSafeToSpeculativelyExecute(V)) { + if (V == I || !isa(V) || + isSafeToSpeculativelyExecute(cast(V))) { EphValues.insert(V); if (const User *U = dyn_cast(V)) for (User::const_op_iterator J = U->op_begin(), JE = U->op_end(); @@ -3895,18 +3896,9 @@ return true; } -bool llvm::isSafeToSpeculativelyExecute(const Value *V, +bool llvm::isSafeToSpeculativelyExecute(const Instruction *Inst, const Instruction *CtxI, const DominatorTree *DT) { - const Operator *Inst = dyn_cast(V); - if (!Inst) - return false; - - for (unsigned i = 0, e = Inst->getNumOperands(); i != e; ++i) - if (Constant *C = dyn_cast(Inst->getOperand(i))) - if (C->canTrap()) - return false; - switch (Inst->getOpcode()) { default: return true; Index: lib/CodeGen/SelectionDAG/FastISel.cpp =================================================================== --- lib/CodeGen/SelectionDAG/FastISel.cpp +++ lib/CodeGen/SelectionDAG/FastISel.cpp @@ -1817,14 +1817,26 @@ case Instruction::FMul: return selectBinaryOp(I, ISD::FMUL); case Instruction::SDiv: + // Non-trapping div for ConstantExpr not yet implemented. + if (isa(I)) + return false; return selectBinaryOp(I, ISD::SDIV); case Instruction::UDiv: + // Non-trapping div for ConstantExpr not yet implemented. + if (isa(I)) + return false; return selectBinaryOp(I, ISD::UDIV); case Instruction::FDiv: return selectBinaryOp(I, ISD::FDIV); case Instruction::SRem: + // Non-trapping div for ConstantExpr not yet implemented. + if (isa(I)) + return false; return selectBinaryOp(I, ISD::SREM); case Instruction::URem: + // Non-trapping div for ConstantExpr not yet implemented. + if (isa(I)) + return false; return selectBinaryOp(I, ISD::UREM); case Instruction::FRem: return selectBinaryOp(I, ISD::FREM); Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h @@ -878,17 +878,18 @@ void visitBinary(const User &I, unsigned Opcode); void visitShift(const User &I, unsigned Opcode); + void visitDivRem(const User &I, unsigned Opcode); void visitAdd(const User &I) { visitBinary(I, ISD::ADD); } void visitFAdd(const User &I) { visitBinary(I, ISD::FADD); } void visitSub(const User &I) { visitBinary(I, ISD::SUB); } void visitFSub(const User &I); void visitMul(const User &I) { visitBinary(I, ISD::MUL); } void visitFMul(const User &I) { visitBinary(I, ISD::FMUL); } - void visitURem(const User &I) { visitBinary(I, ISD::UREM); } - void visitSRem(const User &I) { visitBinary(I, ISD::SREM); } + void visitURem(const User &I) { visitDivRem(I, ISD::UREM); } + void visitSRem(const User &I) { visitDivRem(I, ISD::SREM); } void visitFRem(const User &I) { visitBinary(I, ISD::FREM); } - void visitUDiv(const User &I) { visitBinary(I, ISD::UDIV); } - void visitSDiv(const User &I); + void visitUDiv(const User &I) { visitDivRem(I, ISD::UDIV); } + void visitSDiv(const User &I) { visitDivRem(I, ISD::SDIV); } void visitFDiv(const User &I) { visitBinary(I, ISD::FDIV); } void visitAnd (const User &I) { visitBinary(I, ISD::AND); } void visitOr (const User &I) { visitBinary(I, ISD::OR); } Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -3206,15 +3206,45 @@ setValue(&I, Res); } -void SelectionDAGBuilder::visitSDiv(const User &I) { +void SelectionDAGBuilder::visitDivRem(const User &I, unsigned Opcode) { + if (!isa(I)) + return visitBinary(I, Opcode); + + // Constants aren't allowed to trap, so we have to do something + // a bit trickier. + // + // FIXME: Some targets have a cheap non-trapping div. SDValue Op1 = getValue(I.getOperand(0)); SDValue Op2 = getValue(I.getOperand(1)); - - SDNodeFlags Flags; - Flags.setExact(isa(&I) && - cast(&I)->isExact()); - setValue(&I, DAG.getNode(ISD::SDIV, getCurSDLoc(), Op1.getValueType(), Op1, - Op2, Flags)); + SDLoc dl(getCurSDLoc()); + EVT VT = Op1.getValueType(); + if (Opcode == ISD::UDIV || Opcode == ISD::UREM) { + Op2 = DAG.getNode(ISD::UMAX, dl, VT, Op2, DAG.getConstant(1, dl, VT)); + } else { + auto &TLI = DAG.getTargetLoweringInfo(); + EVT CCVT = + TLI.getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), VT); + SDValue IsZero = + DAG.getSetCC(dl, CCVT, Op2, DAG.getConstant(0, dl, VT), ISD::SETEQ); + SDValue IsNegOne = + DAG.getSetCC(dl, CCVT, Op2, DAG.getAllOnesConstant(dl, VT), ISD::SETEQ); + auto IntMin = APInt::getSignedMinValue(VT.getScalarSizeInBits()); + SDValue IsIntMin = DAG.getSetCC( + dl, CCVT, Op1, DAG.getConstant(IntMin, dl, VT), ISD::SETEQ); + SDValue IsIntMinOverNegOne = + DAG.getNode(ISD::AND, dl, CCVT, IsNegOne, IsIntMin); + SDValue IsInvalid = + DAG.getNode(ISD::OR, dl, CCVT, IsZero, IsIntMinOverNegOne); + ISD::NodeType SelectOpCode = VT.isVector() ? ISD::VSELECT : ISD::SELECT; + Op2 = DAG.getNode(SelectOpCode, dl, VT, IsInvalid, + DAG.getConstant(1, dl, VT), Op2); + } + + SDNodeFlags DivFlags; + if (auto *ExactOp = dyn_cast(&I)) + DivFlags.setExact(ExactOp->isExact()); + SDValue BinNodeValue = DAG.getNode(Opcode, dl, VT, Op1, Op2, DivFlags); + setValue(&I, BinNodeValue); } void SelectionDAGBuilder::visitICmp(const User &I) { Index: lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -342,47 +342,6 @@ MachineFunctionPass::getAnalysisUsage(AU); } -/// SplitCriticalSideEffectEdges - Look for critical edges with a PHI value that -/// may trap on it. In this case we have to split the edge so that the path -/// through the predecessor block that doesn't go to the phi block doesn't -/// execute the possibly trapping instruction. If available, we pass domtree -/// and loop info to be updated when we split critical edges. This is because -/// SelectionDAGISel preserves these analyses. -/// This is required for correctness, so it must be done at -O0. -/// -static void SplitCriticalSideEffectEdges(Function &Fn, DominatorTree *DT, - LoopInfo *LI) { - // Loop for blocks with phi nodes. - for (BasicBlock &BB : Fn) { - PHINode *PN = dyn_cast(BB.begin()); - if (!PN) continue; - - ReprocessBlock: - // For each block with a PHI node, check to see if any of the input values - // are potentially trapping constant expressions. Constant expressions are - // the only potentially trapping value that can occur as the argument to a - // PHI. - for (BasicBlock::iterator I = BB.begin(); (PN = dyn_cast(I)); ++I) - for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) { - ConstantExpr *CE = dyn_cast(PN->getIncomingValue(i)); - if (!CE || !CE->canTrap()) continue; - - // The only case we have to worry about is when the edge is critical. - // Since this block has a PHI Node, we assume it has multiple input - // edges: check to see if the pred has multiple successors. - BasicBlock *Pred = PN->getIncomingBlock(i); - if (Pred->getTerminator()->getNumSuccessors() == 1) - continue; - - // Okay, we have to split this edge. - SplitCriticalEdge( - Pred->getTerminator(), GetSuccessorNumber(Pred, &BB), - CriticalEdgeSplittingOptions(DT, LI).setMergeIdenticalEdges()); - goto ReprocessBlock; - } - } -} - static void computeUsesMSVCFloatingPoint(const Triple &TT, const Function &F, MachineModuleInfo &MMI) { // Only needed for MSVC @@ -444,8 +403,6 @@ LLVM_DEBUG(dbgs() << "\n\n\n=== " << Fn.getName() << "\n"); - SplitCriticalSideEffectEdges(const_cast(Fn), DT, LI); - CurDAG->init(*MF, *ORE, this, LibInfo, getAnalysisIfAvailable()); FuncInfo->set(Fn, *MF, CurDAG); Index: lib/IR/Constants.cpp =================================================================== --- lib/IR/Constants.cpp +++ lib/IR/Constants.cpp @@ -408,42 +408,6 @@ delete this; } -static bool canTrapImpl(const Constant *C, - SmallPtrSetImpl &NonTrappingOps) { - assert(C->getType()->isFirstClassType() && "Cannot evaluate aggregate vals!"); - // The only thing that could possibly trap are constant exprs. - const ConstantExpr *CE = dyn_cast(C); - if (!CE) - return false; - - // ConstantExpr traps if any operands can trap. - for (unsigned i = 0, e = C->getNumOperands(); i != e; ++i) { - if (ConstantExpr *Op = dyn_cast(CE->getOperand(i))) { - if (NonTrappingOps.insert(Op).second && canTrapImpl(Op, NonTrappingOps)) - return true; - } - } - - // Otherwise, only specific operations can trap. - switch (CE->getOpcode()) { - default: - return false; - case Instruction::UDiv: - case Instruction::SDiv: - case Instruction::URem: - case Instruction::SRem: - // Div and rem can trap if the RHS is not known to be non-zero. - if (!isa(CE->getOperand(1)) ||CE->getOperand(1)->isNullValue()) - return true; - return false; - } -} - -bool Constant::canTrap() const { - SmallPtrSet NonTrappingOps; - return canTrapImpl(this, NonTrappingOps); -} - /// Check if C contains a GlobalValue for which Predicate is true. static bool ConstHasGlobalValuePredicate(const Constant *C, Index: lib/Transforms/Utils/SimplifyCFG.cpp =================================================================== --- lib/Transforms/Utils/SimplifyCFG.cpp +++ lib/Transforms/Utils/SimplifyCFG.cpp @@ -308,7 +308,8 @@ /// expensive. static unsigned ComputeSpeculationCost(const User *I, const TargetTransformInfo &TTI) { - assert(isSafeToSpeculativelyExecute(I) && + assert(!isa(I) || + isSafeToSpeculativelyExecute(cast(I)) && "Instruction is not safe to speculatively execute!"); return TTI.getUserCost(I); } @@ -343,14 +344,8 @@ return false; Instruction *I = dyn_cast(V); - if (!I) { - // Non-instructions all dominate instructions, but not all constantexprs - // can be executed unconditionally. - if (ConstantExpr *C = dyn_cast(V)) - if (C->canTrap()) - return false; + if (!I) return true; - } BasicBlock *PBB = I->getParent(); // We don't want to allow weird loops that might have the "if condition" in @@ -1378,11 +1373,6 @@ if (passingValueIsAlwaysUndefined(BB1V, &PN) || passingValueIsAlwaysUndefined(BB2V, &PN)) return Changed; - - if (isa(BB1V) && !isSafeToSpeculativelyExecute(BB1V)) - return Changed; - if (isa(BB2V) && !isSafeToSpeculativelyExecute(BB2V)) - return Changed; } } @@ -2056,9 +2046,6 @@ if (!OrigCE && !ThenCE) continue; // Known safe and cheap. - if ((ThenCE && !isSafeToSpeculativelyExecute(ThenCE)) || - (OrigCE && !isSafeToSpeculativelyExecute(OrigCE))) - return false; unsigned OrigCost = OrigCE ? ComputeSpeculationCost(OrigCE, TTI) : 0; unsigned ThenCost = ThenCE ? ComputeSpeculationCost(ThenCE, TTI) : 0; unsigned MaxCost = @@ -2467,18 +2454,6 @@ if (FVPN->getParent() == FalseSucc) FalseValue = FVPN->getIncomingValueForBlock(BI->getParent()); - // In order for this transformation to be safe, we must be able to - // unconditionally execute both operands to the return. This is - // normally the case, but we could have a potentially-trapping - // constant expression that prevents this transformation from being - // safe. - if (ConstantExpr *TCV = dyn_cast_or_null(TrueValue)) - if (TCV->canTrap()) - return false; - if (ConstantExpr *FCV = dyn_cast_or_null(FalseValue)) - if (FCV->canTrap()) - return false; - // Okay, we collected all the mapped values and checked them for sanity, and // defined to really do this transformation. First, update the CFG. TrueSucc->removePredecessor(BI->getParent()); @@ -2634,15 +2609,6 @@ return false; } - // Cond is known to be a compare or binary operator. Check to make sure that - // neither operand is a potentially-trapping constant expression. - if (ConstantExpr *CE = dyn_cast(Cond->getOperand(0))) - if (CE->canTrap()) - return false; - if (ConstantExpr *CE = dyn_cast(Cond->getOperand(1))) - if (CE->canTrap()) - return false; - // Finally, don't infinitely unroll conditional loops. BasicBlock *TrueDest = BI->getSuccessor(0); BasicBlock *FalseDest = (BI->isConditional()) ? BI->getSuccessor(1) : nullptr; @@ -3244,10 +3210,6 @@ } } - if (auto *CE = dyn_cast(BI->getCondition())) - if (CE->canTrap()) - return false; - // If both branches are conditional and both contain stores to the same // address, remove the stores from the conditionals and create a conditional // merged store at the end. @@ -3288,29 +3250,12 @@ // Do not perform this transformation if it would require // insertion of a large number of select instructions. For targets // without predication/cmovs, this is a big pessimization. - - // Also do not perform this transformation if any phi node in the common - // destination block can trap when reached by BB or PBB (PR17073). In that - // case, it would be unsafe to hoist the operation into a select instruction. - BasicBlock *CommonDest = PBI->getSuccessor(PBIOp); unsigned NumPhis = 0; for (BasicBlock::iterator II = CommonDest->begin(); isa(II); ++II, ++NumPhis) { if (NumPhis > 2) // Disable this xform. return false; - - PHINode *PN = cast(II); - Value *BIV = PN->getIncomingValueForBlock(BB); - if (ConstantExpr *CE = dyn_cast(BIV)) - if (CE->canTrap()) - return false; - - unsigned PBBIdx = PN->getBasicBlockIndex(PBI->getParent()); - Value *PBIV = PN->getIncomingValue(PBBIdx); - if (ConstantExpr *CE = dyn_cast(PBIV)) - if (CE->canTrap()) - return false; } // Finally, if everything is ok, fold the branches to logical ops. Index: lib/Transforms/Vectorize/LoopVectorizationLegality.cpp =================================================================== --- lib/Transforms/Vectorize/LoopVectorizationLegality.cpp +++ lib/Transforms/Vectorize/LoopVectorizationLegality.cpp @@ -378,20 +378,6 @@ return true; } -/// Check whether it is safe to if-convert this phi node. -/// -/// Phi nodes with constant expressions that can trap are not safe to if -/// convert. -static bool canIfConvertPHINodes(BasicBlock *BB) { - for (PHINode &Phi : BB->phis()) { - for (Value *V : Phi.incoming_values()) - if (auto *C = dyn_cast(V)) - if (C->canTrap()) - return false; - } - return true; -} - static Type *convertPointerToIntegerType(const DataLayout &DL, Type *Ty) { if (Ty->isPointerTy()) return DL.getIntPtrType(Ty); @@ -877,12 +863,6 @@ const bool IsAnnotatedParallel = TheLoop->isAnnotatedParallel(); for (Instruction &I : *BB) { - // Check that we don't have a constant expression that can trap as operand. - for (Value *Operand : I.operands()) { - if (auto *C = dyn_cast(Operand)) - if (C->canTrap()) - return false; - } // We might be able to hoist the load. if (I.mayReadFromMemory()) { auto *LI = dyn_cast(&I); @@ -960,12 +940,6 @@ "NoCFGForSelect", BB->getTerminator()); return false; } - } else if (BB != Header && !canIfConvertPHINodes(BB)) { - reportVectorizationFailure( - "Control flow cannot be substituted for a select", - "control flow cannot be substituted for a select", - "NoCFGForSelect", BB->getTerminator()); - return false; } } Index: test/CodeGen/X86/critical-edge-split-2.ll =================================================================== --- test/CodeGen/X86/critical-edge-split-2.ll +++ test/CodeGen/X86/critical-edge-split-2.ll @@ -21,6 +21,8 @@ ; CHECK-NEXT: cmpq %rax, %rcx ; CHECK-NEXT: sete %sil ; CHECK-NEXT: movl $1, %eax +; CHECK-NEXT: cmovnel %eax, %esi +; CHECK-NEXT: movl $1, %eax ; CHECK-NEXT: xorl %edx, %edx ; CHECK-NEXT: divl %esi ; CHECK-NEXT: movl %edx, %eax Index: test/CodeGen/X86/divide-constant.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/divide-constant.ll @@ -0,0 +1,390 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple=x86_64-linux-gnu -verify-machineinstrs | FileCheck %s -check-prefix=SDAG +; RUN: llc < %s -mtriple=x86_64-linux-gnu -fast-isel -verify-machineinstrs | FileCheck %s -check-prefix=FAST +; RUN: llc < %s -mtriple=x86_64-linux-gnu -global-isel -global-isel-abort=0 -verify-machineinstrs | FileCheck %s -check-prefix=GLOBAL + +@g1 = extern_weak global i32 +@g2 = extern_weak global i32 + +define i32 @test1(i1 %c) { +; SDAG-LABEL: test1: +; SDAG: # %bb.0: # %entry +; SDAG-NEXT: movl $g1, %eax +; SDAG-NEXT: xorl $-2147483648, %eax # imm = 0x80000000 +; SDAG-NEXT: movl $g2, %esi +; SDAG-NEXT: movl $g2, %ecx +; SDAG-NEXT: notl %ecx +; SDAG-NEXT: orl %eax, %ecx +; SDAG-NEXT: sete %al +; SDAG-NEXT: testl %esi, %esi +; SDAG-NEXT: sete %cl +; SDAG-NEXT: orb %al, %cl +; SDAG-NEXT: movl $1, %ecx +; SDAG-NEXT: cmovnel %ecx, %esi +; SDAG-NEXT: movl $g1, %eax +; SDAG-NEXT: cltd +; SDAG-NEXT: idivl %esi +; SDAG-NEXT: testb $1, %dil +; SDAG-NEXT: je .LBB0_2 +; SDAG-NEXT: # %bb.1: +; SDAG-NEXT: movl %eax, %ecx +; SDAG-NEXT: .LBB0_2: # %cond.end.i +; SDAG-NEXT: movl %ecx, %eax +; SDAG-NEXT: retq +; +; FAST-LABEL: test1: +; FAST: # %bb.0: # %entry +; FAST-NEXT: movl $g1, %eax +; FAST-NEXT: xorl $-2147483648, %eax # imm = 0x80000000 +; FAST-NEXT: movl $g2, %esi +; FAST-NEXT: movl $g2, %ecx +; FAST-NEXT: notl %ecx +; FAST-NEXT: orl %eax, %ecx +; FAST-NEXT: sete %al +; FAST-NEXT: testl %esi, %esi +; FAST-NEXT: sete %cl +; FAST-NEXT: orb %al, %cl +; FAST-NEXT: movl $1, %ecx +; FAST-NEXT: cmovnel %ecx, %esi +; FAST-NEXT: movl $g1, %eax +; FAST-NEXT: cltd +; FAST-NEXT: idivl %esi +; FAST-NEXT: testb $1, %dil +; FAST-NEXT: je .LBB0_2 +; FAST-NEXT: # %bb.1: +; FAST-NEXT: movl %eax, %ecx +; FAST-NEXT: .LBB0_2: # %cond.end.i +; FAST-NEXT: movl %ecx, %eax +; FAST-NEXT: retq +; +; GLOBAL-LABEL: test1: +; GLOBAL: # %bb.0: # %entry +; GLOBAL-NEXT: movl $g1, %eax +; GLOBAL-NEXT: xorl $-2147483648, %eax # imm = 0x80000000 +; GLOBAL-NEXT: movl $g2, %esi +; GLOBAL-NEXT: movl $g2, %ecx +; GLOBAL-NEXT: notl %ecx +; GLOBAL-NEXT: orl %eax, %ecx +; GLOBAL-NEXT: sete %al +; GLOBAL-NEXT: testl %esi, %esi +; GLOBAL-NEXT: sete %cl +; GLOBAL-NEXT: orb %al, %cl +; GLOBAL-NEXT: movl $1, %ecx +; GLOBAL-NEXT: cmovnel %ecx, %esi +; GLOBAL-NEXT: movl $g1, %eax +; GLOBAL-NEXT: cltd +; GLOBAL-NEXT: idivl %esi +; GLOBAL-NEXT: testb $1, %dil +; GLOBAL-NEXT: je .LBB0_2 +; GLOBAL-NEXT: # %bb.1: +; GLOBAL-NEXT: movl %eax, %ecx +; GLOBAL-NEXT: .LBB0_2: # %cond.end.i +; GLOBAL-NEXT: movl %ecx, %eax +; GLOBAL-NEXT: retq +entry: + br i1 %c, label %cond.end.i, label %cond.false.i + +cond.false.i: + br label %cond.end.i + +cond.end.i: + %r = phi i32 [ sdiv (i32 ptrtoint (i32* @g1 to i32), i32 ptrtoint (i32* @g2 to i32)), %entry ], [ 1, %cond.false.i ] + ret i32 %r +} + +define i32 @test2(i1 %c) { +; SDAG-LABEL: test2: +; SDAG: # %bb.0: # %entry +; SDAG-NEXT: movl $g2, %esi +; SDAG-NEXT: cmpl $1, %esi +; SDAG-NEXT: movl $1, %ecx +; SDAG-NEXT: cmovbel %ecx, %esi +; SDAG-NEXT: movl $g1, %eax +; SDAG-NEXT: xorl %edx, %edx +; SDAG-NEXT: divl %esi +; SDAG-NEXT: testb $1, %dil +; SDAG-NEXT: je .LBB1_2 +; SDAG-NEXT: # %bb.1: +; SDAG-NEXT: movl %eax, %ecx +; SDAG-NEXT: .LBB1_2: # %cond.end.i +; SDAG-NEXT: movl %ecx, %eax +; SDAG-NEXT: retq +; +; FAST-LABEL: test2: +; FAST: # %bb.0: # %entry +; FAST-NEXT: movl $g2, %esi +; FAST-NEXT: cmpl $1, %esi +; FAST-NEXT: movl $1, %ecx +; FAST-NEXT: cmovbel %ecx, %esi +; FAST-NEXT: movl $g1, %eax +; FAST-NEXT: xorl %edx, %edx +; FAST-NEXT: divl %esi +; FAST-NEXT: testb $1, %dil +; FAST-NEXT: je .LBB1_2 +; FAST-NEXT: # %bb.1: +; FAST-NEXT: movl %eax, %ecx +; FAST-NEXT: .LBB1_2: # %cond.end.i +; FAST-NEXT: movl %ecx, %eax +; FAST-NEXT: retq +; +; GLOBAL-LABEL: test2: +; GLOBAL: # %bb.0: # %entry +; GLOBAL-NEXT: movl $g2, %esi +; GLOBAL-NEXT: cmpl $1, %esi +; GLOBAL-NEXT: movl $1, %ecx +; GLOBAL-NEXT: cmovbel %ecx, %esi +; GLOBAL-NEXT: movl $g1, %eax +; GLOBAL-NEXT: xorl %edx, %edx +; GLOBAL-NEXT: divl %esi +; GLOBAL-NEXT: testb $1, %dil +; GLOBAL-NEXT: je .LBB1_2 +; GLOBAL-NEXT: # %bb.1: +; GLOBAL-NEXT: movl %eax, %ecx +; GLOBAL-NEXT: .LBB1_2: # %cond.end.i +; GLOBAL-NEXT: movl %ecx, %eax +; GLOBAL-NEXT: retq +entry: + br i1 %c, label %cond.end.i, label %cond.false.i + +cond.false.i: + br label %cond.end.i + +cond.end.i: + %r = phi i32 [ udiv (i32 ptrtoint (i32* @g1 to i32), i32 ptrtoint (i32* @g2 to i32)), %entry ], [ 1, %cond.false.i ] + ret i32 %r +} + +define i32 @test3(i1 %c) { +; SDAG-LABEL: test3: +; SDAG: # %bb.0: # %entry +; SDAG-NEXT: movl $g1, %eax +; SDAG-NEXT: xorl $-2147483648, %eax # imm = 0x80000000 +; SDAG-NEXT: movl $g2, %esi +; SDAG-NEXT: movl $g2, %ecx +; SDAG-NEXT: notl %ecx +; SDAG-NEXT: orl %eax, %ecx +; SDAG-NEXT: sete %al +; SDAG-NEXT: testl %esi, %esi +; SDAG-NEXT: sete %cl +; SDAG-NEXT: orb %al, %cl +; SDAG-NEXT: movl $1, %ecx +; SDAG-NEXT: cmovnel %ecx, %esi +; SDAG-NEXT: movl $g1, %eax +; SDAG-NEXT: cltd +; SDAG-NEXT: idivl %esi +; SDAG-NEXT: testb $1, %dil +; SDAG-NEXT: je .LBB2_2 +; SDAG-NEXT: # %bb.1: +; SDAG-NEXT: movl %edx, %ecx +; SDAG-NEXT: .LBB2_2: # %cond.end.i +; SDAG-NEXT: movl %ecx, %eax +; SDAG-NEXT: retq +; +; FAST-LABEL: test3: +; FAST: # %bb.0: # %entry +; FAST-NEXT: movl $g1, %eax +; FAST-NEXT: xorl $-2147483648, %eax # imm = 0x80000000 +; FAST-NEXT: movl $g2, %esi +; FAST-NEXT: movl $g2, %ecx +; FAST-NEXT: notl %ecx +; FAST-NEXT: orl %eax, %ecx +; FAST-NEXT: sete %al +; FAST-NEXT: testl %esi, %esi +; FAST-NEXT: sete %cl +; FAST-NEXT: orb %al, %cl +; FAST-NEXT: movl $1, %ecx +; FAST-NEXT: cmovnel %ecx, %esi +; FAST-NEXT: movl $g1, %eax +; FAST-NEXT: cltd +; FAST-NEXT: idivl %esi +; FAST-NEXT: testb $1, %dil +; FAST-NEXT: je .LBB2_2 +; FAST-NEXT: # %bb.1: +; FAST-NEXT: movl %edx, %ecx +; FAST-NEXT: .LBB2_2: # %cond.end.i +; FAST-NEXT: movl %ecx, %eax +; FAST-NEXT: retq +; +; GLOBAL-LABEL: test3: +; GLOBAL: # %bb.0: # %entry +; GLOBAL-NEXT: movl $g1, %eax +; GLOBAL-NEXT: xorl $-2147483648, %eax # imm = 0x80000000 +; GLOBAL-NEXT: movl $g2, %esi +; GLOBAL-NEXT: movl $g2, %ecx +; GLOBAL-NEXT: notl %ecx +; GLOBAL-NEXT: orl %eax, %ecx +; GLOBAL-NEXT: sete %al +; GLOBAL-NEXT: testl %esi, %esi +; GLOBAL-NEXT: sete %cl +; GLOBAL-NEXT: orb %al, %cl +; GLOBAL-NEXT: movl $1, %ecx +; GLOBAL-NEXT: cmovnel %ecx, %esi +; GLOBAL-NEXT: movl $g1, %eax +; GLOBAL-NEXT: cltd +; GLOBAL-NEXT: idivl %esi +; GLOBAL-NEXT: testb $1, %dil +; GLOBAL-NEXT: je .LBB2_2 +; GLOBAL-NEXT: # %bb.1: +; GLOBAL-NEXT: movl %edx, %ecx +; GLOBAL-NEXT: .LBB2_2: # %cond.end.i +; GLOBAL-NEXT: movl %ecx, %eax +; GLOBAL-NEXT: retq +entry: + br i1 %c, label %cond.end.i, label %cond.false.i + +cond.false.i: + br label %cond.end.i + +cond.end.i: + %r = phi i32 [ srem (i32 ptrtoint (i32* @g1 to i32), i32 ptrtoint (i32* @g2 to i32)), %entry ], [ 1, %cond.false.i ] + ret i32 %r +} + +define i32 @test4(i1 %c) { +; SDAG-LABEL: test4: +; SDAG: # %bb.0: # %entry +; SDAG-NEXT: movl $g2, %esi +; SDAG-NEXT: cmpl $1, %esi +; SDAG-NEXT: movl $1, %ecx +; SDAG-NEXT: cmovbel %ecx, %esi +; SDAG-NEXT: movl $g1, %eax +; SDAG-NEXT: xorl %edx, %edx +; SDAG-NEXT: divl %esi +; SDAG-NEXT: testb $1, %dil +; SDAG-NEXT: je .LBB3_2 +; SDAG-NEXT: # %bb.1: +; SDAG-NEXT: movl %edx, %ecx +; SDAG-NEXT: .LBB3_2: # %cond.end.i +; SDAG-NEXT: movl %ecx, %eax +; SDAG-NEXT: retq +; +; FAST-LABEL: test4: +; FAST: # %bb.0: # %entry +; FAST-NEXT: movl $g2, %esi +; FAST-NEXT: cmpl $1, %esi +; FAST-NEXT: movl $1, %ecx +; FAST-NEXT: cmovbel %ecx, %esi +; FAST-NEXT: movl $g1, %eax +; FAST-NEXT: xorl %edx, %edx +; FAST-NEXT: divl %esi +; FAST-NEXT: testb $1, %dil +; FAST-NEXT: je .LBB3_2 +; FAST-NEXT: # %bb.1: +; FAST-NEXT: movl %edx, %ecx +; FAST-NEXT: .LBB3_2: # %cond.end.i +; FAST-NEXT: movl %ecx, %eax +; FAST-NEXT: retq +; +; GLOBAL-LABEL: test4: +; GLOBAL: # %bb.0: # %entry +; GLOBAL-NEXT: movl $g2, %esi +; GLOBAL-NEXT: cmpl $1, %esi +; GLOBAL-NEXT: movl $1, %ecx +; GLOBAL-NEXT: cmovbel %ecx, %esi +; GLOBAL-NEXT: movl $g1, %eax +; GLOBAL-NEXT: xorl %edx, %edx +; GLOBAL-NEXT: divl %esi +; GLOBAL-NEXT: testb $1, %dil +; GLOBAL-NEXT: je .LBB3_2 +; GLOBAL-NEXT: # %bb.1: +; GLOBAL-NEXT: movl %edx, %ecx +; GLOBAL-NEXT: .LBB3_2: # %cond.end.i +; GLOBAL-NEXT: movl %ecx, %eax +; GLOBAL-NEXT: retq +entry: + br i1 %c, label %cond.end.i, label %cond.false.i + +cond.false.i: + br label %cond.end.i + +cond.end.i: + %r = phi i32 [ urem (i32 ptrtoint (i32* @g1 to i32), i32 ptrtoint (i32* @g2 to i32)), %entry ], [ 1, %cond.false.i ] + ret i32 %r +} + +define i32 @test5(i32 %c) { +; SDAG-LABEL: test5: +; SDAG: # %bb.0: # %entry +; SDAG-NEXT: movl $g1, %eax +; SDAG-NEXT: xorl $-2147483648, %eax # imm = 0x80000000 +; SDAG-NEXT: movl $g2, %ecx +; SDAG-NEXT: movl $g2, %edx +; SDAG-NEXT: notl %edx +; SDAG-NEXT: orl %eax, %edx +; SDAG-NEXT: sete %al +; SDAG-NEXT: testl %ecx, %ecx +; SDAG-NEXT: sete %dl +; SDAG-NEXT: orb %al, %dl +; SDAG-NEXT: movl $1, %eax +; SDAG-NEXT: cmovnel %eax, %ecx +; SDAG-NEXT: movl $g1, %eax +; SDAG-NEXT: cltd +; SDAG-NEXT: idivl %ecx +; SDAG-NEXT: #APP +; SDAG-NEXT: #NO_APP +; SDAG-NEXT: .Ltmp0: # Block address taken +; SDAG-NEXT: .LBB4_1: # %cond.false.i +; SDAG-NEXT: movl $1, %eax +; SDAG-NEXT: .LBB4_2: # %cond.end.i +; SDAG-NEXT: retq +; +; FAST-LABEL: test5: +; FAST: # %bb.0: # %entry +; FAST-NEXT: movl $g1, %eax +; FAST-NEXT: xorl $-2147483648, %eax # imm = 0x80000000 +; FAST-NEXT: movl $g2, %ecx +; FAST-NEXT: movl $g2, %edx +; FAST-NEXT: notl %edx +; FAST-NEXT: orl %eax, %edx +; FAST-NEXT: sete %al +; FAST-NEXT: testl %ecx, %ecx +; FAST-NEXT: sete %dl +; FAST-NEXT: orb %al, %dl +; FAST-NEXT: movl $1, %eax +; FAST-NEXT: cmovnel %eax, %ecx +; FAST-NEXT: movl $g1, %eax +; FAST-NEXT: cltd +; FAST-NEXT: idivl %ecx +; FAST-NEXT: #APP +; FAST-NEXT: #NO_APP +; FAST-NEXT: .Ltmp0: # Block address taken +; FAST-NEXT: .LBB4_1: # %cond.false.i +; FAST-NEXT: movl $1, %eax +; FAST-NEXT: .LBB4_2: # %cond.end.i +; FAST-NEXT: retq +; +; GLOBAL-LABEL: test5: +; GLOBAL: # %bb.0: # %entry +; GLOBAL-NEXT: movl $g1, %eax +; GLOBAL-NEXT: xorl $-2147483648, %eax # imm = 0x80000000 +; GLOBAL-NEXT: movl $g2, %ecx +; GLOBAL-NEXT: movl $g2, %edx +; GLOBAL-NEXT: notl %edx +; GLOBAL-NEXT: orl %eax, %edx +; GLOBAL-NEXT: sete %al +; GLOBAL-NEXT: testl %ecx, %ecx +; GLOBAL-NEXT: sete %dl +; GLOBAL-NEXT: orb %al, %dl +; GLOBAL-NEXT: movl $1, %eax +; GLOBAL-NEXT: cmovnel %eax, %ecx +; GLOBAL-NEXT: movl $g1, %eax +; GLOBAL-NEXT: cltd +; GLOBAL-NEXT: idivl %ecx +; GLOBAL-NEXT: #APP +; GLOBAL-NEXT: #NO_APP +; GLOBAL-NEXT: .Ltmp0: # Block address taken +; GLOBAL-NEXT: .LBB4_1: # %cond.false.i +; GLOBAL-NEXT: movl $1, %eax +; GLOBAL-NEXT: .LBB4_2: # %cond.end.i +; GLOBAL-NEXT: retq +entry: + callbr void asm "", "r,X"(i32 %c, i8 *blockaddress(@test5, %cond.false.i)) + to label %cond.false.i [label %cond.end.i] + +cond.false.i: + br label %cond.end.i + +cond.end.i: + %r = phi i32 [ sdiv (i32 ptrtoint (i32* @g1 to i32), i32 ptrtoint (i32* @g2 to i32)), %entry ], [ 1, %cond.false.i ] + ret i32 %r +}