@@ -2391,3 +2391,136 @@ SILCombiner::visitDifferentiableFunctionExtractInst(DifferentiableFunctionExtrac
2391
2391
replaceInstUsesWith (*DFEI, newValue);
2392
2392
return eraseInstFromFunction (*DFEI);
2393
2393
}
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