+/// GetSelectFoldableOperands - We want to turn code that looks like this:
+/// %C = or %A, %B
+/// %D = select %cond, %C, %A
+/// into:
+/// %C = select %cond, %B, 0
+/// %D = or %A, %C
+///
+/// Assuming that the specified instruction is an operand to the select, return
+/// a bitmask indicating which operands of this instruction are foldable if they
+/// equal the other incoming value of the select.
+///
+static unsigned GetSelectFoldableOperands(Instruction *I) {
+ switch (I->getOpcode()) {
+ case Instruction::Add:
+ case Instruction::Mul:
+ case Instruction::And:
+ case Instruction::Or:
+ case Instruction::Xor:
+ return 3; // Can fold through either operand.
+ case Instruction::Sub: // Can only fold on the amount subtracted.
+ case Instruction::Shl: // Can only fold on the shift amount.
+ case Instruction::Shr:
+ return 1;
+ default:
+ return 0; // Cannot fold
+ }
+}
+
+/// GetSelectFoldableConstant - For the same transformation as the previous
+/// function, return the identity constant that goes into the select.
+static Constant *GetSelectFoldableConstant(Instruction *I) {
+ switch (I->getOpcode()) {
+ default: assert(0 && "This cannot happen!"); abort();
+ case Instruction::Add:
+ case Instruction::Sub:
+ case Instruction::Or:
+ case Instruction::Xor:
+ return Constant::getNullValue(I->getType());
+ case Instruction::Shl:
+ case Instruction::Shr:
+ return Constant::getNullValue(Type::UByteTy);
+ case Instruction::And:
+ return ConstantInt::getAllOnesValue(I->getType());
+ case Instruction::Mul:
+ return ConstantInt::get(I->getType(), 1);
+ }
+}
+
+Instruction *InstCombiner::visitSelectInst(SelectInst &SI) {
+ Value *CondVal = SI.getCondition();
+ Value *TrueVal = SI.getTrueValue();
+ Value *FalseVal = SI.getFalseValue();
+
+ // select true, X, Y -> X
+ // select false, X, Y -> Y
+ if (ConstantBool *C = dyn_cast<ConstantBool>(CondVal))
+ if (C == ConstantBool::True)
+ return ReplaceInstUsesWith(SI, TrueVal);
+ else {
+ assert(C == ConstantBool::False);
+ return ReplaceInstUsesWith(SI, FalseVal);
+ }
+
+ // select C, X, X -> X
+ if (TrueVal == FalseVal)
+ return ReplaceInstUsesWith(SI, TrueVal);
+
+ if (SI.getType() == Type::BoolTy)
+ if (ConstantBool *C = dyn_cast<ConstantBool>(TrueVal)) {
+ if (C == ConstantBool::True) {
+ // Change: A = select B, true, C --> A = or B, C
+ return BinaryOperator::create(Instruction::Or, CondVal, FalseVal);
+ } else {
+ // Change: A = select B, false, C --> A = and !B, C
+ Value *NotCond =
+ InsertNewInstBefore(BinaryOperator::createNot(CondVal,
+ "not."+CondVal->getName()), SI);
+ return BinaryOperator::create(Instruction::And, NotCond, FalseVal);
+ }
+ } else if (ConstantBool *C = dyn_cast<ConstantBool>(FalseVal)) {
+ if (C == ConstantBool::False) {
+ // Change: A = select B, C, false --> A = and B, C
+ return BinaryOperator::create(Instruction::And, CondVal, TrueVal);
+ } else {
+ // Change: A = select B, C, true --> A = or !B, C
+ Value *NotCond =
+ InsertNewInstBefore(BinaryOperator::createNot(CondVal,
+ "not."+CondVal->getName()), SI);
+ return BinaryOperator::create(Instruction::Or, NotCond, TrueVal);
+ }
+ }
+
+ // Selecting between two integer constants?
+ if (ConstantInt *TrueValC = dyn_cast<ConstantInt>(TrueVal))
+ if (ConstantInt *FalseValC = dyn_cast<ConstantInt>(FalseVal)) {
+ // select C, 1, 0 -> cast C to int
+ if (FalseValC->isNullValue() && TrueValC->getRawValue() == 1) {
+ return new CastInst(CondVal, SI.getType());
+ } else if (TrueValC->isNullValue() && FalseValC->getRawValue() == 1) {
+ // select C, 0, 1 -> cast !C to int
+ Value *NotCond =
+ InsertNewInstBefore(BinaryOperator::createNot(CondVal,
+ "not."+CondVal->getName()), SI);
+ return new CastInst(NotCond, SI.getType());
+ }
+ }
+
+ // See if we are selecting two values based on a comparison of the two values.
+ if (SetCondInst *SCI = dyn_cast<SetCondInst>(CondVal)) {
+ if (SCI->getOperand(0) == TrueVal && SCI->getOperand(1) == FalseVal) {
+ // Transform (X == Y) ? X : Y -> Y
+ if (SCI->getOpcode() == Instruction::SetEQ)
+ return ReplaceInstUsesWith(SI, FalseVal);
+ // Transform (X != Y) ? X : Y -> X
+ if (SCI->getOpcode() == Instruction::SetNE)
+ return ReplaceInstUsesWith(SI, TrueVal);
+ // NOTE: if we wanted to, this is where to detect MIN/MAX/ABS/etc.
+
+ } else if (SCI->getOperand(0) == FalseVal && SCI->getOperand(1) == TrueVal){
+ // Transform (X == Y) ? Y : X -> X
+ if (SCI->getOpcode() == Instruction::SetEQ)
+ return ReplaceInstUsesWith(SI, FalseVal);
+ // Transform (X != Y) ? Y : X -> Y
+ if (SCI->getOpcode() == Instruction::SetNE)
+ return ReplaceInstUsesWith(SI, TrueVal);
+ // NOTE: if we wanted to, this is where to detect MIN/MAX/ABS/etc.
+ }
+ }
+
+ // See if we can fold the select into one of our operands.
+ if (SI.getType()->isInteger()) {
+ // See the comment above GetSelectFoldableOperands for a description of the
+ // transformation we are doing here.
+ if (Instruction *TVI = dyn_cast<Instruction>(TrueVal))
+ if (TVI->hasOneUse() && TVI->getNumOperands() == 2 &&
+ !isa<Constant>(FalseVal))
+ if (unsigned SFO = GetSelectFoldableOperands(TVI)) {
+ unsigned OpToFold = 0;
+ if ((SFO & 1) && FalseVal == TVI->getOperand(0)) {
+ OpToFold = 1;
+ } else if ((SFO & 2) && FalseVal == TVI->getOperand(1)) {
+ OpToFold = 2;
+ }
+
+ if (OpToFold) {
+ Constant *C = GetSelectFoldableConstant(TVI);
+ std::string Name = TVI->getName(); TVI->setName("");
+ Instruction *NewSel =
+ new SelectInst(SI.getCondition(), TVI->getOperand(2-OpToFold), C,
+ Name);
+ InsertNewInstBefore(NewSel, SI);
+ if (BinaryOperator *BO = dyn_cast<BinaryOperator>(TVI))
+ return BinaryOperator::create(BO->getOpcode(), FalseVal, NewSel);
+ else if (ShiftInst *SI = dyn_cast<ShiftInst>(TVI))
+ return new ShiftInst(SI->getOpcode(), FalseVal, NewSel);
+ else {
+ assert(0 && "Unknown instruction!!");
+ }
+ }
+ }
+
+ if (Instruction *FVI = dyn_cast<Instruction>(FalseVal))
+ if (FVI->hasOneUse() && FVI->getNumOperands() == 2 &&
+ !isa<Constant>(TrueVal))
+ if (unsigned SFO = GetSelectFoldableOperands(FVI)) {
+ unsigned OpToFold = 0;
+ if ((SFO & 1) && TrueVal == FVI->getOperand(0)) {
+ OpToFold = 1;
+ } else if ((SFO & 2) && TrueVal == FVI->getOperand(1)) {
+ OpToFold = 2;
+ }
+
+ if (OpToFold) {
+ Constant *C = GetSelectFoldableConstant(FVI);
+ std::string Name = FVI->getName(); FVI->setName("");
+ Instruction *NewSel =
+ new SelectInst(SI.getCondition(), C, FVI->getOperand(2-OpToFold),
+ Name);
+ InsertNewInstBefore(NewSel, SI);
+ if (BinaryOperator *BO = dyn_cast<BinaryOperator>(FVI))
+ return BinaryOperator::create(BO->getOpcode(), TrueVal, NewSel);
+ else if (ShiftInst *SI = dyn_cast<ShiftInst>(FVI))
+ return new ShiftInst(SI->getOpcode(), TrueVal, NewSel);
+ else {
+ assert(0 && "Unknown instruction!!");
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+