Skip to content

Commit 1e89ad6

Browse files
committed
Sink address projections in ArrayPropertyOpt so that there are no address phis
1 parent 46bed7c commit 1e89ad6

File tree

2 files changed

+177
-11
lines changed

2 files changed

+177
-11
lines changed

lib/SILOptimizer/LoopTransforms/ArrayPropertyOpt.cpp

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -53,19 +53,19 @@
5353
#define DEBUG_TYPE "array-property-opt"
5454

5555
#include "ArrayOpt.h"
56+
#include "swift/SIL/CFG.h"
57+
#include "swift/SIL/DebugUtils.h"
58+
#include "swift/SIL/InstructionUtils.h"
59+
#include "swift/SIL/LoopInfo.h"
60+
#include "swift/SIL/Projection.h"
61+
#include "swift/SIL/SILCloner.h"
5662
#include "swift/SILOptimizer/Analysis/ArraySemantic.h"
5763
#include "swift/SILOptimizer/Analysis/LoopAnalysis.h"
5864
#include "swift/SILOptimizer/PassManager/Transforms.h"
65+
#include "swift/SILOptimizer/Utils/BasicBlockOptUtils.h"
5966
#include "swift/SILOptimizer/Utils/CFGOptUtils.h"
6067
#include "swift/SILOptimizer/Utils/LoopUtils.h"
6168
#include "swift/SILOptimizer/Utils/SILSSAUpdater.h"
62-
#include "swift/SIL/CFG.h"
63-
#include "swift/SIL/DebugUtils.h"
64-
#include "swift/SIL/InstructionUtils.h"
65-
#include "swift/SIL/Projection.h"
66-
#include "swift/SIL/LoopInfo.h"
67-
#include "swift/SIL/BasicBlockBits.h"
68-
#include "swift/SIL/SILCloner.h"
6969
#include "llvm/ADT/SmallSet.h"
7070
#include "llvm/Support/CommandLine.h"
7171
#include "llvm/Support/Debug.h"
@@ -86,6 +86,8 @@ class ArrayPropertiesAnalysis {
8686
SILBasicBlock *Preheader;
8787
DominanceInfo *DomTree;
8888

89+
SinkAddressProjections sinkProj;
90+
8991
llvm::DenseMap<SILFunction *, uint32_t> InstCountCache;
9092
llvm::SmallSet<SILValue, 16> HoistableArray;
9193

@@ -169,13 +171,18 @@ class ArrayPropertiesAnalysis {
169171

170172
bool FoundHoistable = false;
171173
uint32_t LoopInstCount = 0;
174+
172175
for (auto *BB : Loop->getBlocks()) {
173176
for (auto &Inst : *BB) {
174177
// Can't clone alloc_stack instructions whose dealloc_stack is outside
175178
// the loop.
176179
if (!canDuplicateLoopInstruction(Loop, &Inst))
177180
return false;
178181

182+
if (!sinkProj.analyzeAddressProjections(&Inst)) {
183+
return false;
184+
}
185+
179186
ArraySemanticsCall ArrayPropsInst(&Inst, "array.props", true);
180187
if (!ArrayPropsInst)
181188
continue;
@@ -512,10 +519,11 @@ class RegionCloner : public SILCloner<RegionCloner> {
512519
SILSSAUpdater &SSAUp) {
513520
// Collect outside uses.
514521
SmallVector<UseWrapper, 16> UseList;
515-
for (auto Use : V->getUses())
522+
for (auto Use : V->getUses()) {
516523
if (!isBlockCloned(Use->getUser()->getParent())) {
517524
UseList.push_back(UseWrapper(Use));
518525
}
526+
}
519527
if (UseList.empty())
520528
return;
521529

@@ -532,15 +540,40 @@ class RegionCloner : public SILCloner<RegionCloner> {
532540

533541
void updateSSAForm() {
534542
SILSSAUpdater SSAUp;
543+
SmallVector<SingleValueInstruction *, 4> newProjections;
544+
SinkAddressProjections sinkProj(&newProjections);
545+
535546
for (auto *origBB : originalPreorderBlocks()) {
536547
// Update outside used phi values.
537-
for (auto *arg : origBB->getArguments())
548+
for (auto *arg : origBB->getArguments()) {
538549
updateSSAForValue(origBB, arg, SSAUp);
550+
}
539551

540552
// Update outside used instruction values.
541553
for (auto &inst : *origBB) {
542-
for (auto result : inst.getResults())
543-
updateSSAForValue(origBB, result, SSAUp);
554+
for (auto result : inst.getResults()) {
555+
bool success = sinkProj.analyzeAddressProjections(&inst);
556+
assert(success);
557+
// Sink address projections by cloning to avoid address phis.
558+
sinkProj.cloneProjections();
559+
560+
// If no new projections were created, update ssa for the result only.
561+
if (newProjections.empty()) {
562+
updateSSAForValue(origBB, result, SSAUp);
563+
continue;
564+
}
565+
566+
for (auto *newProj : newProjections) {
567+
// Operand values of new projections may need ssa update.
568+
for (auto opVal : newProj->getOperandValues()) {
569+
if (!isBlockCloned(opVal->getParentBlock())) {
570+
continue;
571+
}
572+
updateSSAForValue(origBB, opVal, SSAUp);
573+
}
574+
}
575+
newProjections.clear();
576+
}
544577
}
545578
}
546579
}

test/SILOptimizer/array_property_opt.sil

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
// RUN: %target-sil-opt -parse-serialized-sil -enable-sil-verify-all %s -array-property-opt | %FileCheck %s
22

3+
// Linux doesn't have the same symbol name for _ArrayBuffer, which is part of
4+
// the ObjC runtime interop. Use `_ContiguousArrayBuffer instead.
5+
// REQUIRES: objc_interop
6+
37
sil_stage canonical
48

59
import Builtin
@@ -258,3 +262,132 @@ bb10: // Exit dominated by bb3
258262
bb11: // Non-exit dominated by bb1
259263
return %4 : $Builtin.Int1
260264
}
265+
266+
class Klass {
267+
var val: Optional<Int>
268+
}
269+
270+
struct WrapperStruct {
271+
var val: Klass
272+
}
273+
274+
sil @use_klass : $@convention(thin) (@in_guaranteed Klass) -> ()
275+
276+
sil @test_sink_address_proj : $@convention(thin) (@inout MyArray<MyClass>, @in_guaranteed WrapperStruct) -> () {
277+
bb0(%0 : $*MyArray<MyClass>, %1 : $*WrapperStruct):
278+
%3 = load %0 : $*MyArray<MyClass>
279+
br bb1
280+
281+
bb1:
282+
%2 = function_ref @arrayPropertyIsNative : $@convention(method) (@owned MyArray<MyClass>) -> Bool
283+
retain_value %3 : $MyArray<MyClass>
284+
%5 = apply %2(%3) : $@convention(method) (@owned MyArray<MyClass>) -> Bool
285+
%ele = struct_element_addr %1 : $*WrapperStruct, #WrapperStruct.val
286+
cond_br undef, bb5, bb2
287+
288+
bb2:
289+
%6 = integer_literal $Builtin.Int1, -1
290+
cond_br %6, bb3, bb4
291+
292+
bb3:
293+
br bb1
294+
295+
bb4:
296+
br bb6
297+
298+
bb5:
299+
%f = function_ref @use_klass : $@convention(thin) (@in_guaranteed Klass) -> ()
300+
%a = apply %f(%ele) : $@convention(thin) (@in_guaranteed Klass) -> ()
301+
br bb6
302+
303+
bb6:
304+
%t = tuple ()
305+
return %t : $()
306+
}
307+
308+
sil [_semantics "array.props.isNativeTypeChecked"] @hoistableIsNativeTypeChecked : $@convention(method) (@guaranteed Array<Klass>) -> Bool
309+
sil [_semantics "array.get_element"] @getElement : $@convention(method) (Int, Bool, _DependenceToken, @guaranteed Array<Klass>) -> @owned Klass
310+
sil [_semantics "array.get_count"] @getCount : $@convention(method) (@guaranteed Array<Klass>) -> Int
311+
312+
sil hidden @test_array_prop_opt : $@convention(thin) (@guaranteed Optional<Array<Klass>>) -> Int {
313+
bb0(%0 : $Optional<Array<Klass>>):
314+
%4 = integer_literal $Builtin.Int64, 0
315+
switch_enum %0 : $Optional<Array<Klass>>, case #Optional.some!enumelt: bb2, case #Optional.none!enumelt: bb1
316+
317+
bb1:
318+
br bb12(%4 : $Builtin.Int64)
319+
320+
bb2(%12 : $Array<Klass>):
321+
%14 = function_ref @getCount : $@convention(method) (@guaranteed Array<Klass>) -> Int
322+
retain_value %0 : $Optional<Array<Klass>>
323+
retain_value %0 : $Optional<Array<Klass>>
324+
%17 = apply %14(%12) : $@convention(method) (@guaranteed Array<Klass>) -> Int
325+
%18 = struct_extract %17 : $Int, #Int._value
326+
%19 = builtin "cmp_eq_Int64"(%18 : $Builtin.Int64, %4 : $Builtin.Int64) : $Builtin.Int1
327+
cond_br %19, bb3, bb4
328+
329+
bb3:
330+
release_value %0 : $Optional<Array<Klass>>
331+
%22 = unchecked_enum_data %0 : $Optional<Array<Klass>>, #Optional.some!enumelt
332+
%23 = struct_extract %22 : $Array<Klass>, #Array._buffer
333+
%24 = struct_extract %23 : $_ArrayBuffer<Klass>, #_ArrayBuffer._storage
334+
%25 = struct_extract %24 : $_BridgeStorage<__ContiguousArrayStorageBase>, #_BridgeStorage.rawValue
335+
strong_release %25 : $Builtin.BridgeObject
336+
br bb12(%4 : $Builtin.Int64)
337+
338+
bb4:
339+
%28 = function_ref @hoistableIsNativeTypeChecked : $@convention(method) (@guaranteed Array<Klass>) -> Bool
340+
%29 = function_ref @getElement : $@convention(method) (Int, Bool, _DependenceToken, @guaranteed Array<Klass>) -> @owned Klass
341+
%30 = integer_literal $Builtin.Int64, 1
342+
%31 = integer_literal $Builtin.Int1, -1
343+
%32 = struct $_DependenceToken ()
344+
br bb5(%4 : $Builtin.Int64)
345+
346+
bb5(%34 : $Builtin.Int64):
347+
%35 = struct $Int (%34 : $Builtin.Int64)
348+
%36 = apply %28(%12) : $@convention(method) (@guaranteed Array<Klass>) -> Bool
349+
%37 = apply %29(%35, %36, %32, %12) : $@convention(method) (Int, Bool, _DependenceToken, @guaranteed Array<Klass>) -> @owned Klass
350+
%38 = builtin "sadd_with_overflow_Int64"(%34 : $Builtin.Int64, %30 : $Builtin.Int64, %31 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1)
351+
%39 = tuple_extract %38 : $(Builtin.Int64, Builtin.Int1), 0
352+
%40 = tuple_extract %38 : $(Builtin.Int64, Builtin.Int1), 1
353+
cond_fail %40 : $Builtin.Int1, "arithmetic overflow"
354+
%43 = ref_element_addr %37 : $Klass, #Klass.val
355+
%44 = begin_access [read] [dynamic] [no_nested_conflict] %43 : $*Optional<Int>
356+
%45 = load %44 : $*Optional<Int>
357+
end_access %44 : $*Optional<Int>
358+
switch_enum %45 : $Optional<Int>, case #Optional.some!enumelt: bb9, case #Optional.none!enumelt: bb6
359+
360+
bb6:
361+
strong_release %37 : $Klass
362+
%49 = builtin "cmp_eq_Int64"(%39 : $Builtin.Int64, %18 : $Builtin.Int64) : $Builtin.Int1
363+
cond_br %49, bb7, bb8
364+
365+
bb7:
366+
release_value %0 : $Optional<Array<Klass>>
367+
release_value %0 : $Optional<Array<Klass>>
368+
br bb12(%4 : $Builtin.Int64)
369+
370+
bb8:
371+
br bb5(%39 : $Builtin.Int64)
372+
373+
bb9:
374+
release_value %0 : $Optional<Array<Klass>>
375+
%57 = begin_access [read] [dynamic] [no_nested_conflict] %43 : $*Optional<Int>
376+
%58 = load %57 : $*Optional<Int>
377+
end_access %57 : $*Optional<Int>
378+
switch_enum %58 : $Optional<Int>, case #Optional.some!enumelt: bb11, case #Optional.none!enumelt: bb10
379+
380+
bb10:
381+
cond_fail %31 : $Builtin.Int1, "Unexpectedly found nil while unwrapping an Optional value"
382+
unreachable
383+
384+
bb11(%63 : $Int):
385+
release_value %0 : $Optional<Array<Klass>>
386+
strong_release %37 : $Klass
387+
%66 = struct_extract %63 : $Int, #Int._value
388+
br bb12(%66 : $Builtin.Int64)
389+
390+
bb12(%69 : $Builtin.Int64):
391+
%70 = struct $Int (%69 : $Builtin.Int64)
392+
return %70 : $Int
393+
}

0 commit comments

Comments
 (0)