Skip to content

Commit 4657a58

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

File tree

2 files changed

+173
-11
lines changed

2 files changed

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

0 commit comments

Comments
 (0)