Skip to content

Commit a6f4658

Browse files
committed
[Evaluator] Indirect evaluation of uncached requests through a separate table.
The bundling of the form of a request (e.g., the storage that makes up a request) with the function that evaluates the request value requires us to perform ad hoc indirection to address the AST —> Sema layering violation. For example, ClassDecl::getSuperclass() calls through the LazyResolver (when available) to form the appropriate request. This means that we cannot use the the request-evaluator’s cache when LazyResolver is null, forcing all cached state into the AST. Provide the evaluator with a zone-based registration system, where each request “zone” (e.g., the type checker’s requests) registers callbacks to evaluate each kind of request within that zone. The evaluator indirects through this table of function pointers, allowing the request classes themselves to be available at a lower level (AST) than the functions that perform the computation when the value isn’t in the cache (e.g., Sema). We are not taking advantage of the indirection yet; that’ll come in a follow-up commit.
1 parent 0418ae4 commit a6f4658

File tree

11 files changed

+130
-21
lines changed

11 files changed

+130
-21
lines changed

include/swift/AST/Evaluator.h

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,23 @@ class raw_ostream;
3737

3838
namespace swift {
3939

40+
using llvm::ArrayRef;
4041
using llvm::Optional;
4142
using llvm::None;
4243

4344
class DiagnosticEngine;
45+
class Evaluator;
4446
class UnifiedStatsReporter;
4547

48+
/// An "abstract" request function pointer, which is the storage type
49+
/// used for each of the
50+
using AbstractRequestFunction = void(void);
51+
52+
/// Form the specific request function for the given request type.
53+
template<typename Request>
54+
using RequestFunction =
55+
typename Request::OutputType(const Request &, Evaluator &);
56+
4657
/// Pretty stack trace handler for an arbitrary request.
4758
template<typename Request>
4859
class PrettyStackTraceRequest : public llvm::PrettyStackTraceEntry {
@@ -138,6 +149,18 @@ class Evaluator {
138149
/// non-null.
139150
UnifiedStatsReporter *stats = nullptr;
140151

152+
/// A vector containing the abstract request functions that can compute
153+
/// the result of a particular request within a given zone. The
154+
/// \c uint8_t is the zone number of the request, and the array is
155+
/// indexed by the index of the request type within that zone. Each
156+
/// entry is a function pointer that will be reinterpret_cast'd to
157+
///
158+
/// RequestType::OutputType (*)(const RequestType &request,
159+
/// Evaluator &evaluator);
160+
/// and called to satisfy the request.
161+
std::vector<std::pair<uint8_t, ArrayRef<AbstractRequestFunction *>>>
162+
requestFunctionsByZone;
163+
141164
/// A vector containing all of the active evaluation requests, which
142165
/// is treated as a stack and is used to detect cycles.
143166
llvm::SetVector<AnyRequest> activeRequests;
@@ -156,6 +179,19 @@ class Evaluator {
156179
/// so all clients must cope with cycles.
157180
llvm::DenseMap<AnyRequest, std::vector<AnyRequest>> dependencies;
158181

182+
/// Retrieve the request function for the given zone and request IDs.
183+
AbstractRequestFunction *getAbstractRequestFunction(uint8_t zoneID,
184+
uint8_t requestID) const;
185+
186+
/// Retrieve the request function for the given request type.
187+
template<typename Request>
188+
auto getRequestFunction() const -> RequestFunction<Request> * {
189+
auto abstractFn = getAbstractRequestFunction(TypeID<Request>::zoneID,
190+
TypeID<Request>::localID);
191+
assert(abstractFn && "No request function for request");
192+
return reinterpret_cast<RequestFunction<Request> *>(abstractFn);
193+
}
194+
159195
public:
160196
/// Construct a new evaluator that can emit cyclic-dependency
161197
/// diagnostics through the given diagnostics engine.
@@ -165,6 +201,13 @@ class Evaluator {
165201
/// statistics will be recorded.
166202
void setStatsReporter(UnifiedStatsReporter *stats) { this->stats = stats; }
167203

204+
/// Register the set of request functions for the given zone.
205+
///
206+
/// These functions will be called to evaluate any requests within that
207+
/// zone.
208+
void registerRequestFunctions(uint8_t zoneID,
209+
ArrayRef<AbstractRequestFunction *> functions);
210+
168211
/// Evaluate the given request and produce its result,
169212
/// consulting/populating the cache as required.
170213
template<typename Request>
@@ -247,7 +290,7 @@ class Evaluator {
247290
/// Update statistics.
248291
if (stats) reportEvaluatedRequest(*stats, request);
249292

250-
return request(*this);
293+
return getRequestFunction<Request>()(request, *this);
251294
}
252295

253296
/// Get the result of a request, consulting an external cache
@@ -301,7 +344,7 @@ class Evaluator {
301344
llvm::raw_ostream &out,
302345
llvm::DenseSet<AnyRequest> &visitedAnywhere,
303346
llvm::SmallVectorImpl<AnyRequest> &visitedAlongPath,
304-
llvm::ArrayRef<AnyRequest> highlightPath,
347+
ArrayRef<AnyRequest> highlightPath,
305348
std::string &prefixStr,
306349
bool lastChild) const;
307350

include/swift/AST/SimpleRequest.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,10 @@ class SimpleRequest {
130130
explicit SimpleRequest(const Inputs& ...inputs)
131131
: storage(inputs...) { }
132132

133-
OutputType operator()(Evaluator &evaluator) const {
134-
return callDerived(evaluator, llvm::index_sequence_for<Inputs...>());
133+
/// Request evaluation function that will be registered with the evaluator.
134+
static OutputType evaluate(const Derived &request, Evaluator &evaluator) {
135+
return request.callDerived(evaluator,
136+
llvm::index_sequence_for<Inputs...>());
135137
}
136138

137139
void diagnoseCycle(DiagnosticEngine &diags) const {

include/swift/Basic/DefineTypeIDZone.h

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,15 @@ template<> struct TypeIDZoneTypes<SWIFT_TYPEID_ZONE> {
4646
};
4747

4848
// Second pass: create specializations of TypeID for these types.
49-
#define SWIFT_TYPEID_NAMED(Type, Name) \
50-
template<> struct TypeID<Type> { \
51-
static const uint64_t value = \
52-
formTypeID(SWIFT_TYPEID_ZONE, \
53-
TypeIDZoneTypes<SWIFT_TYPEID_ZONE>::Name); \
54-
\
55-
static llvm::StringRef getName() { \
56-
return #Name; \
57-
} \
49+
#define SWIFT_TYPEID_NAMED(Type, Name) \
50+
template<> struct TypeID<Type> { \
51+
static const uint8_t zoneID = SWIFT_TYPEID_ZONE; \
52+
static const uint8_t localID = \
53+
TypeIDZoneTypes<SWIFT_TYPEID_ZONE>::Name; \
54+
\
55+
static const uint64_t value = formTypeID(zoneID, localID); \
56+
\
57+
static llvm::StringRef getName() { return #Name; } \
5858
};
5959

6060
#define SWIFT_TYPEID_TEMPLATE1_NAMED(Template, Name, Param1, Arg1) \

include/swift/Sema/TypeCheckRequests.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ class InheritedTypeRequest :
4646

4747
public:
4848
using SimpleRequest::SimpleRequest;
49-
using SimpleRequest::operator();
5049

5150
private:
5251
friend class SimpleRequest;
@@ -76,7 +75,6 @@ class SuperclassTypeRequest :
7675
NominalTypeDecl *> {
7776
public:
7877
using SimpleRequest::SimpleRequest;
79-
using SimpleRequest::operator();
8078

8179
private:
8280
friend class SimpleRequest;
@@ -104,7 +102,6 @@ class EnumRawTypeRequest :
104102
EnumDecl *> {
105103
public:
106104
using SimpleRequest::SimpleRequest;
107-
using SimpleRequest::operator();
108105

109106
private:
110107
friend class SimpleRequest;
@@ -124,7 +121,10 @@ class EnumRawTypeRequest :
124121
void cacheResult(Type value) const;
125122
};
126123

127-
#define SWIFT_TYPEID_ZONE 10
124+
/// The zone number for the type checker.
125+
#define SWIFT_TYPE_CHECKER_REQUESTS_TYPEID_ZONE 10
126+
127+
#define SWIFT_TYPEID_ZONE SWIFT_TYPE_CHECKER_REQUESTS_TYPEID_ZONE
128128
#define SWIFT_TYPEID_HEADER "swift/Sema/TypeCheckerTypeIDZone.def"
129129
#include "swift/Basic/DefineTypeIDZone.h"
130130

include/swift/Sema/TypeCheckerTypeIDZone.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//===--- ArithmeticEvaluatorTypeIDZone.def - --------------------*- C++ -*-===//
1+
//===--- TypeCheckerTypeIDZone.def ------------------------------*- C++ -*-===//
22
//
33
// This source file is part of the Swift.org open source project
44
//

include/swift/Subsystems.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ namespace swift {
4646
class DelayedParsingCallbacks;
4747
class DiagnosticConsumer;
4848
class DiagnosticEngine;
49+
class Evaluator;
4950
class FileUnit;
5051
class GenericEnvironment;
5152
class GenericParamList;
@@ -342,6 +343,13 @@ namespace swift {
342343
struct Implementation;
343344
Implementation &Impl;
344345
};
346+
347+
/// Register the type checker's request functions with the evaluator.
348+
///
349+
/// Clients that form an ASTContext and will perform any semantic
350+
/// queries should call this function after forming the ASTContext.
351+
void registerTypeCheckerRequestFunctions(Evaluator &evaluator);
352+
345353
} // end namespace swift
346354

347355
#endif // SWIFT_SUBSYSTEMS_H

lib/AST/Evaluator.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,32 @@ std::string AnyRequest::getAsString() const {
3232
return result;
3333
}
3434

35+
AbstractRequestFunction *
36+
Evaluator::getAbstractRequestFunction(uint8_t zoneID, uint8_t requestID) const {
37+
for (const auto &zone : requestFunctionsByZone) {
38+
if (zone.first == zoneID) {
39+
if (requestID < zone.second.size())
40+
return zone.second[requestID];
41+
42+
return nullptr;
43+
}
44+
}
45+
46+
return nullptr;
47+
}
48+
49+
void Evaluator::registerRequestFunctions(
50+
uint8_t zoneID,
51+
ArrayRef<AbstractRequestFunction *> functions) {
52+
#ifndef NDEBUG
53+
for (const auto &zone : requestFunctionsByZone) {
54+
assert(zone.first != zoneID);
55+
}
56+
#endif
57+
58+
requestFunctionsByZone.push_back({zoneID, functions});
59+
}
60+
3561
Evaluator::Evaluator(DiagnosticEngine &diags,
3662
CycleDiagnosticKind shouldDiagnoseCycles)
3763
: diags(diags), shouldDiagnoseCycles(shouldDiagnoseCycles) { }

lib/Frontend/Frontend.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ bool CompilerInstance::setup(const CompilerInvocation &Invok) {
152152
Context.reset(ASTContext::get(Invocation.getLangOptions(),
153153
Invocation.getSearchPathOptions(), SourceMgr,
154154
Diagnostics));
155+
registerTypeCheckerRequestFunctions(Context->evaluator);
155156

156157
if (setUpModuleLoaders())
157158
return true;

lib/Sema/TypeCheckRequests.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
#include "swift/AST/ExistentialLayout.h"
1717
#include "swift/AST/TypeLoc.h"
1818
#include "swift/AST/Types.h"
19+
#include "swift/Subsystems.h"
20+
1921
using namespace swift;
2022

2123
namespace swift {
@@ -265,3 +267,16 @@ void EnumRawTypeRequest::cacheResult(Type value) const {
265267
auto enumDecl = std::get<0>(getStorage());
266268
enumDecl->LazySemanticInfo.RawType.setPointerAndInt(value, true);
267269
}
270+
271+
// Define request evaluation functions for each of the type checker requests.
272+
static AbstractRequestFunction *typeCheckerRequestFunctions[] = {
273+
#define SWIFT_TYPEID(Name) \
274+
reinterpret_cast<AbstractRequestFunction *>(&Name::evaluate),
275+
#include "swift/Sema/TypeCheckerTypeIDZone.def"
276+
#undef SWIFT_TYPEID
277+
};
278+
279+
void swift::registerTypeCheckerRequestFunctions(Evaluator &evaluator) {
280+
evaluator.registerRequestFunctions(SWIFT_TYPE_CHECKER_REQUESTS_TYPEID_ZONE,
281+
typeCheckerRequestFunctions);
282+
}

tools/driver/modulewrap_main.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,8 @@ int modulewrap_main(ArrayRef<const char *> Args, const char *Argv0,
171171
LangOpts.Target = Invocation.getTargetTriple();
172172
ASTContext &ASTCtx = *ASTContext::get(LangOpts, SearchPathOpts, SrcMgr,
173173
Instance.getDiags());
174+
registerTypeCheckerRequestFunctions(ASTCtx.evaluator);
175+
174176
ClangImporterOptions ClangImporterOpts;
175177
ASTCtx.addModuleLoader(ClangImporter::create(ASTCtx, ClangImporterOpts, ""),
176178
true);

unittests/AST/ArithmeticEvaluator.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,6 @@ struct EvaluationRule
8787
: public SimpleRequest<Derived, Caching, double, ArithmeticExpr *>
8888
{
8989
using SimpleRequest<Derived, Caching, double, ArithmeticExpr *>::SimpleRequest;
90-
using SimpleRequest<Derived, Caching, double, ArithmeticExpr *>::operator();
9190

9291
double operator()(Evaluator &evaluator, ArithmeticExpr *expr) const {
9392
switch (expr->kind) {
@@ -179,16 +178,25 @@ struct ExternallyCachedEvaluationRule
179178

180179
// Define the arithmetic evaluator's zone.
181180
namespace swift {
182-
#define SWIFT_TYPEID_ZONE 255
181+
#define SWIFT_ARITHMETIC_EVALUATOR_ZONE 255
182+
#define SWIFT_TYPEID_ZONE SWIFT_ARITHMETIC_EVALUATOR_ZONE
183183
#define SWIFT_TYPEID_HEADER "ArithmeticEvaluatorTypeIDZone.def"
184184
#include "swift/Basic/DefineTypeIDZone.h"
185185

186-
#define SWIFT_TYPEID_ZONE 255
186+
#define SWIFT_TYPEID_ZONE SWIFT_ARITHMETIC_EVALUATOR_ZONE
187187
#define SWIFT_TYPEID_HEADER "ArithmeticEvaluatorTypeIDZone.def"
188188
#include "swift/Basic/ImplementTypeIDZone.h"
189189

190190
}
191191

192+
/// All of the arithmetic request functions.
193+
static AbstractRequestFunction *arithmeticRequestFunctions[] = {
194+
#define SWIFT_TYPEID(Name) \
195+
reinterpret_cast<AbstractRequestFunction *>(&Name::evaluate),
196+
#include "ArithmeticEvaluatorTypeIDZone.def"
197+
#undef SWIFT_TYPEID
198+
};
199+
192200
TEST(ArithmeticEvaluator, Simple) {
193201
// (3.14159 + 2.71828) * 42
194202
ArithmeticExpr *pi = new Literal(3.14159);
@@ -201,6 +209,8 @@ TEST(ArithmeticEvaluator, Simple) {
201209
SourceManager sourceMgr;
202210
DiagnosticEngine diags(sourceMgr);
203211
Evaluator evaluator(diags, CycleDiagnosticKind::FullDiagnose);
212+
evaluator.registerRequestFunctions(SWIFT_ARITHMETIC_EVALUATOR_ZONE,
213+
arithmeticRequestFunctions);
204214

205215
const double expectedResult = (3.14159 + 2.71828) * 42.0;
206216
EXPECT_EQ(evaluator(InternallyCachedEvaluationRule(product)),
@@ -321,6 +331,8 @@ TEST(ArithmeticEvaluator, Cycle) {
321331
SourceManager sourceMgr;
322332
DiagnosticEngine diags(sourceMgr);
323333
Evaluator evaluator(diags, CycleDiagnosticKind::FullDiagnose);
334+
evaluator.registerRequestFunctions(SWIFT_ARITHMETIC_EVALUATOR_ZONE,
335+
arithmeticRequestFunctions);
324336

325337
// Evaluate when there is a cycle.
326338
UncachedEvaluationRule::brokeCycle = false;

0 commit comments

Comments
 (0)