+
+ // If this is an argument, we can export it if the BB is the entry block or
+ // if it is already exported.
+ if (isa<Argument>(V)) {
+ if (FromBB == &FromBB->getParent()->getEntryBlock())
+ return true;
+
+ // Otherwise, can only export this if it is already exported.
+ return FuncInfo.isExportedInst(V);
+ }
+
+ // Otherwise, constants can always be exported.
+ return true;
+}
+
+static bool InBlock(const Value *V, const BasicBlock *BB) {
+ if (const Instruction *I = dyn_cast<Instruction>(V))
+ return I->getParent() == BB;
+ return true;
+}
+
+/// FindMergedConditions - If Cond is an expression like
+void SelectionDAGLowering::FindMergedConditions(Value *Cond,
+ MachineBasicBlock *TBB,
+ MachineBasicBlock *FBB,
+ MachineBasicBlock *CurBB,
+ unsigned Opc) {
+ // If this node is not part of the or/and tree, emit it as a branch.
+ BinaryOperator *BOp = dyn_cast<BinaryOperator>(Cond);
+
+ if (!BOp || (unsigned)BOp->getOpcode() != Opc || !BOp->hasOneUse() ||
+ BOp->getParent() != CurBB->getBasicBlock() ||
+ !InBlock(BOp->getOperand(0), CurBB->getBasicBlock()) ||
+ !InBlock(BOp->getOperand(1), CurBB->getBasicBlock())) {
+ const BasicBlock *BB = CurBB->getBasicBlock();
+
+ if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(Cond))
+ if ((II->getIntrinsicID() == Intrinsic::isunordered_f32 ||
+ II->getIntrinsicID() == Intrinsic::isunordered_f64) &&
+ // The operands of the setcc have to be in this block. We don't know
+ // how to export them from some other block. If this is the first
+ // block of the sequence, no exporting is needed.
+ (CurBB == CurMBB ||
+ (isExportableFromCurrentBlock(II->getOperand(1), BB) &&
+ isExportableFromCurrentBlock(II->getOperand(2), BB)))) {
+ SelectionDAGISel::CaseBlock CB(ISD::SETUO, II->getOperand(1),
+ II->getOperand(2), TBB, FBB, CurBB);
+ SwitchCases.push_back(CB);
+ return;
+ }
+
+
+ // If the leaf of the tree is a setcond inst, merge the condition into the
+ // caseblock.
+ if (BOp && isa<SetCondInst>(BOp) &&
+ // The operands of the setcc have to be in this block. We don't know
+ // how to export them from some other block. If this is the first block
+ // of the sequence, no exporting is needed.
+ (CurBB == CurMBB ||
+ (isExportableFromCurrentBlock(BOp->getOperand(0), BB) &&
+ isExportableFromCurrentBlock(BOp->getOperand(1), BB)))) {
+ ISD::CondCode SignCond, UnsCond, FPCond, Condition;
+ switch (BOp->getOpcode()) {
+ default: assert(0 && "Unknown setcc opcode!");
+ case Instruction::SetEQ:
+ SignCond = ISD::SETEQ;
+ UnsCond = ISD::SETEQ;
+ FPCond = ISD::SETOEQ;
+ break;
+ case Instruction::SetNE:
+ SignCond = ISD::SETNE;
+ UnsCond = ISD::SETNE;
+ FPCond = ISD::SETUNE;
+ break;
+ case Instruction::SetLE:
+ SignCond = ISD::SETLE;
+ UnsCond = ISD::SETULE;
+ FPCond = ISD::SETOLE;
+ break;
+ case Instruction::SetGE:
+ SignCond = ISD::SETGE;
+ UnsCond = ISD::SETUGE;
+ FPCond = ISD::SETOGE;
+ break;
+ case Instruction::SetLT:
+ SignCond = ISD::SETLT;
+ UnsCond = ISD::SETULT;
+ FPCond = ISD::SETOLT;
+ break;
+ case Instruction::SetGT:
+ SignCond = ISD::SETGT;
+ UnsCond = ISD::SETUGT;
+ FPCond = ISD::SETOGT;
+ break;
+ }
+
+ const Type *OpType = BOp->getOperand(0)->getType();
+ if (const PackedType *PTy = dyn_cast<PackedType>(OpType))
+ OpType = PTy->getElementType();
+
+ if (!FiniteOnlyFPMath() && OpType->isFloatingPoint())
+ Condition = FPCond;
+ else if (OpType->isUnsigned())
+ Condition = UnsCond;
+ else
+ Condition = SignCond;
+
+ SelectionDAGISel::CaseBlock CB(Condition, BOp->getOperand(0),
+ BOp->getOperand(1), TBB, FBB, CurBB);
+ SwitchCases.push_back(CB);
+ return;
+ }
+
+ // Create a CaseBlock record representing this branch.
+ SelectionDAGISel::CaseBlock CB(ISD::SETEQ, Cond, ConstantBool::getTrue(),
+ TBB, FBB, CurBB);
+ SwitchCases.push_back(CB);
+ return;
+ }
+
+
+ // Create TmpBB after CurBB.
+ MachineFunction::iterator BBI = CurBB;
+ MachineBasicBlock *TmpBB = new MachineBasicBlock(CurBB->getBasicBlock());
+ CurBB->getParent()->getBasicBlockList().insert(++BBI, TmpBB);
+
+ if (Opc == Instruction::Or) {
+ // Codegen X | Y as:
+ // jmp_if_X TBB
+ // jmp TmpBB
+ // TmpBB:
+ // jmp_if_Y TBB
+ // jmp FBB
+ //
+
+ // Emit the LHS condition.
+ FindMergedConditions(BOp->getOperand(0), TBB, TmpBB, CurBB, Opc);
+
+ // Emit the RHS condition into TmpBB.
+ FindMergedConditions(BOp->getOperand(1), TBB, FBB, TmpBB, Opc);
+ } else {
+ assert(Opc == Instruction::And && "Unknown merge op!");
+ // Codegen X & Y as:
+ // jmp_if_X TmpBB
+ // jmp FBB
+ // TmpBB:
+ // jmp_if_Y TBB
+ // jmp FBB
+ //
+ // This requires creation of TmpBB after CurBB.
+
+ // Emit the LHS condition.
+ FindMergedConditions(BOp->getOperand(0), TmpBB, FBB, CurBB, Opc);
+
+ // Emit the RHS condition into TmpBB.
+ FindMergedConditions(BOp->getOperand(1), TBB, FBB, TmpBB, Opc);
+ }
+}
+
+/// If the set of cases should be emitted as a series of branches, return true.
+/// If we should emit this as a bunch of and/or'd together conditions, return
+/// false.
+static bool
+ShouldEmitAsBranches(const std::vector<SelectionDAGISel::CaseBlock> &Cases) {
+ if (Cases.size() != 2) return true;
+
+ // If this is two comparisons of the same values or'd or and'd together, they
+ // will get folded into a single comparison, so don't emit two blocks.
+ if ((Cases[0].CmpLHS == Cases[1].CmpLHS &&
+ Cases[0].CmpRHS == Cases[1].CmpRHS) ||
+ (Cases[0].CmpRHS == Cases[1].CmpLHS &&
+ Cases[0].CmpLHS == Cases[1].CmpRHS)) {
+ return false;
+ }
+
+ return true;