Skip to content

Commit 1e28b0a

Browse files
committed
SILGen: revise emission of UnreachableExpr
The prior emission strategy produced some scary SIL where we have a copy of uninitialized memory: ``` ignored_use %14 %16 = alloc_stack $T unreachable bb1: copy_addr [take] %16 to [init] %0 dealloc_stack %16 ``` I assume this was done to dodge the SILVerifier, which will catch a take of an uninitialized address, had the alloc_stack been in any reachable predecessor. We already have a representation for an undefined value in SIL, so I'd rather use that than try to sneak one past the verifier. This adjusted emission also is opaque values friendly, as it doesn't assume the result value is an address. resolves rdar://162239557
1 parent cc8f060 commit 1e28b0a

File tree

3 files changed

+50
-8
lines changed

3 files changed

+50
-8
lines changed

lib/SILGen/SILGenExpr.cpp

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2606,19 +2606,31 @@ RValue RValueEmitter::visitUnderlyingToOpaqueExpr(UnderlyingToOpaqueExpr *E,
26062606
}
26072607

26082608
RValue RValueEmitter::visitUnreachableExpr(UnreachableExpr *E, SGFContext C) {
2609-
// Emit the expression, followed by an unreachable. To produce a value of
2610-
// arbitrary type, we emit a temporary allocation, with the use of the
2611-
// allocation in the unreachable block. The SILOptimizer will eliminate both
2612-
// the unreachable block and unused allocation.
2609+
// Emit the expression, followed by an unreachable.
26132610
SGF.emitIgnoredExpr(E->getSubExpr());
2611+
SGF.B.createUnreachable(E);
2612+
2613+
// Continue code generation in a block with no predecessors.
2614+
// Whatever code is emitted here is guaranteed to be removed by SIL passes.
2615+
SGF.B.emitBlock(SGF.createBasicBlock());
26142616

2617+
// Since the type is uninhabited, use a SILUndef of so that we can return
2618+
// some sort of RValue from this API.
26152619
auto &lowering = SGF.getTypeLowering(E->getType());
2616-
auto resultAddr = SGF.emitTemporaryAllocation(E, lowering.getLoweredType());
2620+
auto loweredTy = lowering.getLoweredType();
2621+
auto undef = SILUndef::get(SGF.F, loweredTy);
26172622

2618-
SGF.B.createUnreachable(E);
2619-
SGF.B.emitBlock(SGF.createBasicBlock());
2623+
// Create an alloc initialized with contents from the undefined addr type.
2624+
// It seems pack addresses do not satisfy isPlusOneOrTrivial, so we need an
2625+
// actual allocation.
2626+
if (loweredTy.isAddress()) {
2627+
auto resultAddr = SGF.emitTemporaryAllocation(E, loweredTy);
2628+
SGF.emitSemanticStore(E, undef, resultAddr, lowering, IsInitialization);
2629+
return RValue(SGF, E, SGF.emitManagedRValueWithCleanup(resultAddr));
2630+
}
26202631

2621-
return RValue(SGF, E, SGF.emitManagedRValueWithCleanup(resultAddr));
2632+
// Otherwise, if it's not an address, just emit the undef value itself.
2633+
return RValue(SGF, E, ManagedValue::forRValueWithoutOwnership(undef));
26222634
}
26232635

26242636
VarargsInfo Lowering::emitBeginVarargs(SILGenFunction &SGF, SILLocation loc,

test/SILGen/unreachable_expr.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// RUN: %target-swift-emit-silgen %s -verify -sil-verify-all | %FileCheck %s --check-prefixes CHECK,REG
2+
// RUN: %target-swift-emit-silgen %s -verify -sil-verify-all -enable-sil-opaque-values | %FileCheck %s --check-prefixes CHECK,OV
3+
4+
// CHECK-LABEL: sil{{.*}} [ossa] @{{.*}}uninhabited_generic{{.*}}
5+
// CHECK: [[NEVER:%[^,]+]] = apply {{.*}} -> Never
6+
// CHECK-NEXT: ignored_use [[NEVER]]
7+
// CHECK-NEXT: unreachable
8+
//
9+
// CHECK: bb1:
10+
// CHECK-NOT: Preds
11+
12+
// Without opaque values, take from an undef address,
13+
// through a temporary alloc, to eventually the out-parameter %0
14+
// REG-NEXT: [[BOGUS_ALLOC:%.*]] = alloc_stack $T
15+
// REG-NEXT: copy_addr [take] undef to [init] [[BOGUS_ALLOC]]
16+
// REG-NEXT: copy_addr [take] [[BOGUS_ALLOC]] to [init] %0
17+
18+
// With opaque values, simply return the undef value
19+
// OV-NEXT: return undef : $T
20+
func uninhabited_generic<T>() -> T { fatalError("todo") }

test/SILGen/variadic-generic-tuples.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,16 @@ func convertVoidPayloads() {
430430
convertPayloads(as: Void.self)
431431
}
432432

433+
// CHECK-LABEL: sil{{.*}} [ossa] @{{.*}}convertPayloads{{.*}} :
434+
// CHECK: ignored_use {{.*}}
435+
// CHECK-NEXT: unreachable
436+
//
437+
// CHECK: bb1:
438+
// CHECK-NOT: Preds
439+
// CHECK: [[BOGUS_ALLOC:%.*]] = alloc_stack $(repeat each Value)
440+
// CHECK-NEXT: copy_addr [take] undef to [init] [[BOGUS_ALLOC]]
441+
//
442+
// CHECK: = tuple_pack_element_addr {{.*}} of [[BOGUS_ALLOC]]
433443
func convertPayloads<each Value>(as valueTypes: repeat (each Value).Type) -> (repeat each Value) {
434444
fatalError()
435445
}

0 commit comments

Comments
 (0)