Skip to content

Commit 874bb1d

Browse files
Marc Rasiravikandhadai
authored andcommitted
[Constant Evaluator] Support Array constants in the constant
evaluator. Add support for evaluating array initializations and array append.
1 parent be87bd1 commit 874bb1d

File tree

6 files changed

+701
-26
lines changed

6 files changed

+701
-26
lines changed

include/swift/SIL/SILConstants.h

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,7 @@ class SILValue;
2828
class SILBuilder;
2929
class SerializedSILLoader;
3030

31-
struct APIntSymbolicValue;
32-
struct ArraySymbolicValue;
31+
struct SymbolicArrayStorage;
3332
struct DerivedAddressValue;
3433
struct EnumWithPayloadSymbolicValue;
3534
struct SymbolicValueMemoryObject;
@@ -256,6 +255,12 @@ class SymbolicValue {
256255

257256
/// This represents an index *into* a memory object.
258257
RK_DerivedAddress,
258+
259+
/// This represents the internal storage of an array.
260+
RK_ArrayStorage,
261+
262+
/// This represents an array.
263+
RK_Array,
259264
};
260265

261266
union {
@@ -299,6 +304,31 @@ class SymbolicValue {
299304
/// When this SymbolicValue is of "DerivedAddress" kind, this pointer stores
300305
/// information about the memory object and access path of the access.
301306
DerivedAddressValue *derivedAddress;
307+
308+
// The following fields are for representing an Array.
309+
//
310+
// In Swift, an array is a non-trivial struct that stores a reference to an
311+
// internal storage: _ContiguousArrayStorage. Though arrays have value
312+
// semantics in Swift, it is not the case in SIL. In SIL, an array can be
313+
// mutated by taking the address of the internal storage i.e., through a
314+
// shared, mutable pointer to the internal storage of the array. In fact,
315+
// this is how an array initialization is lowered in SIL. Therefore, the
316+
// symbolic representation of an array is an addressable "memory cell"
317+
// (i.e., a SymbolicValueMemoryObject) containing the array storage. The
318+
// array storage is modeled by the type: SymbolicArrayStorage. This
319+
// representation of the array enables obtaining the address of the internal
320+
// storage and modifying the array through that address. Array operations
321+
// such as `append` that mutate an array must clone the internal storage of
322+
// the array, following the semantics of the Swift implementation of those
323+
// operations.
324+
325+
/// Representation of array storage (RK_ArrayStorage). SymbolicArrayStorage
326+
/// is a container for a sequence of symbolic values.
327+
SymbolicArrayStorage *arrayStorage;
328+
329+
/// When this symbolic value is of an "Array" kind, this stores a memory
330+
/// object that contains a SymbolicArrayStorage value.
331+
SymbolicValueMemoryObject *array;
302332
} value;
303333

304334
RepresentationKind representationKind : 8;
@@ -348,6 +378,12 @@ class SymbolicValue {
348378
/// This value represents the address of, or into, a memory object.
349379
Address,
350380

381+
/// This represents an internal array storage.
382+
ArrayStorage,
383+
384+
/// This represents an array value.
385+
Array,
386+
351387
/// These values are generally only seen internally to the system, external
352388
/// clients shouldn't have to deal with them.
353389
UninitMemory
@@ -471,6 +507,32 @@ class SymbolicValue {
471507
/// Return just the memory object for an address value.
472508
SymbolicValueMemoryObject *getAddressValueMemoryObject() const;
473509

510+
/// Create a symbolic array storage containing \c elements.
511+
static SymbolicValue
512+
getSymbolicArrayStorage(ArrayRef<SymbolicValue> elements, CanType elementType,
513+
SymbolicValueAllocator &allocator);
514+
515+
/// Create a symbolic array using the given symbolic array storage, which
516+
/// contains the array elements.
517+
static SymbolicValue getArray(Type arrayType, SymbolicValue arrayStorage,
518+
SymbolicValueAllocator &allocator);
519+
520+
/// Return the elements stored in this SymbolicValue of "ArrayStorage" kind.
521+
ArrayRef<SymbolicValue> getStoredElements(CanType &elementType) const;
522+
523+
/// Return the symbolic value representing the internal storage of this array.
524+
SymbolicValue getStorageOfArray() const;
525+
526+
/// Return the symbolic value representing the address of the element of this
527+
/// array at the given \c index. The return value is a derived address whose
528+
/// base is the memory object \c value.array (which contains the array
529+
/// storage) and whose accesspath is \c index.
530+
SymbolicValue getAddressOfArrayElement(SymbolicValueAllocator &allocator,
531+
unsigned index) const;
532+
533+
/// Return the type of this array symbolic value.
534+
Type getArrayType() const;
535+
474536
//===--------------------------------------------------------------------===//
475537
// Helpers
476538

@@ -545,7 +607,6 @@ struct SymbolicValueMemoryObject {
545607
SymbolicValueMemoryObject(const SymbolicValueMemoryObject &) = delete;
546608
void operator=(const SymbolicValueMemoryObject &) = delete;
547609
};
548-
549610
} // end namespace swift
550611

551612
#endif

lib/SIL/SILConstants.cpp

Lines changed: 183 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,32 @@ void SymbolicValue::print(llvm::raw_ostream &os, unsigned indent) const {
101101
case RK_DerivedAddress: {
102102
SmallVector<unsigned, 4> accessPath;
103103
SymbolicValueMemoryObject *memObject = getAddressValue(accessPath);
104-
os << "Address[" << memObject->getType() << "] ";
104+
os << "address[" << memObject->getType() << "] ";
105105
interleave(accessPath.begin(), accessPath.end(),
106106
[&](unsigned idx) { os << idx; }, [&]() { os << ", "; });
107107
os << "\n";
108108
break;
109109
}
110+
case RK_ArrayStorage: {
111+
CanType elementType;
112+
ArrayRef<SymbolicValue> elements = getStoredElements(elementType);
113+
os << "elements type: " << elementType << " size: " << elements.size();
114+
switch (elements.size()) {
115+
case 0:
116+
os << " contents []\n";
117+
return;
118+
default:
119+
os << " contents [\n";
120+
for (auto elt : elements)
121+
elt.print(os, indent + 2);
122+
os.indent(indent) << "]\n";
123+
return;
124+
}
125+
}
126+
case RK_Array: {
127+
os << getArrayType() << ": \n";
128+
getStorageOfArray().print(os, indent);
129+
}
110130
}
111131
}
112132

@@ -138,11 +158,15 @@ SymbolicValue::Kind SymbolicValue::getKind() const {
138158
case RK_DirectAddress:
139159
case RK_DerivedAddress:
140160
return Address;
161+
case RK_ArrayStorage:
162+
return ArrayStorage;
163+
case RK_Array:
164+
return Array;
141165
}
142166
llvm_unreachable("covered switch");
143167
}
144168

145-
/// Clone this SymbolicValue into the specified ASTContext and return the new
169+
/// Clone this SymbolicValue into the specified allocator and return the new
146170
/// version. This only works for valid constants.
147171
SymbolicValue
148172
SymbolicValue::cloneInto(SymbolicValueAllocator &allocator) const {
@@ -169,16 +193,32 @@ SymbolicValue::cloneInto(SymbolicValueAllocator &allocator) const {
169193
results.push_back(elt.cloneInto(allocator));
170194
return getAggregate(results, allocator);
171195
}
172-
case RK_EnumWithPayload:
173-
return getEnumWithPayload(getEnumValue(), getEnumPayloadValue(), allocator);
196+
case RK_EnumWithPayload: {
197+
return getEnumWithPayload(
198+
getEnumValue(), getEnumPayloadValue().cloneInto(allocator), allocator);
199+
}
174200
case RK_DirectAddress:
175201
case RK_DerivedAddress: {
176202
SmallVector<unsigned, 4> accessPath;
177203
auto *memObject = getAddressValue(accessPath);
178204
auto *newMemObject = SymbolicValueMemoryObject::create(
179-
memObject->getType(), memObject->getValue(), allocator);
205+
memObject->getType(), memObject->getValue().cloneInto(allocator),
206+
allocator);
180207
return getAddress(newMemObject, accessPath, allocator);
181208
}
209+
case RK_ArrayStorage: {
210+
CanType elementType;
211+
ArrayRef<SymbolicValue> oldElements = getStoredElements(elementType);
212+
SmallVector<SymbolicValue, 4> clonedElements;
213+
clonedElements.reserve(oldElements.size());
214+
for (auto elem : oldElements)
215+
clonedElements.push_back(elem.cloneInto(allocator));
216+
return getSymbolicArrayStorage(clonedElements, elementType, allocator);
217+
}
218+
case RK_Array: {
219+
SymbolicValue clonedStorage = getStorageOfArray().cloneInto(allocator);
220+
return getArray(getArrayType(), clonedStorage, allocator);
221+
}
182222
}
183223
llvm_unreachable("covered switch");
184224
}
@@ -522,6 +562,105 @@ SymbolicValueMemoryObject *SymbolicValue::getAddressValueMemoryObject() const {
522562
return value.derivedAddress->memoryObject;
523563
}
524564

565+
//===----------------------------------------------------------------------===//
566+
// Arrays
567+
//===----------------------------------------------------------------------===//
568+
569+
namespace swift {
570+
571+
/// Representation of the internal storage of an array. This is a container for
572+
/// a sequence of symbolic values corresponding to the elements of an array.
573+
struct SymbolicArrayStorage final
574+
: private llvm::TrailingObjects<SymbolicArrayStorage, SymbolicValue> {
575+
friend class llvm::TrailingObjects<SymbolicArrayStorage, SymbolicValue>;
576+
577+
const CanType elementType;
578+
579+
const unsigned numElements;
580+
581+
static SymbolicArrayStorage *create(ArrayRef<SymbolicValue> elements,
582+
CanType elementType,
583+
SymbolicValueAllocator &allocator) {
584+
auto byteSize =
585+
SymbolicArrayStorage::totalSizeToAlloc<SymbolicValue>(elements.size());
586+
auto rawMem = allocator.allocate(byteSize, alignof(SymbolicArrayStorage));
587+
588+
// Placement initialize the object.
589+
auto *storage =
590+
::new (rawMem) SymbolicArrayStorage(elementType, elements.size());
591+
std::uninitialized_copy(elements.begin(), elements.end(),
592+
storage->getTrailingObjects<SymbolicValue>());
593+
return storage;
594+
}
595+
596+
/// Return the stored elements.
597+
ArrayRef<SymbolicValue> getElements() const {
598+
return {getTrailingObjects<SymbolicValue>(), numElements};
599+
}
600+
601+
// This is used by the llvm::TrailingObjects base class.
602+
size_t numTrailingObjects(OverloadToken<SymbolicValue>) const {
603+
return numElements;
604+
}
605+
606+
private:
607+
SymbolicArrayStorage() = delete;
608+
SymbolicArrayStorage(const SymbolicArrayStorage &) = delete;
609+
SymbolicArrayStorage(CanType elementType, unsigned numElements)
610+
: elementType(elementType), numElements(numElements) {}
611+
};
612+
} // namespace swift
613+
// end namespace swift
614+
615+
SymbolicValue
616+
SymbolicValue::getSymbolicArrayStorage(ArrayRef<SymbolicValue> elements,
617+
CanType elementType,
618+
SymbolicValueAllocator &allocator) {
619+
// TODO: Could compress the empty array representation if there were a reason
620+
// to.
621+
auto *arrayStorage =
622+
SymbolicArrayStorage::create(elements, elementType, allocator);
623+
SymbolicValue result;
624+
result.representationKind = RK_ArrayStorage;
625+
result.value.arrayStorage = arrayStorage;
626+
return result;
627+
}
628+
629+
ArrayRef<SymbolicValue>
630+
SymbolicValue::getStoredElements(CanType &elementType) const {
631+
assert(getKind() == ArrayStorage);
632+
elementType = value.arrayStorage->elementType;
633+
return value.arrayStorage->getElements();
634+
}
635+
636+
SymbolicValue SymbolicValue::getArray(Type arrayType,
637+
SymbolicValue arrayStorage,
638+
SymbolicValueAllocator &allocator) {
639+
assert(arrayStorage.getKind() == ArrayStorage);
640+
SymbolicValue result;
641+
result.representationKind = RK_Array;
642+
result.value.array =
643+
SymbolicValueMemoryObject::create(arrayType, arrayStorage, allocator);
644+
return result;
645+
}
646+
647+
SymbolicValue
648+
SymbolicValue::getAddressOfArrayElement(SymbolicValueAllocator &allocator,
649+
unsigned index) const {
650+
assert(getKind() == Array);
651+
return SymbolicValue::getAddress(value.array, {index}, allocator);
652+
}
653+
654+
SymbolicValue SymbolicValue::getStorageOfArray() const {
655+
assert(getKind() == Array);
656+
return value.array->getValue();
657+
}
658+
659+
Type SymbolicValue::getArrayType() const {
660+
assert(getKind() == Array);
661+
return value.array->getType();
662+
}
663+
525664
//===----------------------------------------------------------------------===//
526665
// Higher level code
527666
//===----------------------------------------------------------------------===//
@@ -766,20 +905,29 @@ static SymbolicValue getIndexedElement(SymbolicValue aggregate,
766905
if (aggregate.getKind() == SymbolicValue::UninitMemory)
767906
return SymbolicValue::getUninitMemory();
768907

769-
assert(aggregate.getKind() == SymbolicValue::Aggregate &&
908+
assert((aggregate.getKind() == SymbolicValue::Aggregate ||
909+
aggregate.getKind() == SymbolicValue::ArrayStorage) &&
770910
"the accessPath is invalid for this type");
771911

772912
unsigned elementNo = accessPath.front();
773913

774-
SymbolicValue elt = aggregate.getAggregateValue()[elementNo];
914+
SymbolicValue elt;
775915
Type eltType;
776-
if (auto *decl = type->getStructOrBoundGenericStruct()) {
777-
eltType = decl->getStoredProperties()[elementNo]->getType();
778-
} else if (auto tuple = type->getAs<TupleType>()) {
779-
assert(elementNo < tuple->getNumElements() && "invalid index");
780-
eltType = tuple->getElement(elementNo).getType();
916+
917+
if (aggregate.getKind() == SymbolicValue::ArrayStorage) {
918+
CanType arrayEltTy;
919+
elt = aggregate.getStoredElements(arrayEltTy)[elementNo];
920+
eltType = arrayEltTy;
781921
} else {
782-
llvm_unreachable("the accessPath is invalid for this type");
922+
elt = aggregate.getAggregateValue()[elementNo];
923+
if (auto *decl = type->getStructOrBoundGenericStruct()) {
924+
eltType = decl->getStoredProperties()[elementNo]->getType();
925+
} else if (auto tuple = type->getAs<TupleType>()) {
926+
assert(elementNo < tuple->getNumElements() && "invalid index");
927+
eltType = tuple->getElement(elementNo).getType();
928+
} else {
929+
llvm_unreachable("the accessPath is invalid for this type");
930+
}
783931
}
784932

785933
return getIndexedElement(elt, accessPath.drop_front(), eltType);
@@ -828,20 +976,29 @@ static SymbolicValue setIndexedElement(SymbolicValue aggregate,
828976
aggregate = SymbolicValue::getAggregate(newElts, allocator);
829977
}
830978

831-
assert(aggregate.getKind() == SymbolicValue::Aggregate &&
979+
assert((aggregate.getKind() == SymbolicValue::Aggregate ||
980+
aggregate.getKind() == SymbolicValue::ArrayStorage) &&
832981
"the accessPath is invalid for this type");
833982

834983
unsigned elementNo = accessPath.front();
835984

836-
ArrayRef<SymbolicValue> oldElts = aggregate.getAggregateValue();
985+
ArrayRef<SymbolicValue> oldElts;
837986
Type eltType;
838-
if (auto *decl = type->getStructOrBoundGenericStruct()) {
839-
eltType = decl->getStoredProperties()[elementNo]->getType();
840-
} else if (auto tuple = type->getAs<TupleType>()) {
841-
assert(elementNo < tuple->getNumElements() && "invalid index");
842-
eltType = tuple->getElement(elementNo).getType();
987+
988+
if (aggregate.getKind() == SymbolicValue::ArrayStorage) {
989+
CanType arrayEltTy;
990+
oldElts = aggregate.getStoredElements(arrayEltTy);
991+
eltType = arrayEltTy;
843992
} else {
844-
llvm_unreachable("the accessPath is invalid for this type");
993+
oldElts = aggregate.getAggregateValue();
994+
if (auto *decl = type->getStructOrBoundGenericStruct()) {
995+
eltType = decl->getStoredProperties()[elementNo]->getType();
996+
} else if (auto tuple = type->getAs<TupleType>()) {
997+
assert(elementNo < tuple->getNumElements() && "invalid index");
998+
eltType = tuple->getElement(elementNo).getType();
999+
} else {
1000+
llvm_unreachable("the accessPath is invalid for this type");
1001+
}
8451002
}
8461003

8471004
// Update the indexed element of the aggregate.
@@ -850,7 +1007,11 @@ static SymbolicValue setIndexedElement(SymbolicValue aggregate,
8501007
setIndexedElement(newElts[elementNo], accessPath.drop_front(), newElement,
8511008
eltType, allocator);
8521009

853-
aggregate = SymbolicValue::getAggregate(newElts, allocator);
1010+
if (aggregate.getKind() == SymbolicValue::Aggregate)
1011+
return SymbolicValue::getAggregate(newElts, allocator);
1012+
1013+
return aggregate = SymbolicValue::getSymbolicArrayStorage(
1014+
newElts, eltType->getCanonicalType(), allocator);
8541015
return aggregate;
8551016
}
8561017

0 commit comments

Comments
 (0)