Skip to content

Commit bb7363d

Browse files
committed
[const evaluator] Parameterize allocation of symbolic values in the
constant interpreter. Based on this, change to a short-lived bump allocator for storing symbolic values in the pass that checks #assert.
1 parent 93632f0 commit bb7363d

File tree

5 files changed

+122
-87
lines changed

5 files changed

+122
-87
lines changed

include/swift/SIL/SILConstants.h

Lines changed: 52 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,45 @@ enum class UnknownReason {
6060
Trap,
6161
};
6262

63+
/// An abstract class that exposes functions for allocating symbolic values.
64+
/// The implementors of this class have to determine where to allocate them and
65+
/// and manage the lifetime of the allocated symbolic values.
66+
class SymbolicValueAllocator {
67+
public:
68+
virtual ~SymbolicValueAllocator() {}
69+
70+
/// Allocate raw bytes.
71+
/// \param byteSize number of bytes to allocate.
72+
/// \param alignment alignment for the allocated bytes.
73+
virtual void *allocate(unsigned long byteSize, unsigned alignment) = 0;
74+
75+
/// Allocate storage for a given number of elements of a specific type
76+
/// provided as a template parameter. Precondition: \c T must have an
77+
/// accesible zero argument constructor.
78+
/// \param numElts number of elements of the type to allocate.
79+
template <typename T> T *allocate(unsigned numElts) {
80+
T *res = (T *)allocate(sizeof(T) * numElts, alignof(T));
81+
for (unsigned i = 0; i != numElts; ++i)
82+
new (res + i) T();
83+
return res;
84+
}
85+
};
86+
87+
/// A class that allocates symbolic values in a local bump allocator. The
88+
/// lifetime of the bump allocator is same as the lifetime of \c this object.
89+
class SymbolicValueBumpAllocator : public SymbolicValueAllocator {
90+
private:
91+
llvm::BumpPtrAllocator bumpAllocator;
92+
93+
public:
94+
SymbolicValueBumpAllocator() {}
95+
~SymbolicValueBumpAllocator() {}
96+
97+
void *allocate(unsigned long byteSize, unsigned alignment) {
98+
return bumpAllocator.Allocate(byteSize, alignment);
99+
}
100+
};
101+
63102
/// This is the symbolic value tracked for each SILValue in a scope. We
64103
/// support multiple representational forms for the constant node in order to
65104
/// avoid pointless memory bloat + copying. This is intended to be a
@@ -225,7 +264,7 @@ class SymbolicValue {
225264

226265
static SymbolicValue getUnknown(SILNode *node, UnknownReason reason,
227266
llvm::ArrayRef<SourceLoc> callStack,
228-
ASTContext &astContext);
267+
SymbolicValueAllocator &allocator);
229268

230269
/// Return true if this represents an unknown result.
231270
bool isUnknown() const { return getKind() == Unknown; }
@@ -272,22 +311,22 @@ class SymbolicValue {
272311

273312
static SymbolicValue getInteger(int64_t value, unsigned bitWidth);
274313
static SymbolicValue getInteger(const APInt &value,
275-
ASTContext &astContext);
314+
SymbolicValueAllocator &allocator);
276315

277316
APInt getIntegerValue() const;
278317
unsigned getIntegerValueBitWidth() const;
279318

280319
/// Returns a SymbolicValue representing a UTF-8 encoded string.
281320
static SymbolicValue getString(StringRef string,
282-
ASTContext &astContext);
321+
SymbolicValueAllocator &allocator);
283322

284323
/// Returns the UTF-8 encoded string underlying a SymbolicValue.
285324
StringRef getStringValue() const;
286325

287326
/// This returns an aggregate value with the specified elements in it. This
288-
/// copies the elements into the specified ASTContext.
327+
/// copies the elements into the specified Allocator.
289328
static SymbolicValue getAggregate(ArrayRef<SymbolicValue> elements,
290-
ASTContext &astContext);
329+
SymbolicValueAllocator &allocator);
291330

292331
ArrayRef<SymbolicValue> getAggregateValue() const;
293332

@@ -304,7 +343,7 @@ class SymbolicValue {
304343
/// `payload` must be a constant.
305344
static SymbolicValue getEnumWithPayload(EnumElementDecl *decl,
306345
SymbolicValue payload,
307-
ASTContext &astContext);
346+
SymbolicValueAllocator &allocator);
308347

309348
EnumElementDecl *getEnumValue() const;
310349

@@ -322,7 +361,7 @@ class SymbolicValue {
322361
/// indexed by a path.
323362
static SymbolicValue getAddress(SymbolicValueMemoryObject *memoryObject,
324363
ArrayRef<unsigned> indices,
325-
ASTContext &astContext);
364+
SymbolicValueAllocator &allocator);
326365

327366
/// Return the memory object of this reference along with any access path
328367
/// indices involved.
@@ -345,9 +384,9 @@ class SymbolicValue {
345384
/// reason, we fall back to using the specified location.
346385
void emitUnknownDiagnosticNotes(SILLocation fallbackLoc);
347386

348-
/// Clone this SymbolicValue into the specified ASTContext and return the new
349-
/// version. This only works for valid constants.
350-
SymbolicValue cloneInto(ASTContext &astContext) const;
387+
/// Clone this SymbolicValue into the specified Allocator and return the new
388+
/// version. This only works for valid constants.
389+
SymbolicValue cloneInto(SymbolicValueAllocator &allocator) const;
351390

352391
void print(llvm::raw_ostream &os, unsigned indent = 0) const;
353392
void dump() const;
@@ -374,7 +413,7 @@ struct SymbolicValueMemoryObject {
374413

375414
/// Create a new memory object whose overall type is as specified.
376415
static SymbolicValueMemoryObject *create(Type type, SymbolicValue value,
377-
ASTContext &astContext);
416+
SymbolicValueAllocator &allocator);
378417

379418
/// Given that this memory object contains an aggregate value like
380419
/// {{1, 2}, 3}, and given an access path like [0,1], return the indexed
@@ -392,7 +431,8 @@ struct SymbolicValueMemoryObject {
392431
///
393432
/// Precondition: The access path must be valid for this memory object's type.
394433
void setIndexedElement(ArrayRef<unsigned> accessPath,
395-
SymbolicValue newElement, ASTContext &astCtx);
434+
SymbolicValue newElement,
435+
SymbolicValueAllocator &allocator);
396436

397437
private:
398438
const Type type;

include/swift/SILOptimizer/Utils/ConstExpr.h

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626

2727
#include "swift/Basic/LLVM.h"
2828
#include "swift/Basic/SourceLoc.h"
29-
#include "llvm/Support/Allocator.h"
3029

3130
namespace swift {
3231
class ApplyInst;
@@ -37,15 +36,13 @@ class SILModule;
3736
class SILNode;
3837
class SILValue;
3938
class SymbolicValue;
39+
class SymbolicValueAllocator;
4040
enum class UnknownReason;
4141

4242
/// This class is the main entrypoint for evaluating constant expressions. It
4343
/// also handles caching of previously computed constexpr results.
4444
class ConstExprEvaluator {
45-
/// We store arguments and result values for the cached constexpr calls we
46-
/// have already analyzed in this ASTContext so that they are available even
47-
/// after this ConstExprEvaluator is gone.
48-
ASTContext &astContext;
45+
SymbolicValueAllocator &allocator;
4946

5047
/// The current call stack, used for providing accurate diagnostics.
5148
llvm::SmallVector<SourceLoc, 4> callStack;
@@ -54,10 +51,10 @@ class ConstExprEvaluator {
5451
void operator=(const ConstExprEvaluator &) = delete;
5552

5653
public:
57-
explicit ConstExprEvaluator(SILModule &m);
54+
explicit ConstExprEvaluator(SymbolicValueAllocator &alloc);
5855
~ConstExprEvaluator();
5956

60-
ASTContext &getASTContext() { return astContext; }
57+
SymbolicValueAllocator &getAllocator() { return allocator; }
6158

6259
void pushCallStack(SourceLoc loc) { callStack.push_back(loc); }
6360

lib/SIL/SILConstants.cpp

Lines changed: 37 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ SymbolicValue::Kind SymbolicValue::getKind() const {
143143
/// Clone this SymbolicValue into the specified ASTContext and return the new
144144
/// version. This only works for valid constants.
145145
SymbolicValue
146-
SymbolicValue::cloneInto(ASTContext &astContext) const {
146+
SymbolicValue::cloneInto(SymbolicValueAllocator &allocator) const {
147147
auto thisRK = representationKind;
148148
switch (thisRK) {
149149
case RK_UninitMemory:
@@ -156,26 +156,26 @@ SymbolicValue::cloneInto(ASTContext &astContext) const {
156156
return *this;
157157
case RK_IntegerInline:
158158
case RK_Integer:
159-
return SymbolicValue::getInteger(getIntegerValue(), astContext);
159+
return SymbolicValue::getInteger(getIntegerValue(), allocator);
160160
case RK_String:
161-
return SymbolicValue::getString(getStringValue(), astContext);
161+
return SymbolicValue::getString(getStringValue(), allocator);
162162
case RK_Aggregate: {
163163
auto elts = getAggregateValue();
164164
SmallVector<SymbolicValue, 4> results;
165165
results.reserve(elts.size());
166166
for (auto elt : elts)
167-
results.push_back(elt.cloneInto(astContext));
168-
return getAggregate(results, astContext);
167+
results.push_back(elt.cloneInto(allocator));
168+
return getAggregate(results, allocator);
169169
}
170170
case RK_EnumWithPayload:
171-
return getEnumWithPayload(getEnumValue(), getEnumPayloadValue(), astContext);
171+
return getEnumWithPayload(getEnumValue(), getEnumPayloadValue(), allocator);
172172
case RK_DirectAddress:
173173
case RK_DerivedAddress: {
174174
SmallVector<unsigned, 4> accessPath;
175175
auto *memObject = getAddressValue(accessPath);
176176
auto *newMemObject = SymbolicValueMemoryObject::create(
177-
memObject->getType(), memObject->getValue(), astContext);
178-
return getAddress(newMemObject, accessPath, astContext);
177+
memObject->getType(), memObject->getValue(), allocator);
178+
return getAddress(newMemObject, accessPath, allocator);
179179
}
180180
}
181181
}
@@ -186,9 +186,9 @@ SymbolicValue::cloneInto(ASTContext &astContext) const {
186186

187187
SymbolicValueMemoryObject *
188188
SymbolicValueMemoryObject::create(Type type, SymbolicValue value,
189-
ASTContext &astContext) {
190-
auto *result = astContext.Allocate(sizeof(SymbolicValueMemoryObject),
191-
alignof(SymbolicValueMemoryObject));
189+
SymbolicValueAllocator &allocator) {
190+
auto *result = allocator.allocate(sizeof(SymbolicValueMemoryObject),
191+
alignof(SymbolicValueMemoryObject));
192192
new (result) SymbolicValueMemoryObject(type, value);
193193
return (SymbolicValueMemoryObject *)result;
194194
}
@@ -206,14 +206,14 @@ SymbolicValue SymbolicValue::getInteger(int64_t value, unsigned bitWidth) {
206206
}
207207

208208
SymbolicValue SymbolicValue::getInteger(const APInt &value,
209-
ASTContext &astContext) {
209+
SymbolicValueAllocator &allocator) {
210210
// In the common case, we can form an inline representation.
211211
unsigned numWords = value.getNumWords();
212212
if (numWords == 1)
213213
return getInteger(value.getRawData()[0], value.getBitWidth());
214214

215-
// Copy the integers from the APInt into the bump pointer.
216-
auto *words = astContext.Allocate<uint64_t>(numWords).data();
215+
// Copy the integers from the APInt into the allocator.
216+
auto *words = allocator.allocate<uint64_t>(numWords);
217217
std::uninitialized_copy(value.getRawData(), value.getRawData() + numWords,
218218
words);
219219

@@ -251,11 +251,11 @@ unsigned SymbolicValue::getIntegerValueBitWidth() const {
251251

252252
// Returns a SymbolicValue representing a UTF-8 encoded string.
253253
SymbolicValue SymbolicValue::getString(StringRef string,
254-
ASTContext &astContext) {
254+
SymbolicValueAllocator &allocator) {
255255
// TODO: Could have an inline representation for strings if thre was demand,
256256
// just store a char[8] as the storage.
257257

258-
auto *resultPtr = astContext.Allocate<char>(string.size()).data();
258+
auto *resultPtr = allocator.allocate<char>(string.size());
259259
std::uninitialized_copy(string.begin(), string.end(), resultPtr);
260260

261261
SymbolicValue result;
@@ -280,10 +280,9 @@ StringRef SymbolicValue::getStringValue() const {
280280
/// This returns a constant Symbolic value with the specified elements in it.
281281
/// This assumes that the elements lifetime has been managed for this.
282282
SymbolicValue SymbolicValue::getAggregate(ArrayRef<SymbolicValue> elements,
283-
ASTContext &astContext) {
283+
SymbolicValueAllocator &allocator) {
284284
// Copy the elements into the bump pointer.
285-
auto *resultElts =
286-
astContext.Allocate<SymbolicValue>(elements.size()).data();
285+
auto *resultElts = allocator.allocate<SymbolicValue>(elements.size());
287286
std::uninitialized_copy(elements.begin(), elements.end(), resultElts);
288287

289288
SymbolicValue result;
@@ -320,10 +319,10 @@ struct alignas(SourceLoc) UnknownSymbolicValue final
320319

321320
static UnknownSymbolicValue *create(SILNode *node, UnknownReason reason,
322321
ArrayRef<SourceLoc> elements,
323-
ASTContext &astContext) {
322+
SymbolicValueAllocator &allocator) {
324323
auto byteSize =
325324
UnknownSymbolicValue::totalSizeToAlloc<SourceLoc>(elements.size());
326-
auto *rawMem = astContext.Allocate(byteSize, alignof(UnknownSymbolicValue));
325+
auto *rawMem = allocator.allocate(byteSize, alignof(UnknownSymbolicValue));
327326

328327
// Placement-new the value inside the memory we just allocated.
329328
auto value = ::new (rawMem) UnknownSymbolicValue(
@@ -353,12 +352,12 @@ struct alignas(SourceLoc) UnknownSymbolicValue final
353352

354353
SymbolicValue SymbolicValue::getUnknown(SILNode *node, UnknownReason reason,
355354
llvm::ArrayRef<SourceLoc> callStack,
356-
ASTContext &astContext) {
355+
SymbolicValueAllocator &allocator) {
357356
assert(node && "node must be present");
358357
SymbolicValue result;
359358
result.representationKind = RK_Unknown;
360359
result.value.unknown =
361-
UnknownSymbolicValue::create(node, reason, callStack, astContext);
360+
UnknownSymbolicValue::create(node, reason, callStack, allocator);
362361
return result;
363362
}
364363

@@ -402,10 +401,10 @@ struct EnumWithPayloadSymbolicValue final {
402401
/// payload.
403402
SymbolicValue
404403
SymbolicValue::getEnumWithPayload(EnumElementDecl *decl, SymbolicValue payload,
405-
ASTContext &astContext) {
404+
SymbolicValueAllocator &allocator) {
406405
assert(decl && payload.isConstant());
407-
auto rawMem = astContext.Allocate(sizeof(EnumWithPayloadSymbolicValue),
408-
alignof(EnumWithPayloadSymbolicValue));
406+
auto rawMem = allocator.allocate(sizeof(EnumWithPayloadSymbolicValue),
407+
alignof(EnumWithPayloadSymbolicValue));
409408
auto enumVal = ::new (rawMem) EnumWithPayloadSymbolicValue(decl, payload);
410409

411410
SymbolicValue result;
@@ -446,10 +445,10 @@ struct DerivedAddressValue final
446445

447446
static DerivedAddressValue *create(SymbolicValueMemoryObject *memoryObject,
448447
ArrayRef<unsigned> elements,
449-
ASTContext &astContext) {
448+
SymbolicValueAllocator &allocator) {
450449
auto byteSize =
451450
DerivedAddressValue::totalSizeToAlloc<unsigned>(elements.size());
452-
auto *rawMem = astContext.Allocate(byteSize, alignof(DerivedAddressValue));
451+
auto *rawMem = allocator.allocate(byteSize, alignof(DerivedAddressValue));
453452

454453
// Placement initialize the object.
455454
auto dav =
@@ -483,11 +482,11 @@ struct DerivedAddressValue final
483482
/// indexed by a path.
484483
SymbolicValue SymbolicValue::getAddress(SymbolicValueMemoryObject *memoryObject,
485484
ArrayRef<unsigned> indices,
486-
ASTContext &astContext) {
485+
SymbolicValueAllocator &allocator) {
487486
if (indices.empty())
488487
return getAddress(memoryObject);
489488

490-
auto dav = DerivedAddressValue::create(memoryObject, indices, astContext);
489+
auto dav = DerivedAddressValue::create(memoryObject, indices, allocator);
491490
SymbolicValue result;
492491
result.representationKind = RK_DerivedAddress;
493492
result.value.derivedAddress = dav;
@@ -694,7 +693,7 @@ SymbolicValueMemoryObject::getIndexedElement(ArrayRef<unsigned> accessPath) {
694693
static SymbolicValue setIndexedElement(SymbolicValue aggregate,
695694
ArrayRef<unsigned> accessPath,
696695
SymbolicValue newElement, Type type,
697-
ASTContext &astCtx) {
696+
SymbolicValueAllocator &allocator) {
698697
// We're done if we've run out of access path.
699698
if (accessPath.empty())
700699
return newElement;
@@ -715,7 +714,7 @@ static SymbolicValue setIndexedElement(SymbolicValue aggregate,
715714

716715
SmallVector<SymbolicValue, 4> newElts(numMembers,
717716
SymbolicValue::getUninitMemory());
718-
aggregate = SymbolicValue::getAggregate(newElts, astCtx);
717+
aggregate = SymbolicValue::getAggregate(newElts, allocator);
719718
}
720719

721720
assert(aggregate.getKind() == SymbolicValue::Aggregate &&
@@ -738,12 +737,11 @@ static SymbolicValue setIndexedElement(SymbolicValue aggregate,
738737

739738
// Update the indexed element of the aggregate.
740739
SmallVector<SymbolicValue, 4> newElts(oldElts.begin(), oldElts.end());
741-
newElts[elementNo] = setIndexedElement(newElts[elementNo],
742-
accessPath.drop_front(), newElement,
743-
eltType, astCtx);
744-
745-
aggregate = SymbolicValue::getAggregate(newElts, astCtx);
740+
newElts[elementNo] =
741+
setIndexedElement(newElts[elementNo], accessPath.drop_front(), newElement,
742+
eltType, allocator);
746743

744+
aggregate = SymbolicValue::getAggregate(newElts, allocator);
747745
return aggregate;
748746
}
749747

@@ -755,6 +753,6 @@ static SymbolicValue setIndexedElement(SymbolicValue aggregate,
755753
/// Precondition: The access path must be valid for this memory object's type.
756754
void SymbolicValueMemoryObject::setIndexedElement(
757755
ArrayRef<unsigned> accessPath, SymbolicValue newElement,
758-
ASTContext &astCtx) {
759-
value = ::setIndexedElement(value, accessPath, newElement, type, astCtx);
756+
SymbolicValueAllocator &allocator) {
757+
value = ::setIndexedElement(value, accessPath, newElement, type, allocator);
760758
}

lib/SILOptimizer/Mandatory/DataflowDiagnostics.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,8 @@ class EmitDFDiagnostics : public SILFunctionTransform {
175175
}
176176

177177
if (M.getASTContext().LangOpts.EnableExperimentalStaticAssert) {
178-
ConstExprEvaluator constantEvaluator(M);
178+
SymbolicValueBumpAllocator allocator;
179+
ConstExprEvaluator constantEvaluator(allocator);
179180
for (auto &BB : *getFunction())
180181
for (auto &I : BB)
181182
diagnosePoundAssert(&I, M, constantEvaluator);

0 commit comments

Comments
 (0)