Skip to content

Commit f6ccefe

Browse files
authored
Loosen a CopyForwarding assert: store instead of deinit. (#32641)
CopyForwarding attempts to enforce "normal" SIL address patterns using asserts. This isn't a good strategy because it results in strange crash diagnostics in release builds. Eventually, we should replace this logic with a SIL address lifetime utility based on OSSA form and enforced in the verifier. Loosen one of these restrictions where we assume that a value initialized with "copy_addr [initialization]" will be properly destroyed. This assumption is violated when lowering .int_fma_FPIEEE32, which knows that the type is trivial, so avoids deinitialization. The original SIL looks like this: copy_addr %src to [initialization] %dest : $*Float %fma = builtin "int_fma_FPIEEE32"(% : $Builtin.FPIEEE32, % : $Builtin.FPIEEE32, % : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 %result = struct $Float (%fma : $Builtin.FPIEEE32) store %result to %dest : $*Float Fixes rdar://64671864.
1 parent 0cb3e3d commit f6ccefe

File tree

2 files changed

+56
-8
lines changed

2 files changed

+56
-8
lines changed

lib/SILOptimizer/Transforms/CopyForwarding.cpp

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,9 @@ namespace {
322322
/// This returns false and sets Oper to a valid operand if the instruction is a
323323
/// projection of the value at the given address. The assumption is that we
324324
/// cannot deinitialize memory via projections.
325+
///
326+
/// This returns true with Oper == nullptr for trivial stores (without a proper
327+
/// deinit).
325328
class AnalyzeForwardUse
326329
: public SILInstructionVisitor<AnalyzeForwardUse, bool> {
327330
public:
@@ -352,7 +355,10 @@ class AnalyzeForwardUse
352355
return true;
353356
}
354357
bool visitStoreInst(StoreInst *Store) {
355-
llvm_unreachable("illegal reinitialization or store of an address");
358+
// Trivial values may be stored prior to the next deinit. A store is an
359+
// implicit "deinit" with no operand to replace.
360+
assert(Store->getOperand(0)->getType().isTrivial(*Store->getFunction()));
361+
return true;
356362
}
357363
bool visitDestroyAddrInst(DestroyAddrInst *UserInst) {
358364
Oper = &UserInst->getOperandRef();
@@ -1011,15 +1017,17 @@ bool CopyForwarding::forwardPropagateCopy() {
10111017
continue;
10121018

10131019
AnalyzeForwardUse AnalyzeUse(CopyDest);
1014-
bool seenDeinit = AnalyzeUse.visit(UserInst);
1015-
// If this use cannot be analyzed, then abort.
1020+
bool seenDeinitOrStore = AnalyzeUse.visit(UserInst);
1021+
if (AnalyzeUse.Oper)
1022+
ValueUses.push_back(AnalyzeUse.Oper);
1023+
1024+
// If this is a deinit or store, we're done searching.
1025+
if (seenDeinitOrStore)
1026+
break;
1027+
1028+
// If this non-deinit instruction wasn't fully analyzed, bail-out.
10161029
if (!AnalyzeUse.Oper)
10171030
return false;
1018-
// Otherwise record the operand.
1019-
ValueUses.push_back(AnalyzeUse.Oper);
1020-
// If this is a deinit, we're done searching.
1021-
if (seenDeinit)
1022-
break;
10231031
}
10241032
if (SI == SE)
10251033
return false;

test/SILOptimizer/copyforward.sil

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -915,3 +915,43 @@ bb1:
915915
%v = tuple ()
916916
return %v : $()
917917
}
918+
919+
// Test an "illegal" reinitialization of a stack location. This
920+
// happens because lowering .int_fma_FPIEEE32 knows that the type is
921+
// trivial, so avoids deinitialization. rdar://64671864.
922+
//
923+
// Note: we have given up on enforcing known SIL-patterns in
924+
// CopyForwarding. Instead, we just remove restructions whenever we see
925+
// unexpected patterns. Eventually, we will replace it with an OSSA
926+
// pass and enforce all assumptions about SIL patterns in the verifier.
927+
928+
// CHECK-LABEL: sil @testCPF : $@convention(thin) (Float) -> @out Float {
929+
// CHECK: bb0(%0 : $*Float, %1 : $Float):
930+
// CHECK: [[TMP1:%.*]] = alloc_stack $Float
931+
// CHECK: store %1 to [[TMP1]] : $*Float
932+
// CHECK: [[TMP2:%.*]] = alloc_stack $Float
933+
// CHECK-NOT: copy_addr
934+
// CHECK: [[FMA:%.*]] = builtin "int_fma_FPIEEE32"
935+
// CHECK: [[RESULT:%.*]] = struct $Float ([[FMA]] : $Builtin.FPIEEE32)
936+
// CHECK: store [[RESULT]] to %0 : $*Float
937+
// CHECK-NOT: copy_addr
938+
// CHECK-NOT: destroy_addr
939+
// CHECK-LABEL: } // end sil function 'testCPF'
940+
sil @testCPF : $@convention(thin) (Float) -> @out Float {
941+
bb0(%0 : $*Float, %1 : $Float):
942+
%2 = alloc_stack $Float
943+
store %1 to %2 : $*Float
944+
%4 = alloc_stack $Float
945+
copy_addr %2 to [initialization] %4 : $*Float
946+
%6 = struct_extract %1 : $Float, #Float._value
947+
%7 = builtin "int_fma_FPIEEE32"(%6 : $Builtin.FPIEEE32, %6 : $Builtin.FPIEEE32, %6 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32
948+
%8 = struct $Float (%7 : $Builtin.FPIEEE32)
949+
store %8 to %4 : $*Float
950+
copy_addr %4 to [initialization] %0 : $*Float
951+
destroy_addr %4 : $*Float
952+
dealloc_stack %4 : $*Float
953+
destroy_addr %2 : $*Float
954+
dealloc_stack %2 : $*Float
955+
%15 = tuple ()
956+
return %15 : $()
957+
}

0 commit comments

Comments
 (0)