SILInstruction *SILCombiner::visitSelectEnumInst(SelectEnumInst *SEI) {
    // Canonicalize a select_enum: if the default refers to exactly one case, then
    // replace the default with that case.
    if (SEI->hasDefault()) {
        NullablePtr<EnumElementDecl> elementDecl = SEI->getUniqueCaseForDefault();
        if (elementDecl.isNonNull()) {
            // Construct a new instruction by copying all the case entries.
            SmallVector<std::pair<EnumElementDecl *, SILValue>, 4> CaseValues;
            for (int idx = 0, numIdcs = SEI->getNumCases(); idx < numIdcs; idx++) {
                CaseValues.push_back(SEI->getCase(idx));
            }
            // Add the default-entry of the original instruction as case-entry.
            CaseValues.push_back(
                std::make_pair(elementDecl.get(), SEI->getDefaultResult()));

            return Builder.createSelectEnum(SEI->getLoc(), SEI->getEnumOperand(),
                                            SEI->getType(), SILValue(), CaseValues);
        }
    }

    // TODO: We should be able to flat-out replace the select_enum instruction
    // with the selected value in another pass. For parity with the enum_is_tag
    // combiner pass, handle integer literals for now.
    auto *EI = dyn_cast<EnumInst>(SEI->getEnumOperand());
    if (!EI)
        return nullptr;

    SILValue selected;
    for (unsigned i = 0, e = SEI->getNumCases(); i < e; ++i) {
        auto casePair = SEI->getCase(i);
        if (casePair.first == EI->getElement()) {
            selected = casePair.second;
            break;
        }
    }
    if (!selected)
        selected = SEI->getDefaultResult();

    if (auto *ILI = dyn_cast<IntegerLiteralInst>(selected)) {
        return Builder.createIntegerLiteral(ILI->getLoc(), ILI->getType(),
                                            ILI->getValue());
    }

    return nullptr;
}
SILInstruction *SILCombiner::visitSelectEnumAddrInst(SelectEnumAddrInst *SEAI) {
    // Canonicalize a select_enum_addr: if the default refers to exactly one case,
    // then replace the default with that case.
    Builder.setCurrentDebugScope(SEAI->getDebugScope());
    if (SEAI->hasDefault()) {
        NullablePtr<EnumElementDecl> elementDecl = SEAI->getUniqueCaseForDefault();
        if (elementDecl.isNonNull()) {
            // Construct a new instruction by copying all the case entries.
            SmallVector<std::pair<EnumElementDecl *, SILValue>, 4> CaseValues;
            for (int idx = 0, numIdcs = SEAI->getNumCases(); idx < numIdcs; idx++) {
                CaseValues.push_back(SEAI->getCase(idx));
            }
            // Add the default-entry of the original instruction as case-entry.
            CaseValues.push_back(
                std::make_pair(elementDecl.get(), SEAI->getDefaultResult()));

            return Builder.createSelectEnumAddr(SEAI->getLoc(),
                                                SEAI->getEnumOperand(),
                                                SEAI->getType(), SILValue(),
                                                CaseValues);
        }
    }

    // Promote select_enum_addr to select_enum if the enum is loadable.
    //   = select_enum_addr %ptr : $*Optional<SomeClass>, case ...
    //     ->
    //   %value = load %ptr
    //   = select_enum %value
    SILType Ty = SEAI->getEnumOperand().getType();
    if (!Ty.isLoadable(SEAI->getModule()))
        return nullptr;

    SmallVector<std::pair<EnumElementDecl*, SILValue>, 8> Cases;
    for (int i = 0, e = SEAI->getNumCases(); i < e; ++i)
        Cases.push_back(SEAI->getCase(i));

    SILValue Default = SEAI->hasDefault() ? SEAI->getDefaultResult() : SILValue();
    LoadInst *EnumVal = Builder.createLoad(SEAI->getLoc(),
                                           SEAI->getEnumOperand());
    auto *I = Builder.createSelectEnum(SEAI->getLoc(), EnumVal, SEAI->getType(),
                                       Default, Cases);
    return I;
}