From c881a4f0088c98fb99565ae472ee315ddda731af Mon Sep 17 00:00:00 2001 From: Andrew Trick Date: Sun, 26 Jan 2020 22:32:26 -0800 Subject: [PATCH] Fix EscapeAnalysis verification for an array.uninitialized case. The most recently added verification exposed an issue where the code pattern-matches an array.uninitialized call. The pattern matching does not handle multiple tuple_extracts but the API returned "success" in some of those cases. Fixes the verifier assert when building ImagePicker. --- lib/SILOptimizer/Analysis/EscapeAnalysis.cpp | 7 ++-- test/SILOptimizer/escape_analysis_reduced.sil | 33 +++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp b/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp index dbfa9931c9cb1..62e0059646990 100644 --- a/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp @@ -1822,13 +1822,16 @@ EscapeAnalysis::canOptimizeArrayUninitializedCall( // Check if the result is used in the usual way: extracting the // array and the element pointer with tuple_extract. + // + // Do not ignore any uses, even redundant tuple_extract, because all apply + // uses must be mapped to ConnectionGraph nodes by the client of this API. for (Operand *use : getNonDebugUses(ai)) { if (auto *tei = dyn_cast(use->getUser())) { - if (tei->getFieldNo() == 0) { + if (tei->getFieldNo() == 0 && !call.arrayStruct) { call.arrayStruct = tei; continue; } - if (tei->getFieldNo() == 1) { + if (tei->getFieldNo() == 1 && !call.arrayElementPtr) { call.arrayElementPtr = tei; continue; } diff --git a/test/SILOptimizer/escape_analysis_reduced.sil b/test/SILOptimizer/escape_analysis_reduced.sil index c9a31037bbc24..352f4a160bbb4 100644 --- a/test/SILOptimizer/escape_analysis_reduced.sil +++ b/test/SILOptimizer/escape_analysis_reduced.sil @@ -559,3 +559,36 @@ bb65(%614 : $Error): bb72(%681 : $Error): throw %681 : $Error } + +//============================================================================= +// Test an "array.uninitialized" with multiple tuple_extract's but no +// other unusual uses. Make sure canOptimizeArrayUninitializedCall +// returns false; otherwise graph verification can fail because only +// one of the tuple_extracts is mapped to a node. + +// specialized static Array._adoptStorage(_:count:) +sil [_semantics "array.uninitialized"] @$sSa13_adoptStorage_5countSayxG_SpyxGts016_ContiguousArrayB0CyxGn_SitFZSo5Int64V_Tg5 : $@convention(method) (@owned _ContiguousArrayStorage, Int, @thin Array.Type) -> (@owned Array, UnsafeMutablePointer) + +// CHECK-LABEL: CG of testArrayUninitResultMapping +// CHECK-NEXT: [ref] %0 Esc: , Succ: (%0.1) +// CHECK-NEXT: Con [int] %0.1 Esc: G, Succ: (%0.2) +// CHECK-NEXT: Con [ref] %0.2 Esc: G, Succ: +// CHECK-NEXT: Val %2 Esc: , Succ: (%2.1) +// CHECK-NEXT: Con %2.1 Esc: G, Succ: +// CHECK-LABEL: End +sil hidden @testArrayUninitResultMapping : $@convention(thin) () -> () { +bb0: + %0 = alloc_ref [tail_elems $Int64 * undef : $Builtin.Word] $_ContiguousArrayStorage + // function_ref specialized static Array._adoptStorage(_:count:) + %1 = function_ref @$sSa13_adoptStorage_5countSayxG_SpyxGts016_ContiguousArrayB0CyxGn_SitFZSo5Int64V_Tg5 : $@convention(method) (@owned _ContiguousArrayStorage, Int, @thin Array.Type) -> (@owned Array, UnsafeMutablePointer) + %2 = apply %1(%0, undef, undef) : $@convention(method) (@owned _ContiguousArrayStorage, Int, @thin Array.Type) -> (@owned Array, UnsafeMutablePointer) + %3 = tuple_extract %2 : $(Array, UnsafeMutablePointer), 0 + %4 = tuple_extract %2 : $(Array, UnsafeMutablePointer), 1 + %5 = tuple_extract %2 : $(Array, UnsafeMutablePointer), 0 + %6 = struct_extract %5 : $Array, #Array._buffer + %7 = struct_extract %6 : $_ArrayBuffer, #_ArrayBuffer._storage + %8 = struct_extract %7 : $_BridgeStorage<__ContiguousArrayStorageBase>, #_BridgeStorage.rawValue + strong_retain %8 : $Builtin.BridgeObject + %10 = tuple () + return %10 : $() +}