Skip to content

Commit ac01ca6

Browse files
kavonDeniz Dizman
authored andcommitted
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 94b1435 commit ac01ca6

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
@@ -2637,19 +2637,31 @@ RValue RValueEmitter::visitUnderlyingToOpaqueExpr(UnderlyingToOpaqueExpr *E,
26372637
}
26382638

26392639
RValue RValueEmitter::visitUnreachableExpr(UnreachableExpr *E, SGFContext C) {
2640-
// Emit the expression, followed by an unreachable. To produce a value of
2641-
// arbitrary type, we emit a temporary allocation, with the use of the
2642-
// allocation in the unreachable block. The SILOptimizer will eliminate both
2643-
// the unreachable block and unused allocation.
2640+
// Emit the expression, followed by an unreachable.
26442641
SGF.emitIgnoredExpr(E->getSubExpr());
2642+
SGF.B.createUnreachable(E);
2643+
2644+
// Continue code generation in a block with no predecessors.
2645+
// Whatever code is emitted here is guaranteed to be removed by SIL passes.
2646+
SGF.B.emitBlock(SGF.createBasicBlock());
26452647

2648+
// Since the type is uninhabited, use a SILUndef of so that we can return
2649+
// some sort of RValue from this API.
26462650
auto &lowering = SGF.getTypeLowering(E->getType());
2647-
auto resultAddr = SGF.emitTemporaryAllocation(E, lowering.getLoweredType());
2651+
auto loweredTy = lowering.getLoweredType();
2652+
auto undef = SILUndef::get(SGF.F, loweredTy);
26482653

2649-
SGF.B.createUnreachable(E);
2650-
SGF.B.emitBlock(SGF.createBasicBlock());
2654+
// Create an alloc initialized with contents from the undefined addr type.
2655+
// It seems pack addresses do not satisfy isPlusOneOrTrivial, so we need an
2656+
// actual allocation.
2657+
if (loweredTy.isAddress()) {
2658+
auto resultAddr = SGF.emitTemporaryAllocation(E, loweredTy);
2659+
SGF.emitSemanticStore(E, undef, resultAddr, lowering, IsInitialization);
2660+
return RValue(SGF, E, SGF.emitManagedRValueWithCleanup(resultAddr));
2661+
}
26512662

2652-
return RValue(SGF, E, SGF.emitManagedRValueWithCleanup(resultAddr));
2663+
// Otherwise, if it's not an address, just emit the undef value itself.
2664+
return RValue(SGF, E, ManagedValue::forRValueWithoutOwnership(undef));
26532665
}
26542666

26552667
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)