Skip to content

Commit 6df5462

Browse files
committed
[sil] Add support for multiple value instructions by adding MultipleValueInstruction{,Result}.
rdar://31521023
1 parent 652edc9 commit 6df5462

21 files changed

+699
-136
lines changed

include/swift/SIL/SILArgument.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,8 @@ class SILArgument : public ValueBase {
124124
explicit SILArgument(ValueKind SubClassKind, SILType Ty,
125125
ValueOwnershipKind OwnershipKind,
126126
const ValueDecl *D = nullptr)
127-
: ValueBase(SubClassKind, Ty), ParentBB(nullptr), Decl(D), OwnershipKind(OwnershipKind) {}
127+
: ValueBase(SubClassKind, Ty, IsRepresentative::Yes), ParentBB(nullptr),
128+
Decl(D), OwnershipKind(OwnershipKind) {}
128129
void setParent(SILBasicBlock *P) { ParentBB = P; }
129130

130131
friend SILBasicBlock;

include/swift/SIL/SILInstruction.h

Lines changed: 245 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,16 +44,21 @@ class DeclRefExpr;
4444
class FloatLiteralExpr;
4545
class FuncDecl;
4646
class IntegerLiteralExpr;
47+
class SingleValueInstruction;
48+
class MultipleValueInstruction;
49+
class MultipleValueInstructionResult;
4750
class NonValueInstruction;
4851
class SILBasicBlock;
4952
class SILBuilder;
5053
class SILDebugLocation;
5154
class SILDebugScope;
5255
class SILFunction;
5356
class SILGlobalVariable;
57+
class SILInstructionResultArray;
5458
class SILOpenedArchetypesState;
5559
class SILType;
5660
class SILArgument;
61+
class SILUndef;
5762
class Stmt;
5863
class StringLiteralExpr;
5964
class Substitution;
@@ -96,13 +101,37 @@ StringRef getSILInstructionName(SILInstructionKind Kind);
96101
///
97102
/// *NOTE* Most of this defined out of line further down in the file to work
98103
/// around forward declaration issues.
104+
///
105+
/// *NOTE* The reason why this does not store the size of the stored element is
106+
/// that just from the number of elements we can infer the size of each element
107+
/// due to the restricted problem space. Specificially:
108+
///
109+
/// 1. Size == 0 implies nothing is stored and thus element size is irrelevent.
110+
/// 2. Size == 1 implies we either had a single value instruction or a multiple
111+
/// value instruction, but no matter what instruction we had, we are going to
112+
/// store the results at the same starting location so element size is
113+
/// irrelevent.
114+
/// 3. Size > 1 implies we must be storing multiple value instruction results
115+
/// implying that the size of each stored element must be
116+
/// sizeof(MultipleValueInstructionResult).
117+
///
118+
/// If we ever allow for subclasses of MultipleValueInstructionResult of
119+
/// different sizes, we will need to store a stride into
120+
/// SILInstructionResultArray. We always assume all results are the same
121+
/// subclass of MultipleValueInstructionResult.
99122
class SILInstructionResultArray {
123+
friend class MultipleValueInstruction;
124+
125+
/// Byte pointer to our data. nullptr for empty arrays.
100126
const uint8_t *Pointer;
127+
128+
/// The number of stored elements.
101129
unsigned Size;
102130

103131
public:
104132
SILInstructionResultArray() : Pointer(nullptr), Size(0) {}
105133
SILInstructionResultArray(const SingleValueInstruction *SVI);
134+
SILInstructionResultArray(ArrayRef<MultipleValueInstructionResult> MVResults);
106135

107136
SILInstructionResultArray(const SILInstructionResultArray &Other) = default;
108137
SILInstructionResultArray &
@@ -141,6 +170,18 @@ class SILInstructionResultArray {
141170
bool hasSameTypes(const SILInstructionResultArray &rhs);
142171

143172
private:
173+
/// Return the first element of the array. Asserts if the array is empty.
174+
///
175+
/// Please do not use this outside of this class. It is only meant to speedup
176+
/// MultipleValueInstruction::getIndexOfResult(SILValue).
177+
const ValueBase *front() const;
178+
179+
/// Return the last element of the array. Asserts if the array is empty.
180+
///
181+
/// Please do not use this outside of this class. It is only meant to speedup
182+
/// MultipleValueInstruction::getIndexOfResult(SILValue).
183+
const ValueBase *back() const;
184+
144185
/// Return the offset 1 past the end of the array or None if we are not
145186
/// actually storing anything.
146187
Optional<unsigned> getStartOffset() const {
@@ -188,6 +229,17 @@ class SILInstructionResultArray::iterator
188229
return copy;
189230
}
190231

232+
iterator &operator--() {
233+
--Index.getValue();
234+
return *this;
235+
}
236+
237+
iterator operator--(int) {
238+
iterator copy = *this;
239+
--Index.getValue();
240+
return copy;
241+
}
242+
191243
friend bool operator==(iterator lhs, iterator rhs) {
192244
assert(lhs.Parent.Pointer == rhs.Parent.Pointer);
193245
return lhs.Index == rhs.Index;
@@ -256,7 +308,8 @@ class SILInstruction
256308

257309
protected:
258310
SILInstruction(SILInstructionKind kind, SILDebugLocation DebugLoc)
259-
: SILNode(SILNodeKind(kind), SILNodeStorageLocation::Instruction),
311+
: SILNode(SILNodeKind(kind), SILNodeStorageLocation::Instruction,
312+
IsRepresentative::Yes),
260313
ParentBB(nullptr), Location(DebugLoc) {
261314
NumCreatedInstructions++;
262315
}
@@ -303,12 +356,12 @@ class SILInstruction
303356
}
304357

305358
SILNode *getCanonicalSILNodeInObject() {
306-
assert(isCanonicalSILNodeInObject() &&
359+
assert(isRepresentativeSILNodeInObject() &&
307360
"the SILInstruction subobject is always canonical");
308361
return this;
309362
}
310363
const SILNode *getCanonicalSILNodeInObject() const {
311-
assert(isCanonicalSILNodeInObject() &&
364+
assert(isRepresentativeSILNodeInObject() &&
312365
"the SILInstruction subobject is always canonical");
313366
return this;
314367
}
@@ -614,9 +667,8 @@ class SingleValueInstruction : public SILInstruction, public ValueBase {
614667
public:
615668
SingleValueInstruction(SILInstructionKind kind, SILDebugLocation loc,
616669
SILType type)
617-
: SILInstruction(kind, loc),
618-
ValueBase(ValueKind(kind), type) {
619-
}
670+
: SILInstruction(kind, loc),
671+
ValueBase(ValueKind(kind), type, IsRepresentative::No) {}
620672

621673
using SILInstruction::getFunction;
622674
using SILInstruction::getModule;
@@ -636,12 +688,12 @@ class SingleValueInstruction : public SILInstruction, public ValueBase {
636688
}
637689

638690
SILNode *getCanonicalSILNodeInObject() {
639-
assert(SILInstruction::isCanonicalSILNodeInObject() &&
691+
assert(SILInstruction::isRepresentativeSILNodeInObject() &&
640692
"the SILInstruction subobject is always canonical");
641693
return static_cast<SILInstruction*>(this);
642694
}
643695
const SILNode *getCanonicalSILNodeInObject() const {
644-
assert(SILInstruction::isCanonicalSILNodeInObject() &&
696+
assert(SILInstruction::isRepresentativeSILNodeInObject() &&
645697
"the SILInstruction subobject is always canonical");
646698
return static_cast<const SILInstruction*>(this);
647699
}
@@ -693,6 +745,182 @@ inline SingleValueInstruction *SILNode::castToSingleValueInstruction() {
693745
inst->getKind() <= SILInstructionKind::Last_##ID; \
694746
}
695747

748+
/// A value base result of a multiple value instruction.
749+
///
750+
/// *NOTE* We want this to be a pure abstract class that does not add /any/ size
751+
/// to subclasses.
752+
class MultipleValueInstructionResult : public ValueBase {
753+
public:
754+
/// Create a new multiple value instruction result.
755+
///
756+
/// \arg subclassDeltaOffset This is the delta offset in our parent object's
757+
/// layout in between the end of the MultipleValueInstruction object and the
758+
/// end of the specific subclass object.
759+
///
760+
/// *NOTE* subclassDeltaOffset must be use only 5 bits. This gives us to
761+
/// support subclasses up to 32 bytes in size. We can scavange up to 6 more
762+
/// bits from ValueBase if this is not large enough.
763+
MultipleValueInstructionResult(ValueKind valueKind, unsigned index,
764+
SILType type,
765+
ValueOwnershipKind ownershipKind);
766+
767+
/// Return the parent instruction of this result.
768+
MultipleValueInstruction *getParent();
769+
770+
const MultipleValueInstruction *getParent() const {
771+
return const_cast<MultipleValueInstructionResult *>(this)->getParent();
772+
}
773+
774+
unsigned getIndex() const;
775+
776+
/// Get the ownership kind assigned to this result by its parent.
777+
///
778+
/// This is stored in the bottom 3 bits of ValueBase's subclass data.
779+
ValueOwnershipKind getOwnershipKind() const;
780+
781+
SILNode *getCanonicalSILNodeInObject();
782+
const SILNode *getCanonicalSILNodeInObject() const;
783+
784+
static bool classof(const SILInstruction *) = delete;
785+
static bool classof(const SILUndef *) = delete;
786+
static bool classof(const SILArgument *) = delete;
787+
static bool classof(const MultipleValueInstructionResult *) { return true; }
788+
static bool classof(const SILNode *node) {
789+
// This is an abstract class without anything implementing it right now, so
790+
// just return false. This will be fixed in a subsequent commit.
791+
return false;
792+
}
793+
794+
protected:
795+
/// Set the ownership kind assigned to this result.
796+
///
797+
/// This is stored in SILNode in the subclass data.
798+
void setOwnershipKind(ValueOwnershipKind Kind);
799+
800+
/// Set the index of this result.
801+
void setIndex(unsigned NewIndex);
802+
803+
static constexpr unsigned NumIndexBits = 24;
804+
static constexpr uint64_t IndexMask = (uint64_t(1) << 24) - 1;
805+
static constexpr uint64_t IndexBitOffset = ValueOwnershipKind::NumBits;
806+
};
807+
808+
/// An instruction that may produce an arbitrary number of values.
809+
class MultipleValueInstruction : public SILInstruction {
810+
friend class SILInstruction;
811+
friend class SILInstructionResultArray;
812+
813+
protected:
814+
MultipleValueInstruction(SILInstructionKind kind, SILDebugLocation loc)
815+
: SILInstruction(kind, loc) {}
816+
817+
public:
818+
void operator delete(void *Ptr, size_t)SWIFT_DELETE_OPERATOR_DELETED;
819+
820+
MultipleValueInstruction *clone(SILInstruction *insertPt = nullptr) {
821+
return cast<MultipleValueInstruction>(SILInstruction::clone(insertPt));
822+
}
823+
824+
SILValue getResult(unsigned Index) const { return getResults()[Index]; }
825+
826+
/// Return the index of \p Target if it is a result in the given
827+
/// MultipleValueInstructionResult. Otherwise, returns None.
828+
Optional<unsigned> getIndexOfResult(SILValue Target) const;
829+
830+
unsigned getNumResults() const { return getResults().size(); }
831+
832+
static bool classof(const SILNode *node) {
833+
// This is an abstract class without anything implementing it right now, so
834+
// just return false. This will be fixed in a subsequent commit.
835+
return false;
836+
}
837+
};
838+
839+
/// A utility mixin class that must be used by /all/ subclasses of
840+
/// MultipleValueInstruction to store their results.
841+
template <SILInstructionKind Kind, typename Derived, typename DerivedResult,
842+
typename... OtherTrailingTypes>
843+
class MultipleValueInstructionTrailingObjects
844+
: protected llvm::TrailingObjects<Derived, MultipleValueInstruction *,
845+
DerivedResult, OtherTrailingTypes...> {
846+
static_assert(LLVM_IS_FINAL(DerivedResult),
847+
"Expected DerivedResult to be final");
848+
static_assert(
849+
std::is_base_of<MultipleValueInstructionResult, DerivedResult>::value,
850+
"Expected DerivedResult to be a subclass of "
851+
"MultipleValueInstructionResult");
852+
static_assert(sizeof(MultipleValueInstructionResult) == sizeof(DerivedResult),
853+
"Expected DerivedResult to be the same size as a "
854+
"MultipleValueInstructionResult");
855+
856+
protected:
857+
using TrailingObjects =
858+
llvm::TrailingObjects<Derived, MultipleValueInstruction *, DerivedResult,
859+
OtherTrailingTypes...>;
860+
friend TrailingObjects;
861+
862+
using TrailingObjects::totalSizeToAlloc;
863+
using TrailingObjects::getTrailingObjects;
864+
865+
unsigned NumResults;
866+
867+
size_t numTrailingObjects(typename TrailingObjects::template OverloadToken<
868+
MultipleValueInstruction *>) const {
869+
return 1;
870+
}
871+
872+
size_t numTrailingObjects(
873+
typename TrailingObjects::template OverloadToken<DerivedResult>) const {
874+
return NumResults;
875+
}
876+
877+
template <typename... Args>
878+
MultipleValueInstructionTrailingObjects(
879+
Derived *Parent, ArrayRef<SILType> Types,
880+
ArrayRef<ValueOwnershipKind> OwnershipKinds, Args &&... OtherArgs)
881+
: NumResults(Types.size()) {
882+
883+
// If we do not have any results, then we do not need to initialize even the
884+
// parent pointer since we do not have any results that will attempt to get
885+
// our parent pointer.
886+
if (!NumResults)
887+
return;
888+
889+
auto **ParentPtr =
890+
this->template getTrailingObjects<MultipleValueInstruction *>();
891+
*ParentPtr = static_cast<MultipleValueInstruction *>(Parent);
892+
893+
auto *DataPtr = this->template getTrailingObjects<DerivedResult>();
894+
for (unsigned i : range(NumResults)) {
895+
::new (&DataPtr[i]) DerivedResult(i, Types[i], OwnershipKinds[i],
896+
std::forward<Args>(OtherArgs)...);
897+
assert(DataPtr[i].getParent() == Parent &&
898+
"Failed to setup parent reference correctly?!");
899+
}
900+
}
901+
902+
// Destruct the Derived Results.
903+
~MultipleValueInstructionTrailingObjects() {
904+
if (!NumResults)
905+
return;
906+
auto *DataPtr = this->template getTrailingObjects<DerivedResult>();
907+
for (unsigned i : range(NumResults))
908+
DataPtr[i].~DerivedResult();
909+
}
910+
911+
public:
912+
SILInstructionResultArray getAllResults() const {
913+
// Our results start at element 1 since we stash the pointer to our parent
914+
// MultipleValueInstruction in the 0 elt slot. This allows all
915+
// MultipleValueInstructionResult to find their parent
916+
// MultipleValueInstruction by using pointer arithmetic.
917+
auto *Result = this->template getTrailingObjects<DerivedResult>();
918+
return SILInstructionResultArray(
919+
{static_cast<const MultipleValueInstructionResult *>(Result),
920+
NumResults});
921+
};
922+
};
923+
696924
/// A subclass of SILInstruction which does not produce any values.
697925
class NonValueInstruction : public SILInstruction {
698926
public:
@@ -7037,6 +7265,15 @@ SILFunction *ApplyInstBase<Impl, Base, false>::getCalleeFunction() const {
70377265
}
70387266
}
70397267

7268+
inline SILNode *MultipleValueInstructionResult::getCanonicalSILNodeInObject() {
7269+
return getParent();
7270+
}
7271+
7272+
inline const SILNode *
7273+
MultipleValueInstructionResult::getCanonicalSILNodeInObject() const {
7274+
return getParent();
7275+
}
7276+
70407277
} // end swift namespace
70417278

70427279
//===----------------------------------------------------------------------===//

0 commit comments

Comments
 (0)