[region-isolation] When assigning RValues into memory, use tuple_addr_constructor instead of doing it in pieces.

I also included changes to the rest of the SIL optimizer pipeline to ensure that
the part of the optimizer pipeline before we lower tuple_addr_constructor (which
is right after we run TransferNonSendable) work as before.

The reason why I am doing this is that this ensures that diagnostic passes can
tell the difference in between:

```
x = (a, b, c)
```

and

```
x.0 = a
x.1 = b
x.2 = c
```

This is important for things like TransferNonSendable where assigning over the
entire tuple element is treated differently from if one were to initialize it in
pieces using projections.

rdar://117880194
This commit is contained in:
Michael Gottesman
2023-11-05 19:17:46 -08:00
parent d2b5bc33a1
commit b1f69030fc
19 changed files with 425 additions and 78 deletions

View File

@@ -2184,11 +2184,29 @@ SILCloner<ImplClass>::visitTupleInst(TupleInst *Inst) {
template <typename ImplClass>
void SILCloner<ImplClass>::visitTupleAddrConstructorInst(
TupleAddrConstructorInst *Inst) {
auto Elements = getOpValueArray<8>(Inst->getElements());
SmallVector<SILValue, 8> Elements;
for (auto e : Inst->getElements()) {
SILValue mappedValue = getOpValue(e);
// Check if mappedValue only consists of empty tuple elements. If it does,
// then we do not add it to our result. This is because we know that the
// corresponding elements in getOpValue(Inst->getDest()) will also change
// into an empty exploded tuple. Since we only have leaf non-empty non-tuple
// elements as operands, these are not represented.
bool FoundNonTuple = false;
mappedValue->getType().getASTType().visit(
[&](CanType ty) { FoundNonTuple |= !ty->is<TupleType>(); });
if (FoundNonTuple)
Elements.push_back(mappedValue);
}
if (Elements.empty())
return;
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
recordClonedInstruction(Inst, getBuilder().createTupleAddrConstructor(
getOpLocation(Inst->getLoc()),
getOpValue(Inst->getDestValue()), Elements,
getOpValue(Inst->getDest()), Elements,
Inst->isInitializationOfDest()));
}

View File

@@ -6372,10 +6372,10 @@ public:
Dest = 0,
};
Operand &getDest() { return getAllOperands().front(); }
const Operand &getDest() const { return getAllOperands().front(); }
Operand &getDestOperand() { return getAllOperands().front(); }
const Operand &getDestOperand() const { return getAllOperands().front(); }
SILValue getDestValue() const { return getDest().get(); }
SILValue getDest() const { return getDestOperand().get(); }
/// The elements referenced by this TupleInst.
MutableArrayRef<Operand> getElementOperands() {
@@ -6392,14 +6392,16 @@ public:
unsigned getElementIndex(Operand *operand) {
assert(operand->getUser() == this);
assert(operand != &getDest() && "Cannot pass in the destination");
assert(operand != &getDestOperand() && "Cannot pass in the destination");
return operand->getOperandNumber() + 1;
}
unsigned getNumElements() const { return getTupleType()->getNumElements(); }
TupleType *getTupleType() const {
return getDest().get()->getType().getRawASTType()->castTo<TupleType>();
// We use getASTType() since we want to look through a wrapped noncopyable
// type to get to the underlying tuple type.
return getDest()->getType().getASTType()->castTo<TupleType>();
}
IsInitialization_t isInitializationOfDest() const {