Skip to content

Commit 3194718

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

File tree

9 files changed

+258
-35
lines changed

9 files changed

+258
-35
lines changed

include/swift/SIL/SILInstruction.h

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,16 +44,20 @@ class DeclRefExpr;
4444
class FloatLiteralExpr;
4545
class FuncDecl;
4646
class IntegerLiteralExpr;
47+
class SingleValueInstruction;
48+
class MultipleValueInstruction;
4749
class NonValueInstruction;
4850
class SILBasicBlock;
4951
class SILBuilder;
5052
class SILDebugLocation;
5153
class SILDebugScope;
5254
class SILFunction;
5355
class SILGlobalVariable;
56+
class SILInstructionResultArray;
5457
class SILOpenedArchetypesState;
5558
class SILType;
5659
class SILArgument;
60+
class SILUndef;
5761
class Stmt;
5862
class StringLiteralExpr;
5963
class Substitution;
@@ -103,6 +107,7 @@ class SILInstructionResultArray {
103107
public:
104108
SILInstructionResultArray() : Pointer(nullptr), Size(0) {}
105109
SILInstructionResultArray(const SingleValueInstruction *SVI);
110+
SILInstructionResultArray(const MultipleValueInstruction *MVI);
106111

107112
SILInstructionResultArray(const SILInstructionResultArray &Other)
108113
: Pointer(Other.Pointer), Size(Other.Size) {}
@@ -704,6 +709,122 @@ inline SingleValueInstruction *SILNode::castToSingleValueInstruction() {
704709
inst->getKind() <= SILInstructionKind::Last_##ID; \
705710
}
706711

712+
/// A value base result of a multiple value instruction.
713+
class MultipleValueInstructionResult : public ValueBase {
714+
/// The parent instruction that this MultipleValueInstructionResult is
715+
/// contained within.
716+
MultipleValueInstruction *Parent;
717+
718+
/// The ownership kind assigned to this result by its parent.
719+
///
720+
/// We store this rather than delegating to our parent since there is not a
721+
/// natural clear way to derive the ValueOwnershipKind for all potential
722+
/// multiple value instructions. This contrasts with the index of our result
723+
/// in the parent array.
724+
ValueOwnershipKind Kind;
725+
726+
public:
727+
MultipleValueInstructionResult(MultipleValueInstruction *parent, SILType type,
728+
ValueOwnershipKind kind)
729+
: ValueBase(ValueKind::MultipleValueInstructionResult, type),
730+
Parent(parent), Kind(kind) {}
731+
732+
MultipleValueInstruction *getParent() const { return Parent; }
733+
734+
unsigned getIndex() const;
735+
736+
ValueOwnershipKind getOwnershipKind() const { return Kind; }
737+
738+
SILNode *getCanonicalSILNodeInObject();
739+
const SILNode *getCanonicalSILNodeInObject() const;
740+
741+
static bool classof(const SILInstruction *) = delete;
742+
static bool classof(const SILUndef *) = delete;
743+
static bool classof(const SILNode *node) {
744+
return node->getKind() == SILNodeKind::MultipleValueInstructionResult;
745+
}
746+
};
747+
748+
/// An instruction which always produces a fixed list of values.
749+
class MultipleValueInstruction : public SILInstruction {
750+
// *NOTE* THis is just a stub since we do not currently have any multiple
751+
// value instructions.
752+
static bool isMultipleValueInstKind(SILNodeKind kind) { return false; }
753+
754+
friend class SILInstruction;
755+
friend class SILInstructionResultArray;
756+
757+
/// An ArrayRef of Result objects. We assume that our child classes's will
758+
/// allocate this for us on memory that will be placement newed.
759+
ArrayRef<MultipleValueInstructionResult> Results;
760+
761+
SILInstructionResultArray getResultsImpl() const {
762+
return SILInstructionResultArray(this);
763+
}
764+
765+
protected:
766+
MultipleValueInstruction(
767+
SILInstructionKind kind, SILDebugLocation loc,
768+
ArrayRef<MultipleValueInstructionResult> results = {})
769+
: SILInstruction(kind, loc), Results(results) {}
770+
771+
// Sometimes our subclasses need to set the new results /after/ we construct
772+
// the MultipleValueInstruction.
773+
void setResults(ArrayRef<MultipleValueInstructionResult> NewResults) {
774+
Results = NewResults;
775+
}
776+
777+
public:
778+
// Redeclare because lldb currently doesn't know about using-declarations
779+
void dump() const;
780+
781+
void operator delete(void *Ptr, size_t)SWIFT_DELETE_OPERATOR_DELETED;
782+
783+
SILInstructionResultArray getValueKinds() const { return getResultsImpl(); }
784+
785+
SILNode *getCanonicalSILNodeInObject() {
786+
assert(SILInstruction::isCanonicalSILNodeInObject() &&
787+
"the SILInstruction subobject is always canonical");
788+
return static_cast<SILInstruction *>(this);
789+
}
790+
const SILNode *getCanonicalSILNodeInObject() const {
791+
assert(SILInstruction::isCanonicalSILNodeInObject() &&
792+
"the SILInstruction subobject is always canonical");
793+
return static_cast<const SILInstruction *>(this);
794+
}
795+
796+
MultipleValueInstruction *clone(SILInstruction *insertPt = nullptr) {
797+
return cast<MultipleValueInstruction>(SILInstruction::clone(insertPt));
798+
}
799+
800+
/// Override this to reflect the more efficient access pattern.
801+
SILInstructionResultArray getResults() const {
802+
return SILInstructionResultArray(this);
803+
}
804+
805+
SILValue getResult(unsigned Index) const { return getResults()[Index]; }
806+
807+
unsigned getIndexOfResult(const MultipleValueInstructionResult *R) const {
808+
assert(((&Results.front() <= R) && (&Results.back() >= R)) &&
809+
"Passed in result is not a result of this MultipleValueInstruction");
810+
uintptr_t bytes = uintptr_t(R) - uintptr_t(&Results.front());
811+
return unsigned(bytes) / sizeof(MultipleValueInstructionResult);
812+
}
813+
814+
unsigned getNumResults() const { return getResults().size(); }
815+
816+
static bool classof(const SILNode *node) {
817+
return isMultipleValueInstKind(node->getKind());
818+
}
819+
};
820+
821+
// Resolve ambiguities.
822+
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
823+
const MultipleValueInstruction &I) {
824+
I.print(OS);
825+
return OS;
826+
}
827+
707828
/// A subclass of SILInstruction which does not produce any values.
708829
class NonValueInstruction : public SILInstruction {
709830
public:
@@ -7058,6 +7179,19 @@ SILFunction *ApplyInstBase<Impl, Base, false>::getCalleeFunction() const {
70587179
}
70597180
}
70607181

7182+
inline SILNode *MultipleValueInstructionResult::getCanonicalSILNodeInObject() {
7183+
return Parent->getCanonicalSILNodeInObject();
7184+
}
7185+
7186+
inline const SILNode *
7187+
MultipleValueInstructionResult::getCanonicalSILNodeInObject() const {
7188+
return Parent->getCanonicalSILNodeInObject();
7189+
}
7190+
7191+
inline unsigned MultipleValueInstructionResult::getIndex() const {
7192+
return Parent->getIndexOfResult(this);
7193+
}
7194+
70617195
} // end swift namespace
70627196

70637197
//===----------------------------------------------------------------------===//

include/swift/SIL/SILNode.h

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class SingleValueInstruction;
3232
class ValueBase;
3333

3434
/// An enumeration which contains values for all the nodes in SILNodes.def.
35-
/// Other enumerators, like ValueKind and SILInstructionind, ultimately
35+
/// Other enumerators, like ValueKind and SILInstructionKind, ultimately
3636
/// take their values from this enumerator.
3737
enum class SILNodeKind {
3838
#define NODE(ID, PARENT) \
@@ -113,15 +113,20 @@ class alignas(8) SILNode {
113113

114114
protected:
115115
SILNode(SILNodeKind kind, SILNodeStorageLocation storageLoc)
116-
: Kind(unsigned(kind)),
117-
StorageLoc(unsigned(storageLoc)),
118-
IsCanonical(storageLoc == SILNodeStorageLocation::Instruction ||
119-
!hasMultipleSILNodes(kind)) {}
116+
: Kind(unsigned(kind)), StorageLoc(unsigned(storageLoc)),
117+
IsCanonical(storageLoc == SILNodeStorageLocation::Instruction ||
118+
// TODO: Ask John about why he is using
119+
// hasMultipleSILNodeBaseClasses. Seems weird.
120+
(!hasMultipleSILNodeBaseClasses(kind) &&
121+
kind != SILNodeKind::MultipleValueInstructionResult)) {}
120122

121123
public:
122-
123-
/// Does the given kind of node have multiple SILNode bases?
124-
static bool hasMultipleSILNodes(SILNodeKind kind) {
124+
/// Does the given kind of node inherit from multiple multiple SILNode base
125+
/// classes.
126+
///
127+
/// This enables one to know if their is a diamond in the inheritence
128+
/// hierarchy for this SILNode.
129+
static bool hasMultipleSILNodeBaseClasses(SILNodeKind kind) {
125130
// Currently only SingleValueInstructions. Note that multi-result
126131
// instructions shouldn't return true for this.
127132
return kind >= SILNodeKind::First_SingleValueInstruction &&
@@ -246,7 +251,7 @@ struct cast_sil_node<To, /*single value*/ false, /*unambiguous*/ false> {
246251
static To *doit(SILNode *node) {
247252
// If the node isn't dynamically a SingleValueInstruction, then this
248253
// is indeed the SILNode subobject that's statically observable in To.
249-
if (!SILNode::hasMultipleSILNodes(node->getKind())) {
254+
if (!SILNode::hasMultipleSILNodeBaseClasses(node->getKind())) {
250255
return &static_cast<To&>(*node);
251256
}
252257

include/swift/SIL/SILNodes.def

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,16 @@
3838
#endif
3939
#endif
4040

41+
/// MULTIPLE_VALUE_INST(Id, TextualName, Parent, MemBehavior, MayRelease)
42+
///
43+
/// A concrete subclass of MultipleValueInstruction. ID is a member of
44+
/// SILInstructionKind. The Node's class name is ID and the name of the base
45+
/// class in the heirarchy is PARENT.
46+
#ifndef MULTIPLE_VALUE_INST
47+
#define MULTIPLE_VALUE_INST(ID, NAME, PARENT, MEMBEHAVIOR, MAYRELEASE) \
48+
FULL_INST(ID, NAME, PARENT, MEMBEHAVIOR, MAYRELEASE)
49+
#endif
50+
4151
/// VALUE(ID, PARENT)
4252
///
4353
/// A concrete subclass of ValueBase. ID is a member of ValueKind.
@@ -195,6 +205,8 @@ ABSTRACT_VALUE(SILArgument, ValueBase)
195205
ARGUMENT(SILFunctionArgument, SILArgument)
196206
VALUE_RANGE(SILArgument, SILPHIArgument, SILFunctionArgument)
197207

208+
VALUE(MultipleValueInstructionResult, ValueBase)
209+
198210
VALUE(SILUndef, ValueBase)
199211

200212
ABSTRACT_NODE(SILInstruction, SILNode)
@@ -629,6 +641,7 @@ NODE_RANGE(SILNode, SILPHIArgument, CondFailInst)
629641
#undef ABSTRACT_VALUE_AND_INST
630642
#undef TERMINATOR
631643
#undef NON_VALUE_INST
644+
#undef MULTIPLE_VALUE_INST
632645
#undef SINGLE_VALUE_INST
633646
#undef FULL_INST
634647
#undef INST

include/swift/SIL/SILValue.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,8 @@ struct ValueOwnershipKind {
133133
llvm::raw_ostream &operator<<(llvm::raw_ostream &os, ValueOwnershipKind Kind);
134134

135135
/// This is the base class of the SIL value hierarchy, which represents a
136-
/// runtime computed value. Things like SILInstruction derive from this.
136+
/// runtime computed value. Some examples of ValueBase are SILArgument and
137+
/// SingleValueInstruction.
137138
class ValueBase : public SILNode, public SILAllocated<ValueBase> {
138139
SILType Type;
139140
Operand *FirstUse = nullptr;

lib/ParseSIL/ParseSIL.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4781,15 +4781,18 @@ bool SILParser::parseSILFunctionRef(SILLocation InstLoc,
47814781
}
47824782

47834783
/// True if the current token sequence looks like the start of a SIL
4784-
/// instruction, either:
4785-
/// %name
4786-
/// or:
4787-
/// identifier | keyword
4784+
/// instruction. This can be one of:
4785+
///
4786+
/// 1. %name
4787+
/// 2. (%name1
4788+
/// 3. identifier | keyword
47884789
/// where identifier is not followed by a '(' or ':', which would indicate
47894790
/// a basic block.
47904791
bool SILParser::isStartOfSILInstruction() {
47914792
if (P.Tok.is(tok::sil_local_name))
47924793
return true;
4794+
if (P.Tok.is(tok::l_paren) && P.peekToken().is(tok::sil_local_name))
4795+
return true;
47934796
if (P.Tok.is(tok::identifier) || P.Tok.isKeyword()) {
47944797
auto &peek = P.peekToken();
47954798
return !peek.is(tok::l_paren) && !peek.is(tok::colon);

lib/SIL/SILInstruction.cpp

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -185,9 +185,13 @@ SILInstructionResultArray SILInstruction::getResultsImpl() const {
185185
return SILInstructionResultArray(
186186
static_cast<const SingleValueInstruction *>(this));
187187

188-
// add any multi-result instructions here...
188+
#define MULTIPLE_VALUE_INST(ID, NAME, PARENT, MEMBEHAVIOR, MAYRELEASE) \
189+
case SILInstructionKind::ID:
190+
#include "swift/SIL/SILNodes.def"
191+
return SILInstructionResultArray(
192+
static_cast<const MultipleValueInstruction *>(this));
189193
}
190-
llvm_unreachable("bad kind");
194+
llvm_unreachable("unhandled kind");
191195
}
192196

193197
// Initialize the static members of SILInstruction.
@@ -1202,33 +1206,70 @@ SILInstructionResultArray::SILInstructionResultArray(
12021206
"multi-inheritence parent");
12031207
Pointer = reinterpret_cast<const uint8_t *>(Value);
12041208

1209+
#ifndef NDEBUG
12051210
assert(originalValue == (*this)[0] &&
12061211
"Wrong value returned for single result");
12071212
assert(originalType == (*this)[0]->getType());
12081213

12091214
auto ValueRange = getValues();
1210-
(void)ValueRange;
12111215
assert(1 == std::distance(ValueRange.begin(), ValueRange.end()));
12121216
assert(originalValue == *ValueRange.begin());
12131217

12141218
auto TypedRange = getTypes();
1215-
(void)TypedRange;
12161219
assert(1 == std::distance(TypedRange.begin(), TypedRange.end()));
12171220
assert(originalType == *TypedRange.begin());
12181221

12191222
SILInstructionResultArray Copy = *this;
1220-
(void)Copy;
12211223
assert(Copy.hasSameTypes(*this));
12221224
assert(Copy == *this);
1225+
#endif
1226+
}
1227+
1228+
SILInstructionResultArray::SILInstructionResultArray(
1229+
const MultipleValueInstruction *MVI)
1230+
: Pointer(), Size(MVI->Results.size()) {
1231+
// We are assuming here that MultipleValueInstructionResult when static_cast
1232+
// is not offset.
1233+
Pointer = reinterpret_cast<const uint8_t *>(&MVI->Results[0]);
1234+
1235+
#ifndef NDEBUG
1236+
// Verify our invariants.
1237+
assert(size() == MVI->Results.size());
1238+
auto ValueRange = getValues();
1239+
auto VRangeBegin = ValueRange.begin();
1240+
auto VRangeIter = VRangeBegin;
1241+
auto VRangeEnd = ValueRange.end();
1242+
assert(MVI->Results.size() ==
1243+
unsigned(std::distance(VRangeBegin, VRangeEnd)));
1244+
1245+
auto TypedRange = getTypes();
1246+
auto TRangeBegin = TypedRange.begin();
1247+
auto TRangeIter = TRangeBegin;
1248+
auto TRangeEnd = TypedRange.end();
1249+
assert(MVI->Results.size() ==
1250+
unsigned(std::distance(VRangeBegin, VRangeEnd)));
1251+
for (unsigned i : indices(MVI->Results)) {
1252+
assert(SILValue(&MVI->Results[i]) == (*this)[i]);
1253+
assert(SILValue(&MVI->Results[i])->getType() == (*this)[i]->getType());
1254+
assert(SILValue(&MVI->Results[i]) == (*VRangeIter));
1255+
assert(SILValue(&MVI->Results[i])->getType() == (*VRangeIter)->getType());
1256+
assert(SILValue(&MVI->Results[i])->getType() == *TRangeIter);
1257+
++VRangeIter;
1258+
++TRangeIter;
1259+
}
1260+
1261+
SILInstructionResultArray Copy = *this;
1262+
assert(Copy.hasSameTypes(*this));
1263+
assert(Copy == *this);
1264+
#endif
12231265
}
12241266

12251267
SILValue SILInstructionResultArray::operator[](size_t Index) const {
12261268
assert(Index < Size && "Index out of bounds");
1227-
// Today we only have single instruction results so offset will always be
1228-
// zero. Once we have multiple instruction results, this will be equal to
1229-
// sizeof(MultipleValueInstructionResult)*Index. This is safe even to do with
1230-
// SingleValueInstruction since index will always be zero for the offset.
1231-
size_t Offset = 0;
1269+
// *NOTE* In the case where we have a single instruction, Index will always
1270+
// necessarily be 0 implying that it is safe for us to just multiple Index by
1271+
// sizeof(MultipleValueInstructionResult).
1272+
size_t Offset = sizeof(MultipleValueInstructionResult) * Index;
12321273
return SILValue(reinterpret_cast<const ValueBase *>(&Pointer[Offset]));
12331274
}
12341275

0 commit comments

Comments
 (0)