Skip to content

Commit d433e48

Browse files
authored
Merge pull request #64563 from atrick/test-multidefuse
Add a MultiDefUseLivenessTest
2 parents 18fd92e + 37ff9ad commit d433e48

File tree

6 files changed

+141
-19
lines changed

6 files changed

+141
-19
lines changed

include/swift/SILOptimizer/Utils/ParseTestSpecification.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,8 @@ struct Arguments {
155155
template <typename Subtype>
156156
typename Subtype::Stored getInstance(StringRef name, Argument &argument) {
157157
if (isa<Subtype>(argument)) {
158-
auto string = cast<Subtype>(argument).getValue();
159-
return string;
158+
auto stored = cast<Subtype>(argument).getValue();
159+
return stored;
160160
}
161161
llvm::errs() << "Attempting to take a " << name << " argument but have\n";
162162
argument.print(llvm::errs());

lib/SIL/Parser/ParseSIL.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3638,7 +3638,9 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
36383638
return true;
36393639
}
36403640
// Drop the double quotes.
3641-
auto ArgumentsSpecification = P.Tok.getText().drop_front().drop_back();
3641+
unsigned numQuotes = P.Tok.isMultilineString() ? 4 : 1;
3642+
auto ArgumentsSpecification =
3643+
P.Tok.getText().drop_front(numQuotes).drop_back(numQuotes).trim();
36423644
P.consumeToken(tok::string_literal);
36433645
ResultVal = B.createTestSpecificationInst(InstLoc, ArgumentsSpecification);
36443646
break;

lib/SILOptimizer/UtilityPasses/ParseTestSpecification.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -568,7 +568,10 @@ class ParseTestSpecification {
568568
specificationString.split(components, " ");
569569
for (unsigned long index = 0, size = components.size(); index < size;
570570
++index) {
571-
auto componentString = components[index];
571+
auto componentString = components[index].trim();
572+
if (componentString.empty())
573+
continue;
574+
572575
ParseArgumentSpecification parser(*this, componentString,
573576
specification.context);
574577
auto argument = parser.parse();

lib/SILOptimizer/UtilityPasses/UnitTestRunner.cpp

Lines changed: 80 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,11 @@ class UnitTestRunner : public SILFunctionTransform {
124124
<< name << " with: ";
125125
for (unsigned long index = 0, size = components.size(); index < size;
126126
++index) {
127-
llvm::errs() << components[index];
127+
auto componentString = components[index].trim();
128+
if (componentString.empty())
129+
continue;
130+
131+
llvm::errs() << componentString;
128132
if (index != size - 1) {
129133
llvm::errs() << ", ";
130134
}
@@ -364,9 +368,12 @@ struct ScopedAddressLivenessTest : UnitTest {
364368
};
365369

366370
// Arguments:
367-
// - variadic list of live-range defining values
371+
// - variadic list of live-range defining values or instructions
368372
// Dumps:
369373
// - 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.
370377
struct MultiDefLivenessTest : UnitTest {
371378
MultiDefLivenessTest(UnitTestRunner *pass) : UnitTest(pass) {}
372379

@@ -376,9 +383,16 @@ struct MultiDefLivenessTest : UnitTest {
376383

377384
llvm::outs() << "MultiDef lifetime analysis:\n";
378385
while (arguments.hasUntaken()) {
379-
SILValue value = arguments.takeValue();
380-
llvm::outs() << " def: " << value;
381-
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+
}
382396
}
383397
liveness.computeSimple();
384398
liveness.print(llvm::outs());
@@ -389,6 +403,66 @@ struct MultiDefLivenessTest : UnitTest {
389403
}
390404
};
391405

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+
392466
// Arguments:
393467
// - bool: pruneDebug
394468
// - bool: maximizeLifetimes
@@ -811,6 +885,7 @@ void UnitTestRunner::withTest(StringRef name, Doit doit) {
811885
ADD_UNIT_TEST_SUBCLASS("is-lexical", IsLexicalTest)
812886
ADD_UNIT_TEST_SUBCLASS("linear-liveness", LinearLivenessTest)
813887
ADD_UNIT_TEST_SUBCLASS("multidef-liveness", MultiDefLivenessTest)
888+
ADD_UNIT_TEST_SUBCLASS("multidefuse-liveness", MultiDefUseLivenessTest)
814889
ADD_UNIT_TEST_SUBCLASS("ossa-lifetime-completion", OSSALifetimeCompletionTest)
815890
ADD_UNIT_TEST_SUBCLASS("pruned-liveness-boundary-with-list-of-last-users-insertion-points", PrunedLivenessBoundaryWithListOfLastUsersInsertionPointsTest)
816891
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)