mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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
This commit is contained in:
@@ -2606,19 +2606,31 @@ RValue RValueEmitter::visitUnderlyingToOpaqueExpr(UnderlyingToOpaqueExpr *E,
|
||||
}
|
||||
|
||||
RValue RValueEmitter::visitUnreachableExpr(UnreachableExpr *E, SGFContext C) {
|
||||
// Emit the expression, followed by an unreachable. To produce a value of
|
||||
// arbitrary type, we emit a temporary allocation, with the use of the
|
||||
// allocation in the unreachable block. The SILOptimizer will eliminate both
|
||||
// the unreachable block and unused allocation.
|
||||
// Emit the expression, followed by an unreachable.
|
||||
SGF.emitIgnoredExpr(E->getSubExpr());
|
||||
|
||||
auto &lowering = SGF.getTypeLowering(E->getType());
|
||||
auto resultAddr = SGF.emitTemporaryAllocation(E, lowering.getLoweredType());
|
||||
|
||||
SGF.B.createUnreachable(E);
|
||||
|
||||
// Continue code generation in a block with no predecessors.
|
||||
// Whatever code is emitted here is guaranteed to be removed by SIL passes.
|
||||
SGF.B.emitBlock(SGF.createBasicBlock());
|
||||
|
||||
return RValue(SGF, E, SGF.emitManagedRValueWithCleanup(resultAddr));
|
||||
// Since the type is uninhabited, use a SILUndef of so that we can return
|
||||
// some sort of RValue from this API.
|
||||
auto &lowering = SGF.getTypeLowering(E->getType());
|
||||
auto loweredTy = lowering.getLoweredType();
|
||||
auto undef = SILUndef::get(SGF.F, loweredTy);
|
||||
|
||||
// Create an alloc initialized with contents from the undefined addr type.
|
||||
// It seems pack addresses do not satisfy isPlusOneOrTrivial, so we need an
|
||||
// actual allocation.
|
||||
if (loweredTy.isAddress()) {
|
||||
auto resultAddr = SGF.emitTemporaryAllocation(E, loweredTy);
|
||||
SGF.emitSemanticStore(E, undef, resultAddr, lowering, IsInitialization);
|
||||
return RValue(SGF, E, SGF.emitManagedRValueWithCleanup(resultAddr));
|
||||
}
|
||||
|
||||
// Otherwise, if it's not an address, just emit the undef value itself.
|
||||
return RValue(SGF, E, ManagedValue::forRValueWithoutOwnership(undef));
|
||||
}
|
||||
|
||||
VarargsInfo Lowering::emitBeginVarargs(SILGenFunction &SGF, SILLocation loc,
|
||||
|
||||
20
test/SILGen/unreachable_expr.swift
Normal file
20
test/SILGen/unreachable_expr.swift
Normal file
@@ -0,0 +1,20 @@
|
||||
// RUN: %target-swift-emit-silgen %s -verify -sil-verify-all | %FileCheck %s --check-prefixes CHECK,REG
|
||||
// RUN: %target-swift-emit-silgen %s -verify -sil-verify-all -enable-sil-opaque-values | %FileCheck %s --check-prefixes CHECK,OV
|
||||
|
||||
// CHECK-LABEL: sil{{.*}} [ossa] @{{.*}}uninhabited_generic{{.*}}
|
||||
// CHECK: [[NEVER:%[^,]+]] = apply {{.*}} -> Never
|
||||
// CHECK-NEXT: ignored_use [[NEVER]]
|
||||
// CHECK-NEXT: unreachable
|
||||
//
|
||||
// CHECK: bb1:
|
||||
// CHECK-NOT: Preds
|
||||
|
||||
// Without opaque values, take from an undef address,
|
||||
// through a temporary alloc, to eventually the out-parameter %0
|
||||
// REG-NEXT: [[BOGUS_ALLOC:%.*]] = alloc_stack $T
|
||||
// REG-NEXT: copy_addr [take] undef to [init] [[BOGUS_ALLOC]]
|
||||
// REG-NEXT: copy_addr [take] [[BOGUS_ALLOC]] to [init] %0
|
||||
|
||||
// With opaque values, simply return the undef value
|
||||
// OV-NEXT: return undef : $T
|
||||
func uninhabited_generic<T>() -> T { fatalError("todo") }
|
||||
@@ -430,6 +430,16 @@ func convertVoidPayloads() {
|
||||
convertPayloads(as: Void.self)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil{{.*}} [ossa] @{{.*}}convertPayloads{{.*}} :
|
||||
// CHECK: ignored_use {{.*}}
|
||||
// CHECK-NEXT: unreachable
|
||||
//
|
||||
// CHECK: bb1:
|
||||
// CHECK-NOT: Preds
|
||||
// CHECK: [[BOGUS_ALLOC:%.*]] = alloc_stack $(repeat each Value)
|
||||
// CHECK-NEXT: copy_addr [take] undef to [init] [[BOGUS_ALLOC]]
|
||||
//
|
||||
// CHECK: = tuple_pack_element_addr {{.*}} of [[BOGUS_ALLOC]]
|
||||
func convertPayloads<each Value>(as valueTypes: repeat (each Value).Type) -> (repeat each Value) {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user