Skip to content

Commit f98d7bd

Browse files
authored
Merge pull request swiftlang#19662 from apple/marcrasi-const-evaluator-part-3
2 parents 11f0648 + 867d96d commit f98d7bd

File tree

5 files changed

+905
-83
lines changed

5 files changed

+905
-83
lines changed

include/swift/SIL/SILConstants.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,9 @@ class SymbolicValue {
268268
SymbolicValueMemoryObject *
269269
getAddressValue(SmallVectorImpl<unsigned> &accessPath) const;
270270

271+
/// Return just the memory object for an address value.
272+
SymbolicValueMemoryObject *getAddressValueMemoryObject() const;
273+
271274
//===--------------------------------------------------------------------===//
272275
// Helpers
273276

@@ -312,6 +315,24 @@ struct SymbolicValueMemoryObject {
312315
static SymbolicValueMemoryObject *create(Type type, SymbolicValue value,
313316
ASTContext &astContext);
314317

318+
/// Given that this memory object contains an aggregate value like
319+
/// {{1, 2}, 3}, and given an access path like [0,1], return the indexed
320+
/// element, e.g. "2" in this case.
321+
///
322+
/// Returns uninit memory if the access path points at or into uninit memory.
323+
///
324+
/// Precondition: The access path must be valid for this memory object's type.
325+
SymbolicValue getIndexedElement(ArrayRef<unsigned> accessPath);
326+
327+
/// Given that this memory object contains an aggregate value like
328+
/// {{1, 2}, 3}, given an access path like [0,1], and given a new element like
329+
/// "4", set the indexed element to the specified scalar, producing {{1, 4},
330+
/// 3} in this case.
331+
///
332+
/// Precondition: The access path must be valid for this memory object's type.
333+
void setIndexedElement(ArrayRef<unsigned> accessPath,
334+
SymbolicValue newElement, ASTContext &astCtx);
335+
315336
private:
316337
const Type type;
317338
SymbolicValue value;

lib/SIL/SILConstants.cpp

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,14 @@ SymbolicValue::getAddressValue(SmallVectorImpl<unsigned> &accessPath) const {
404404
return dav->memoryObject;
405405
}
406406

407+
/// Return just the memory object for an address value.
408+
SymbolicValueMemoryObject *SymbolicValue::getAddressValueMemoryObject() const {
409+
if (representationKind == RK_DirectAddress)
410+
return value.directAddress;
411+
assert(representationKind == RK_DerivedAddress);
412+
return value.derivedAddress->memoryObject;
413+
}
414+
407415
//===----------------------------------------------------------------------===//
408416
// Higher level code
409417
//===----------------------------------------------------------------------===//
@@ -521,3 +529,124 @@ void SymbolicValue::emitUnknownDiagnosticNotes(SILLocation fallbackLoc) {
521529
emittedFirstNote = true;
522530
}
523531
}
532+
533+
/// Returns the element of `aggregate` specified by the access path.
534+
///
535+
/// This is a helper for `SymbolicValueMemoryObject::getIndexedElement`. See
536+
/// there for more detailed documentation.
537+
static SymbolicValue getIndexedElement(SymbolicValue aggregate,
538+
ArrayRef<unsigned> accessPath,
539+
Type type) {
540+
// We're done if we've run out of access path.
541+
if (accessPath.empty())
542+
return aggregate;
543+
544+
// Everything inside uninit memory is uninit memory.
545+
if (aggregate.getKind() == SymbolicValue::UninitMemory)
546+
return SymbolicValue::getUninitMemory();
547+
548+
assert(aggregate.getKind() == SymbolicValue::Aggregate &&
549+
"the accessPath is invalid for this type");
550+
551+
unsigned elementNo = accessPath.front();
552+
553+
SymbolicValue elt = aggregate.getAggregateValue()[elementNo];
554+
Type eltType;
555+
if (auto *decl = type->getStructOrBoundGenericStruct()) {
556+
auto it = decl->getStoredProperties().begin();
557+
std::advance(it, elementNo);
558+
eltType = (*it)->getType();
559+
} else if (auto tuple = type->getAs<TupleType>()) {
560+
assert(elementNo < tuple->getNumElements() && "invalid index");
561+
eltType = tuple->getElement(elementNo).getType();
562+
} else {
563+
llvm_unreachable("the accessPath is invalid for this type");
564+
}
565+
566+
return getIndexedElement(elt, accessPath.drop_front(), eltType);
567+
}
568+
569+
/// Given that this memory object contains an aggregate value like
570+
/// {{1, 2}, 3}, and given an access path like [0,1], return the indexed
571+
/// element, e.g. "2" in this case.
572+
///
573+
/// Returns uninit memory if the access path points at or into uninit memory.
574+
///
575+
/// Precondition: The access path must be valid for this memory object's type.
576+
SymbolicValue
577+
SymbolicValueMemoryObject::getIndexedElement(ArrayRef<unsigned> accessPath) {
578+
return ::getIndexedElement(value, accessPath, type);
579+
}
580+
581+
/// Returns `aggregate` with the element specified by the access path set to
582+
/// `newElement`.
583+
///
584+
/// This is a helper for `SymbolicValueMemoryObject::setIndexedElement`. See
585+
/// there for more detailed documentation.
586+
static SymbolicValue setIndexedElement(SymbolicValue aggregate,
587+
ArrayRef<unsigned> accessPath,
588+
SymbolicValue newElement, Type type,
589+
ASTContext &astCtx) {
590+
// We're done if we've run out of access path.
591+
if (accessPath.empty())
592+
return newElement;
593+
594+
// If we have an uninit memory, then scalarize it into an aggregate to
595+
// continue. This happens when memory objects are initialized piecewise.
596+
if (aggregate.getKind() == SymbolicValue::UninitMemory) {
597+
unsigned numMembers;
598+
// We need to have either a struct or a tuple type.
599+
if (auto *decl = type->getStructOrBoundGenericStruct()) {
600+
numMembers = std::distance(decl->getStoredProperties().begin(),
601+
decl->getStoredProperties().end());
602+
} else if (auto tuple = type->getAs<TupleType>()) {
603+
numMembers = tuple->getNumElements();
604+
} else {
605+
llvm_unreachable("the accessPath is invalid for this type");
606+
}
607+
608+
SmallVector<SymbolicValue, 4> newElts(numMembers,
609+
SymbolicValue::getUninitMemory());
610+
aggregate = SymbolicValue::getAggregate(newElts, astCtx);
611+
}
612+
613+
assert(aggregate.getKind() == SymbolicValue::Aggregate &&
614+
"the accessPath is invalid for this type");
615+
616+
unsigned elementNo = accessPath.front();
617+
618+
ArrayRef<SymbolicValue> oldElts = aggregate.getAggregateValue();
619+
Type eltType;
620+
if (auto *decl = type->getStructOrBoundGenericStruct()) {
621+
auto it = decl->getStoredProperties().begin();
622+
std::advance(it, elementNo);
623+
eltType = (*it)->getType();
624+
} else if (auto tuple = type->getAs<TupleType>()) {
625+
assert(elementNo < tuple->getNumElements() && "invalid index");
626+
eltType = tuple->getElement(elementNo).getType();
627+
} else {
628+
llvm_unreachable("the accessPath is invalid for this type");
629+
}
630+
631+
// Update the indexed element of the aggregate.
632+
SmallVector<SymbolicValue, 4> newElts(oldElts.begin(), oldElts.end());
633+
newElts[elementNo] = setIndexedElement(newElts[elementNo],
634+
accessPath.drop_front(), newElement,
635+
eltType, astCtx);
636+
637+
aggregate = SymbolicValue::getAggregate(newElts, astCtx);
638+
639+
return aggregate;
640+
}
641+
642+
/// Given that this memory object contains an aggregate value like
643+
/// {{1, 2}, 3}, given an access path like [0,1], and given a new element like
644+
/// "4", set the indexed element to the specified scalar, producing {{1, 4},
645+
/// 3} in this case.
646+
///
647+
/// Precondition: The access path must be valid for this memory object's type.
648+
void SymbolicValueMemoryObject::setIndexedElement(
649+
ArrayRef<unsigned> accessPath, SymbolicValue newElement,
650+
ASTContext &astCtx) {
651+
value = ::setIndexedElement(value, accessPath, newElement, type, astCtx);
652+
}

0 commit comments

Comments
 (0)