Skip to content

Commit 82cd580

Browse files
committed
[SILOptimizer] Add faux unit testing mechanism.
The testing works by way of a new pass "UnitTestRunner" and a new instruction test_specification. When a function contains test_specification instructions, it invokes the UnitTest subclass named in the test_specification instruction with the arguments specified in that instruction. For example, when running the unit-test-runner class, having the instructions ``` test_specification "my-neato-utility 19 @function[callee].block[2] @trace[2]" test_specification "my-neato-utility 43 @block @trace" ``` would result in the test associated with "my-neato-utility" in UnitTestRunner.cpp being invoked twice. Once with (19, aBlock, aValue), and once with (43, anotherBlock, someOtherValue). That UnitTest subclass class would need to call takeUInt, takeBlock, and takeTrace on the Arguments struct it is invoked with. It would then pass those arguments along to myNeatoUtility and dump out interesting results. The results would then be FileChecked.
1 parent ab35362 commit 82cd580

File tree

6 files changed

+945
-1
lines changed

6 files changed

+945
-1
lines changed

include/swift/SILOptimizer/PassManager/Passes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,8 @@ PASS(SimplifyUnreachableContainingBlocks, "simplify-unreachable-containing-block
445445
"Utility pass. Removes all non-term insts from blocks with unreachable terms")
446446
PASS(SerializeSILPass, "serialize-sil",
447447
"Utility pass. Serializes the current SILModule")
448+
PASS(UnitTestRunner, "unit-test-runner",
449+
"Utility pass. Parses arguments and runs code with them.")
448450
PASS(YieldOnceCheck, "yield-once-check",
449451
"Check correct usage of yields in yield-once coroutines")
450452
PASS(OSLogOptimization, "os-log-optimization", "Optimize os log calls")
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
//===- ParseTestSpecification.h - Parsing for test instructions -*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file defines Test::Argument.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef SWIFT_SIL_PARSETESTSPECIFICATION
18+
#define SWIFT_SIL_PARSETESTSPECIFICATION
19+
20+
#include "swift/Basic/TaggedUnion.h"
21+
#include "swift/SIL/SILValue.h"
22+
#include "llvm/ADT/StringRef.h"
23+
24+
namespace llvm {
25+
template <class T>
26+
class SmallVectorImpl;
27+
}
28+
using llvm::StringRef;
29+
30+
namespace swift {
31+
32+
class SILFunction;
33+
34+
namespace test {
35+
36+
struct Argument {
37+
enum class Kind {
38+
String,
39+
Bool,
40+
UInt,
41+
Value,
42+
Operand,
43+
Instruction,
44+
Block,
45+
Function,
46+
};
47+
using Union = TaggedUnion<StringRef, // StringArgument
48+
bool, // BoolArgument
49+
unsigned long long, // UIntArgument
50+
SILValue, // ValueArgument
51+
Operand *, // OperandArgument
52+
SILInstruction *, // InstructionArgument
53+
SILBasicBlock *, // BlockArgument
54+
SILFunction * // FunctionArgument
55+
>;
56+
57+
private:
58+
Kind kind;
59+
60+
protected:
61+
Argument(Union storage, Kind kind) : kind(kind), storage(storage) {}
62+
Union storage;
63+
64+
public:
65+
Kind getKind() const { return kind; }
66+
};
67+
68+
template <typename Stored, Argument::Kind TheKind>
69+
struct ConcreteArgument : Argument {
70+
using Super = ConcreteArgument<Stored, TheKind>;
71+
ConcreteArgument(Stored stored) : Argument(Union{stored}, TheKind) {}
72+
Stored getValue() { return storage.get<Stored>(); }
73+
static bool classof(const Argument *argument) {
74+
return argument->getKind() == TheKind;
75+
}
76+
};
77+
78+
struct ValueArgument : ConcreteArgument<SILValue, Argument::Kind::Value> {
79+
ValueArgument(SILValue stored) : Super(stored) {}
80+
};
81+
82+
struct OperandArgument : ConcreteArgument<Operand *, Argument::Kind::Operand> {
83+
OperandArgument(Operand *stored) : Super(stored) {}
84+
};
85+
86+
struct InstructionArgument
87+
: ConcreteArgument<SILInstruction *, Argument::Kind::Instruction> {
88+
InstructionArgument(SILInstruction *stored) : Super(stored) {}
89+
};
90+
91+
struct BlockArgument
92+
: ConcreteArgument<SILBasicBlock *, Argument::Kind::Block> {
93+
BlockArgument(SILBasicBlock *stored) : Super(stored) {}
94+
};
95+
96+
struct FunctionArgument
97+
: ConcreteArgument<SILFunction *, Argument::Kind::Function> {
98+
FunctionArgument(SILFunction *stored) : Super(stored) {}
99+
};
100+
101+
struct BoolArgument : ConcreteArgument<bool, Argument::Kind::Bool> {
102+
BoolArgument(bool stored) : Super(stored) {}
103+
};
104+
105+
struct UIntArgument
106+
: ConcreteArgument<unsigned long long, Argument::Kind::UInt> {
107+
UIntArgument(unsigned long long stored) : Super(stored) {}
108+
};
109+
110+
struct StringArgument : ConcreteArgument<StringRef, Argument::Kind::String> {
111+
StringArgument(StringRef stored) : Super(stored) {}
112+
};
113+
114+
struct Arguments {
115+
llvm::SmallVector<Argument, 8> storage;
116+
unsigned untakenIndex = 0;
117+
118+
void assertUsed() {
119+
assert(untakenIndex == storage.size() && "arguments remain!");
120+
}
121+
122+
void clear() {
123+
assertUsed();
124+
storage.clear();
125+
untakenIndex = 0;
126+
}
127+
128+
Arguments() {}
129+
Arguments(Arguments const &) = delete;
130+
Arguments &operator=(Arguments const &) = delete;
131+
~Arguments() { assertUsed(); }
132+
Argument &takeArgument() { return storage[untakenIndex++]; }
133+
StringRef takeString() {
134+
return cast<StringArgument>(takeArgument()).getValue();
135+
}
136+
bool takeBool() { return cast<BoolArgument>(takeArgument()).getValue(); }
137+
unsigned long long takeUInt() {
138+
return cast<UIntArgument>(takeArgument()).getValue();
139+
}
140+
SILValue takeValue() {
141+
return cast<ValueArgument>(takeArgument()).getValue();
142+
}
143+
Operand *takeOperand() {
144+
return cast<OperandArgument>(takeArgument()).getValue();
145+
}
146+
SILInstruction *takeInstruction() {
147+
return cast<InstructionArgument>(takeArgument()).getValue();
148+
}
149+
SILBasicBlock *takeBlock() {
150+
return cast<BlockArgument>(takeArgument()).getValue();
151+
}
152+
SILFunction *takeFunction() {
153+
return cast<FunctionArgument>(takeArgument()).getValue();
154+
}
155+
};
156+
157+
/// Finds and deletes each test_specification instruction in \p function and
158+
/// appends its string payload to the provided vector.
159+
void getTestSpecifications(SILFunction *function,
160+
SmallVectorImpl<std::string> &specifications);
161+
162+
void parseTestArgumentsFromSpecification(
163+
SILFunction *, StringRef specification, Arguments &arguments,
164+
SmallVectorImpl<StringRef> &argumentStrings);
165+
166+
} // namespace test
167+
} // namespace swift
168+
169+
#endif

lib/SILOptimizer/UtilityPasses/CMakeLists.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,8 @@ target_sources(swiftSILOptimizer PRIVATE
3434
SideEffectsDumper.cpp
3535
SimplifyUnreachableContainingBlocks.cpp
3636
StripDebugInfo.cpp
37+
UnitTestRunner.cpp
3738
OwnershipDumper.cpp
38-
OwnershipVerifierTextualErrorDumper.cpp)
39+
OwnershipVerifierTextualErrorDumper.cpp
40+
ParseTestSpecification.cpp)
41+

0 commit comments

Comments
 (0)