Skip to content

Commit 0896540

Browse files
committed
SILOptimizer: Add various pack peepholes to SILCombiner
1 parent 43a3599 commit 0896540

File tree

3 files changed

+200
-0
lines changed

3 files changed

+200
-0
lines changed

lib/SILOptimizer/SILCombiner/SILCombiner.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,11 @@ class SILCombiner :
300300
SILInstruction *
301301
visitDifferentiableFunctionExtractInst(DifferentiableFunctionExtractInst *DFEI);
302302

303+
SILInstruction *visitPackLengthInst(PackLengthInst *PLI);
304+
SILInstruction *visitPackElementGetInst(PackElementGetInst *PEGI);
305+
SILInstruction *visitTuplePackElementAddrInst(TuplePackElementAddrInst *TPEAI);
306+
SILInstruction *visitCopyAddrInst(CopyAddrInst *CAI);
307+
303308
SILInstruction *legacyVisitGlobalValueInst(GlobalValueInst *globalValue);
304309

305310
#define PASS(ID, TAG, DESCRIPTION)

lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// RUN: %target-swift-frontend -parse-as-library -O -emit-sil %s -enable-experimental-feature VariadicGenerics | %FileCheck %s
2+
3+
// Because of -enable-experimental-feature VariadicGenerics
4+
// REQUIRES: asserts
5+
6+
@_transparent func makeTuple<each T>(_ t: repeat each T) -> (repeat each T) {
7+
return (repeat each t)
8+
}
9+
10+
// FIXME: Useless alloc_pack/dealloc_pack
11+
12+
// CHECK-LABEL: sil @$s17tuples_from_packs14makeEmptyTupleyyF : $@convention(thin) () -> () {
13+
// CHECK: bb0:
14+
// CHECK-NEXT: %0 = alloc_pack $Pack{}
15+
// CHECK-NEXT: %1 = alloc_pack $Pack{}
16+
// CHECK-NEXT: dealloc_pack %1 : $*Pack{}
17+
// CHECK-NEXT: dealloc_pack %0 : $*Pack{}
18+
// CHECK-NEXT: [[RET:%.*]] = tuple ()
19+
// CHECK-NEXT: return [[RET]] : $()
20+
public func makeEmptyTuple() {
21+
return makeTuple()
22+
}
23+
24+
// FIXME: This crashes in SILGen
25+
/*public func makeOne<T>(_ t: T) -> T {
26+
return makeTuple(t)
27+
}*/
28+
29+
// FIXME: Useless pack_element_set/pack_element_get
30+
31+
// CHECK-LABEL: sil @$s17tuples_from_packs8makePairyx_q_tx_q_tr0_lF : $@convention(thin) <T, U> (@in_guaranteed T, @in_guaranteed U) -> (@out T, @out U) {
32+
// CHECK: bb0(%0 : $*T, %1 : $*U, %2 : $*T, %3 : $*U):
33+
// CHECK: [[PACK:%.*]] = alloc_pack $Pack{T, U}
34+
// CHECK-NEXT: [[IDX0:%.*]] = scalar_pack_index 0 of $Pack{T, U}
35+
// CHECK-NEXT: pack_element_set %0 : $*T into [[IDX0]] of [[PACK]] : $*Pack{T, U}
36+
// CHECK-NEXT: [[IDX1:%.*]] = scalar_pack_index 1 of $Pack{T, U}
37+
// CHECK-NEXT: pack_element_set %1 : $*U into [[IDX1]] of [[PACK]] : $*Pack{T, U}
38+
// CHECK-NEXT: [[PACK2:%.*]] = alloc_pack $Pack{T, U}
39+
// CHECK-NEXT: [[T:%.*]] = alloc_stack $T
40+
// CHECK-NEXT: copy_addr %2 to [init] [[T]] : $*T
41+
// CHECK-NEXT: pack_element_set [[T]] : $*T into [[IDX0]] of [[PACK2]] : $*Pack{T, U}
42+
// CHECK-NEXT: [[U:%.*]] = alloc_stack $U
43+
// CHECK-NEXT: copy_addr %3 to [init] [[U]] : $*U
44+
// CHECK-NEXT: pack_element_set [[U]] : $*U into [[IDX1]] of [[PACK2]] : $*Pack{T, U}
45+
// CHECK-NEXT: [[ELT0:%.*]] = pack_element_get [[IDX0]] of [[PACK]] : $*Pack{T, U} as $*T
46+
// CHECK-NEXT: [[ELT02:%.*]] = pack_element_get [[IDX0]] of [[PACK2]] : $*Pack{T, U} as $*T
47+
// CHECK-NEXT: copy_addr [[ELT02]] to [init] [[ELT0]] : $*T
48+
// CHECK-NEXT: [[ELT1:%.*]] = pack_element_get [[IDX1]] of [[PACK]] : $*Pack{T, U} as $*U
49+
// CHECK-NEXT: [[ELT12:%.*]] = pack_element_get [[IDX1]] of [[PACK2]] : $*Pack{T, U} as $*U
50+
// CHECK-NEXT: copy_addr [[ELT12]] to [init] [[ELT1]] : $*U
51+
// CHECK-NEXT: destroy_addr [[U]] : $*U
52+
// CHECK-NEXT: dealloc_stack [[U]] : $*U
53+
// CHECK-NEXT: destroy_addr [[T]] : $*T
54+
// CHECK-NEXT: dealloc_stack [[T]] : $*T
55+
// CHECK-NEXT: dealloc_pack [[PACK2]] : $*Pack{T, U}
56+
// CHECK-NEXT: dealloc_pack [[PACK]] : $*Pack{T, U}
57+
// CHECK-NEXT: %30 = tuple ()
58+
// CHECK-NEXT: return %30 : $()
59+
60+
public func makePair<T, U>(_ t: T, _ u: U) -> (T, U) {
61+
return makeTuple(t, u)
62+
}

0 commit comments

Comments
 (0)