findAndMakeBaseConstant(MinValItr, ConstCandVec.end());
}
+/// \brief Updates the operand at Idx in instruction Inst with the result of
+/// instruction Mat. If the instruction is a PHI node then special
+/// handling for duplicate values form the same incomming basic block is
+/// required.
+/// \return The update will always succeed, but the return value indicated if
+/// Mat was used for the update or not.
+static bool updateOperand(Instruction *Inst, unsigned Idx, Instruction *Mat) {
+ if (auto PHI = dyn_cast<PHINode>(Inst)) {
+ // Check if any previous operand of the PHI node has the same incoming basic
+ // block. This is a very odd case that happens when the incoming basic block
+ // has a switch statement. In this case use the same value as the previous
+ // operand(s), otherwise we will fail verification due to different values.
+ // The values are actually the same, but the variable names are different
+ // and the verifier doesn't like that.
+ BasicBlock *IncomingBB = PHI->getIncomingBlock(Idx);
+ for (unsigned i = 0; i < Idx; ++i) {
+ if (PHI->getIncomingBlock(i) == IncomingBB) {
+ Value *IncomingVal = PHI->getIncomingValue(i);
+ Inst->setOperand(Idx, IncomingVal);
+ return false;
+ }
+ }
+ }
+
+ Inst->setOperand(Idx, Mat);
+ return true;
+}
+
/// \brief Emit materialization code for all rebased constants and update their
/// users.
void ConstantHoisting::emitBaseConstants(Instruction *Base, Constant *Offset,
// Visit constant integer.
if (isa<ConstantInt>(Opnd)) {
DEBUG(dbgs() << "Update: " << *ConstUser.Inst << '\n');
- ConstUser.Inst->setOperand(ConstUser.OpndIdx, Mat);
+ if (!updateOperand(ConstUser.Inst, ConstUser.OpndIdx, Mat) && Offset)
+ Mat->eraseFromParent();
DEBUG(dbgs() << "To : " << *ConstUser.Inst << '\n');
return;
}
}
DEBUG(dbgs() << "Update: " << *ConstUser.Inst << '\n');
- ConstUser.Inst->setOperand(ConstUser.OpndIdx, ClonedCastInst);
+ updateOperand(ConstUser.Inst, ConstUser.OpndIdx, ClonedCastInst);
DEBUG(dbgs() << "To : " << *ConstUser.Inst << '\n');
return;
}
DEBUG(dbgs() << "Create instruction: " << *ConstExprInst << '\n'
<< "From : " << *ConstExpr << '\n');
DEBUG(dbgs() << "Update: " << *ConstUser.Inst << '\n');
- ConstUser.Inst->setOperand(ConstUser.OpndIdx, ConstExprInst);
+ if (!updateOperand(ConstUser.Inst, ConstUser.OpndIdx, ConstExprInst)) {
+ ConstExprInst->eraseFromParent();
+ if (Offset)
+ Mat->eraseFromParent();
+ }
DEBUG(dbgs() << "To : " << *ConstUser.Inst << '\n');
return;
}
if.end9: ; preds = %if.then8, %if.end3
ret i32 undef
}
+
+; <rdar://problem/16394449>
+define i64 @switch_test1(i64 %a) {
+; CHECK-LABEL: @switch_test1
+; CHECK: %0 = phi i64 [ %const, %case2 ], [ %const_mat, %Entry ], [ %const_mat, %Entry ]
+Entry:
+ %sel = add i64 %a, 4519019440
+ switch i64 %sel, label %fail [
+ i64 462, label %continuation
+ i64 449, label %case2
+ i64 443, label %continuation
+ ]
+
+case2:
+ br label %continuation
+
+continuation:
+ %0 = phi i64 [ 4519019440, %case2 ], [ 4519019460, %Entry ], [ 4519019460, %Entry ]
+ ret i64 0;
+
+fail:
+ ret i64 -1;
+}
+
+define i64 @switch_test2(i64 %a) {
+; CHECK-LABEL: @switch_test2
+; CHECK: %2 = phi i64* [ %1, %case2 ], [ %0, %Entry ], [ %0, %Entry ]
+Entry:
+ %sel = add i64 %a, 4519019440
+ switch i64 %sel, label %fail [
+ i64 462, label %continuation
+ i64 449, label %case2
+ i64 443, label %continuation
+ ]
+
+case2:
+ br label %continuation
+
+continuation:
+ %0 = phi i64* [ inttoptr(i64 4519019440 to i64*), %case2 ], [ inttoptr(i64 4519019460 to i64*), %Entry ], [ inttoptr(i64 4519019460 to i64*), %Entry ]
+ ret i64 0;
+
+fail:
+ ret i64 -1;
+}
+