Skip to content

Commit f4916bc

Browse files
committed
Add a MultiDefUseLivenessTest
This provides a way to test liveness based on non-SSA values. The move checker is now using pruned liveness this way. So we need a way to test that liveness no longer makes any assumptions about SSA values. These test cases need to explicitly specify all the def and use instructions. (cherry picked from commit 37ff9ad)
1 parent 0b47eb9 commit f4916bc

File tree

3 files changed

+127
-14
lines changed

3 files changed

+127
-14
lines changed

lib/SILOptimizer/UtilityPasses/UnitTestRunner.cpp

Lines changed: 75 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -368,9 +368,12 @@ struct ScopedAddressLivenessTest : UnitTest {
368368
};
369369

370370
// Arguments:
371-
// - variadic list of live-range defining values
371+
// - variadic list of live-range defining values or instructions
372372
// Dumps:
373373
// - the liveness result and boundary
374+
//
375+
// Computes liveness for the specified def nodes by finding all their direct SSA
376+
// uses. If the def is an instruction, then all results are considered.
374377
struct MultiDefLivenessTest : UnitTest {
375378
MultiDefLivenessTest(UnitTestRunner *pass) : UnitTest(pass) {}
376379

@@ -380,9 +383,16 @@ struct MultiDefLivenessTest : UnitTest {
380383

381384
llvm::outs() << "MultiDef lifetime analysis:\n";
382385
while (arguments.hasUntaken()) {
383-
SILValue value = arguments.takeValue();
384-
llvm::outs() << " def: " << value;
385-
liveness.initializeDef(value);
386+
auto argument = arguments.takeArgument();
387+
if (isa<InstructionArgument>(argument)) {
388+
auto *instruction = cast<InstructionArgument>(argument).getValue();
389+
llvm::outs() << " def instruction: " << instruction;
390+
liveness.initializeDef(instruction);
391+
} else {
392+
SILValue value = cast<ValueArgument>(argument).getValue();
393+
llvm::outs() << " def value: " << value;
394+
liveness.initializeDef(value);
395+
}
386396
}
387397
liveness.computeSimple();
388398
liveness.print(llvm::outs());
@@ -393,6 +403,66 @@ struct MultiDefLivenessTest : UnitTest {
393403
}
394404
};
395405

406+
// Arguments:
407+
// - the string "defs:"
408+
// - list of live-range defining values or instructions
409+
// - the string "uses:"
410+
// - variadic list of live-range user instructions
411+
// Dumps:
412+
// - the liveness result and boundary
413+
//
414+
// Computes liveness for the specified def nodes by considering only the
415+
// specified uses. The actual uses of the def nodes are ignored.
416+
//
417+
// This is useful for testing non-ssa liveness, for example, of memory
418+
// locations. In that case, the def nodes may be stores and the uses may be
419+
// destroy_addrs.
420+
struct MultiDefUseLivenessTest : UnitTest {
421+
MultiDefUseLivenessTest(UnitTestRunner *pass) : UnitTest(pass) {}
422+
423+
void invoke(Arguments &arguments) override {
424+
SmallVector<SILBasicBlock *, 8> discoveredBlocks;
425+
MultiDefPrunedLiveness liveness(getFunction(), &discoveredBlocks);
426+
427+
llvm::outs() << "MultiDef lifetime analysis:\n";
428+
if (arguments.takeString() != "defs:") {
429+
llvm::report_fatal_error(
430+
"test specification expects the 'defs:' label\n");
431+
}
432+
while (true) {
433+
auto argument = arguments.takeArgument();
434+
if (isa<InstructionArgument>(argument)) {
435+
auto *instruction = cast<InstructionArgument>(argument).getValue();
436+
llvm::outs() << " def instruction: " << *instruction;
437+
liveness.initializeDef(instruction);
438+
continue;
439+
}
440+
if (isa<ValueArgument>(argument)) {
441+
SILValue value = cast<ValueArgument>(argument).getValue();
442+
llvm::outs() << " def value: " << value;
443+
liveness.initializeDef(value);
444+
continue;
445+
}
446+
if (cast<StringArgument>(argument).getValue() != "uses:") {
447+
llvm::report_fatal_error(
448+
"test specification expects the 'uses:' label\n");
449+
}
450+
break;
451+
}
452+
while (arguments.hasUntaken()) {
453+
auto *inst = arguments.takeInstruction();
454+
// lifetimeEnding has no effects on liveness, it's only a cache for the
455+
// caller.
456+
liveness.updateForUse(inst, /*lifetimeEnding*/false);
457+
}
458+
liveness.print(llvm::outs());
459+
460+
PrunedLivenessBoundary boundary;
461+
liveness.computeBoundary(boundary);
462+
boundary.print(llvm::outs());
463+
}
464+
};
465+
396466
// Arguments:
397467
// - bool: pruneDebug
398468
// - bool: maximizeLifetimes
@@ -815,6 +885,7 @@ void UnitTestRunner::withTest(StringRef name, Doit doit) {
815885
ADD_UNIT_TEST_SUBCLASS("is-lexical", IsLexicalTest)
816886
ADD_UNIT_TEST_SUBCLASS("linear-liveness", LinearLivenessTest)
817887
ADD_UNIT_TEST_SUBCLASS("multidef-liveness", MultiDefLivenessTest)
888+
ADD_UNIT_TEST_SUBCLASS("multidefuse-liveness", MultiDefUseLivenessTest)
818889
ADD_UNIT_TEST_SUBCLASS("ossa-lifetime-completion", OSSALifetimeCompletionTest)
819890
ADD_UNIT_TEST_SUBCLASS("pruned-liveness-boundary-with-list-of-last-users-insertion-points", PrunedLivenessBoundaryWithListOfLastUsersInsertionPointsTest)
820891
ADD_UNIT_TEST_SUBCLASS("shrink-borrow-scope", ShrinkBorrowScopeTest)

test/SILOptimizer/liveness_incomplete_unit.sil

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ bb0(%0 : @guaranteed $C):
7878
//
7979
// CHECK-LABEL: testDeadSelfKill: multidef-liveness
8080
// CHECK: MultiDef lifetime analysis:
81-
// CHECK: def: %1 = argument of bb1 : $C
82-
// CHECK: def: [[V:%.*]] = move_value %1 : $C
81+
// CHECK: def value: %1 = argument of bb1 : $C
82+
// CHECK: def value: [[V:%.*]] = move_value %1 : $C
8383
// CHECK: bb1: LiveWithin
8484
// CHECK: lifetime-ending user: [[V]] = move_value %1 : $C
8585
// CHECK: last user: [[V]] = move_value %1 : $C
@@ -129,8 +129,8 @@ bb0(%0 : @guaranteed $C, %1 : $@thick Never.Type):
129129
//
130130
// CHECK-LABEL: testMultiDefDeadDefBoundaryEdge: multidef-liveness
131131
// CHECK: MultiDef lifetime analysis:
132-
// CHECK: def: [[CP0:%.*]] = copy_value %0 : $C
133-
// CHECK: def: [[CP3:%.*]] = copy_value %0 : $C
132+
// CHECK: def value: [[CP0:%.*]] = copy_value %0 : $C
133+
// CHECK: def value: [[CP3:%.*]] = copy_value %0 : $C
134134
// CHECK: bb0: LiveOut
135135
// CHECK: bb1: LiveWithin
136136
// CHECK: bb2: LiveWithin

test/SILOptimizer/liveness_unit.sil

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ bb3:
7979
//
8080
// CHECK-LABEL: testReborrow: multidef-liveness
8181
// CHECK: MultiDef lifetime analysis:
82-
// CHECK: def: [[B:%.*]] = begin_borrow %0 : $C
83-
// CHECK: def: [[RB:%.*]] = argument of bb3 : $C
82+
// CHECK: def value: [[B:%.*]] = begin_borrow %0 : $C
83+
// CHECK: def value: [[RB:%.*]] = argument of bb3 : $C
8484
// CHECK-NEXT: bb2: LiveWithin
8585
// CHECK-NEXT: bb3: LiveWithin
8686
// CHECK-NEXT: lifetime-ending user: br bb3([[B]] : $C)
@@ -180,10 +180,10 @@ bb0(%0 : @guaranteed $D):
180180
//
181181
// CHECK-LABEL: testMultiDefLiveOutNoBoundary: multidef-liveness
182182
// CHECK: MultiDef lifetime analysis:
183-
// CHECK: def: [[CP0:%.*]] = copy_value %0 : $C
184-
// CHECK: def: %{{.*}} = copy_value %0 : $C
185-
// CHECK: def: %{{.*}} = move_value [[CP0]] : $C
186-
// CHECK: def: %{{.*}} = argument of bb4 : $C
183+
// CHECK: def value: [[CP0:%.*]] = copy_value %0 : $C
184+
// CHECK: def value: %{{.*}} = copy_value %0 : $C
185+
// CHECK: def value: %{{.*}} = move_value [[CP0]] : $C
186+
// CHECK: def value: %{{.*}} = argument of bb4 : $C
187187
// CHECK-NEXT: bb0: LiveOut
188188
// CHECK-NEXT: bb2: LiveWithin
189189
// CHECK-NEXT: bb3: LiveWithin
@@ -503,3 +503,45 @@ bb0(%0 : @guaranteed $C):
503503
%99 = tuple()
504504
return %99 : $()
505505
}
506+
507+
// CHECK-LABEL: begin running test 1 of 1 on testMultiDefUseAddressReinit
508+
// CHECK: MultiDef lifetime analysis:
509+
// CHECK: def instruction: store %{{.*}} to [init] [[ADR:%.*]] : $*C
510+
// CHECK: def instruction: destroy_addr [[ADR]] : $*C
511+
// CHECK: bb0: LiveWithin
512+
// CHECK: bb1: LiveWithin
513+
// CHECK: regular user: %{{.*}} = load [copy] [[ADR]] : $*C
514+
// CHECK: last user: %{{.*}} = load [copy] [[ADR]] : $*C
515+
//
516+
// FIXME: This store is not really a dead def!
517+
// CHECK: dead def: store %2 to [init] %1 : $*C
518+
// CHECK: dead def: destroy_addr %1 : $*C
519+
// CHECK-LABEL: end running test 1 of 1 on testMultiDefUseAddressReinit
520+
sil [ossa] @testMultiDefUseAddressReinit : $@convention(thin) (@owned C) -> () {
521+
bb0(%0: @owned $C):
522+
%1 = alloc_stack $C
523+
%2 = copy_value %0 : $C
524+
test_specification """
525+
multidefuse-liveness defs: @instruction @block[1].instruction[1]
526+
uses: @block[1].instruction[0]
527+
"""
528+
store %2 to [init] %1 : $*C
529+
cond_br undef, bb1, bb2
530+
531+
bb1:
532+
%5 = load [copy] %1 : $*C
533+
destroy_addr %1 : $*C
534+
store %0 to [init] %1 : $*C
535+
destroy_value %5 : $C
536+
br bb3
537+
538+
bb2:
539+
destroy_value %0 : $C
540+
br bb3
541+
542+
bb3:
543+
destroy_addr %1 : $*C
544+
dealloc_stack %1 : $*C
545+
%9999 = tuple ()
546+
return %9999 : $()
547+
}

0 commit comments

Comments
 (0)