@@ -2391,3 +2391,136 @@ SILCombiner::visitDifferentiableFunctionExtractInst(DifferentiableFunctionExtrac
23912391 replaceInstUsesWith (*DFEI, newValue);
23922392 return eraseInstFromFunction (*DFEI);
23932393}
2394+
2395+ // Simplify `pack_length` with constant-length pack.
2396+ //
2397+ // Before:
2398+ // %len = pack_length $Pack{Int, String, Float}
2399+ //
2400+ // After:
2401+ // %len = integer_literal Builtin.Word, 3
2402+ SILInstruction *SILCombiner::visitPackLengthInst (PackLengthInst *PLI) {
2403+ auto PackTy = PLI->getPackType ();
2404+ if (!PackTy->containsPackExpansionType ()) {
2405+ return Builder.createIntegerLiteral (PLI->getLoc (), PLI->getType (),
2406+ PackTy->getNumElements ());
2407+ }
2408+
2409+ return nullptr ;
2410+ }
2411+
2412+ // Simplify `pack_element_get` where the index is a `dynamic_pack_index` with
2413+ // a constant operand.
2414+ //
2415+ // Before:
2416+ // %idx = integer_literal Builtin.Word, N
2417+ // %pack_idx = dynamic_pack_index %Pack{Int, String, Float}, %idx
2418+ // %pack_elt = pack_element_get %pack_value, %pack_idx, @element("...")
2419+ //
2420+ // After:
2421+ // %pack_idx = scalar_pack_index %Pack{Int, String, Float}, N
2422+ // %concrete_elt = pack_element_get %pack_value, %pack_idx, <<concrete type>>
2423+ // %pack_elt = unchecked_addr_cast %concrete_elt, @element("...")
2424+ SILInstruction *SILCombiner::visitPackElementGetInst (PackElementGetInst *PEGI) {
2425+ auto *DPII = dyn_cast<DynamicPackIndexInst>(PEGI->getIndex ());
2426+ if (DPII == nullptr )
2427+ return nullptr ;
2428+
2429+ auto PackTy = PEGI->getPackType ();
2430+ if (PackTy->containsPackExpansionType ())
2431+ return nullptr ;
2432+
2433+ auto *Op = dyn_cast<IntegerLiteralInst>(DPII->getOperand ());
2434+ if (Op == nullptr )
2435+ return nullptr ;
2436+
2437+ if (Op->getValue ().uge (PackTy->getNumElements ()))
2438+ return nullptr ;
2439+
2440+ unsigned Index = Op->getValue ().getZExtValue ();
2441+ auto *SPII = Builder.createScalarPackIndex (
2442+ DPII->getLoc (), Index, DPII->getIndexedPackType ());
2443+
2444+ auto ElementTy = SILType::getPrimitiveAddressType (
2445+ PEGI->getPackType ().getElementType (Index));
2446+ auto *NewPEGI = Builder.createPackElementGet (
2447+ PEGI->getLoc (), SPII, PEGI->getPack (),
2448+ ElementTy);
2449+
2450+ return Builder.createUncheckedAddrCast (
2451+ PEGI->getLoc (), NewPEGI, PEGI->getElementType ());
2452+ }
2453+
2454+ // Simplify `tuple_pack_element_addr` where the index is a `dynamic_pack_index`
2455+ // with a constant operand.
2456+ //
2457+ // Before:
2458+ // %idx = integer_literal Builtin.Word, N
2459+ // %pack_idx = dynamic_pack_index %Pack{Int, String, Float}, %idx
2460+ // %tuple_elt = tuple_pack_element_addr %tuple_value, %pack_idx, @element("...")
2461+ //
2462+ // After:
2463+ // %concrete_elt = tuple_element_addr %tuple_value, N
2464+ // %tuple_elt = unchecked_addr_cast %concrete_elt, @element("...")
2465+ SILInstruction *
2466+ SILCombiner::visitTuplePackElementAddrInst (TuplePackElementAddrInst *TPEAI) {
2467+ auto *DPII = dyn_cast<DynamicPackIndexInst>(TPEAI->getIndex ());
2468+ if (DPII == nullptr )
2469+ return nullptr ;
2470+
2471+ auto PackTy = DPII->getIndexedPackType ();
2472+ if (PackTy->containsPackExpansionType ())
2473+ return nullptr ;
2474+
2475+ auto *Op = dyn_cast<IntegerLiteralInst>(DPII->getOperand ());
2476+ if (Op == nullptr )
2477+ return nullptr ;
2478+
2479+ if (Op->getValue ().uge (PackTy->getNumElements ()))
2480+ return nullptr ;
2481+
2482+ unsigned Index = Op->getValue ().getZExtValue ();
2483+
2484+ auto *TEAI = Builder.createTupleElementAddr (
2485+ TPEAI->getLoc (), TPEAI->getTuple (), Index);
2486+ return Builder.createUncheckedAddrCast (
2487+ TPEAI->getLoc (), TEAI, TPEAI->getElementType ());
2488+ }
2489+
2490+ // This is a hack. When optimizing a simple pack expansion expression which
2491+ // forms a tuple from a pack, like `(repeat each t)`, after the above
2492+ // peepholes we end up with:
2493+ //
2494+ // %src = unchecked_addr_cast %real_src, @element("...")
2495+ // %dst = unchecked_addr_cast %real_dst, @element("...")
2496+ // copy_addr %src, %dst
2497+ //
2498+ // Simplify this to
2499+ //
2500+ // copy_addr %real_src, %real_dst
2501+ //
2502+ // Assuming that %real_src and %real_dst have the same type.
2503+ //
2504+ // In this simple case, this eliminates the opened element archetype entirely.
2505+ // However, a more principled peephole would be to transform an
2506+ // open_pack_element with a scalar index by replacing all usages of the
2507+ // element archetype with a concrete type.
2508+ SILInstruction *
2509+ SILCombiner::visitCopyAddrInst (CopyAddrInst *CAI) {
2510+ auto *Src = dyn_cast<UncheckedAddrCastInst>(CAI->getSrc ());
2511+ auto *Dst = dyn_cast<UncheckedAddrCastInst>(CAI->getDest ());
2512+
2513+ if (Src == nullptr || Dst == nullptr )
2514+ return nullptr ;
2515+
2516+ if (Src->getType () != Dst->getType () ||
2517+ !Src->getType ().is <ElementArchetypeType>())
2518+ return nullptr ;
2519+
2520+ if (Src->getOperand ()->getType () != Dst->getOperand ()->getType ())
2521+ return nullptr ;
2522+
2523+ return Builder.createCopyAddr (
2524+ CAI->getLoc (), Src->getOperand (), Dst->getOperand (),
2525+ CAI->isTakeOfSrc (), CAI->isInitializationOfDest ());
2526+ }
0 commit comments