-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[sil] Add support for multiple value instructions by adding MultipleValueInstruction{,Result}. #12285
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@swift-ci smoke test |
b1f91d7
to
200fc55
Compare
@swift-ci smoke test |
1 similar comment
@swift-ci smoke test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Much better!
include/swift/SIL/SILInstruction.h
Outdated
|
||
/// An instruction which always produces a fixed list of values. | ||
class MultipleValueInstruction : public SILInstruction { | ||
// *NOTE* THis is just a stub since we do not currently have any multiple |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Capital H.
include/swift/SIL/SILInstruction.h
Outdated
unsigned getIndexOfResult(const MultipleValueInstructionResult *R) const { | ||
assert(((&Results.front() <= R) && (&Results.back() >= R)) && | ||
"Passed in result is not a result of this MultipleValueInstruction"); | ||
return unsigned(uintptr_t(R) - uintptr_t(&Results.front())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like a byte offset instead of an index?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Your right. I forgot to divide by the size.
lib/SIL/SILInstruction.cpp
Outdated
const MultipleValueInstruction *MVI) | ||
: Pointer(), Size(1) { | ||
// We can perform a straight reinterpret_cast. | ||
Pointer = reinterpret_cast<const uint8_t *>(MVI); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not reinterpret_cast<const void *>
? We never want to read uint8_t values.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, should not be a reinterpret_cast
at all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea... that is what I was saying via IM. Brain wires got crossed.
// *NOTE* In the case where we have a single instruction, Index will always | ||
// necessarily be 0 implying that it is safe for us to just multiple Index by | ||
// sizeof(MultipleValueInstructionResult). | ||
size_t Offset = sizeof(MultipleValueInstructionResult) * Index; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All this reinterpret_cast
ing is code smell. It makes more sense to me for Pointer
to be an opaque pointer type.
The most self-documenting way to express this is:
if (Index == 0)
return static_cast<ValueBase*>(Pointer);
return static_cast<const MultipleValueInstructionResult*>(Pointer)[Index];
If you don't like the branch, you can just speculatively cast from void *
to MultipleValueInstructionResult*
with a comment about your cleverness.
If static_cast
and reinterpret_cast
are giving you different pointer adjustments, then I think you're already in serious trouble.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should have been submitted with my previous review.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Making fixes!
include/swift/SIL/SILInstruction.h
Outdated
unsigned getIndexOfResult(const MultipleValueInstructionResult *R) const { | ||
assert(((&Results.front() <= R) && (&Results.back() >= R)) && | ||
"Passed in result is not a result of this MultipleValueInstruction"); | ||
return unsigned(uintptr_t(R) - uintptr_t(&Results.front())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Your right. I forgot to divide by the size.
lib/SIL/SILInstruction.cpp
Outdated
const MultipleValueInstruction *MVI) | ||
: Pointer(), Size(1) { | ||
// We can perform a straight reinterpret_cast. | ||
Pointer = reinterpret_cast<const uint8_t *>(MVI); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea... that is what I was saying via IM. Brain wires got crossed.
200fc55
to
03cb3c9
Compare
Just to get feedback together (and to show how the two passes fit together), I am including the destructure_value impl here. |
*two passes == two patches. |
03cb3c9
to
2e610f0
Compare
@swift-ci test |
1 similar comment
@swift-ci test |
The gardening commit is being committed in #12336. |
@rjmccall ping! |
(the conflict is just a module format issue, I can fix that). |
(But it shouldn't affect your ability to review since it is just a ModuleFormat increment). |
include/swift/SIL/SILInstruction.h
Outdated
@@ -44,15 +44,21 @@ class DeclRefExpr; | |||
class FloatLiteralExpr; | |||
class FuncDecl; | |||
class IntegerLiteralExpr; | |||
class Projection; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't appear to be used.
include/swift/SIL/SILInstruction.h
Outdated
static bool classof(const SILInstruction *) = delete; | ||
static bool classof(const SILUndef *) = delete; | ||
static bool classof(const SILNode *node) { | ||
return node->getKind() == SILNodeKind::MultipleValueInstructionResult; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was hoping that this would be an abstract node, actually, so that you could do things like cast<DestructureInstResult>(value)
.
You should static_assert that all of the subclasses have the same size, of course.
include/swift/SIL/SILInstruction.h
Outdated
/// natural clear way to derive the ValueOwnershipKind for all potential | ||
/// multiple value instructions. This contrasts with the index of our result | ||
/// in the parent array. | ||
ValueOwnershipKind Kind; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please pull this up into the spare bits of the ValueBase node. I think you could just give SILNode a protected SubclassData field, LLVM-style.
include/swift/SIL/SILInstruction.h
Outdated
|
||
/// An ArrayRef of Result objects. We assume that our child classes's will | ||
/// allocate this for us on memory that will be placement newed. | ||
ArrayRef<MultipleValueInstructionResult> Results; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think MultipleValueInstruction actually needs to store this directly. It can be dispatched to the various MultiValueInstruction subclasses (from the main SILInstruction implementation) just like getOperands() is. Going from a MultipleValueInstruction to its results is probably not a very common operation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see what you mean.
include/swift/SIL/SILInstruction.h
Outdated
|
||
MultipleValueInstruction *getParent() const { return Parent; } | ||
|
||
unsigned getIndex() const; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My recommendation would have been to store the index in the SubclassData (which should have a completely reasonable number of bits, even with the ValueOwnershipKind) and then store the parent-instruction pointer at the beginning of the array. That might make it more difficult to use llvm::TrailingObjects, but I think it'll be fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rjmccall What do you mean by the beginning of the array? Which array? It can't be in the MultipleValueInstruction parent since we can't access that. Or am I missing something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess since I have the index, I can walk backwards assuming that I store the parent pointer. TBH though, couldn't I just not store the parent pointer at all and walk back using index and then walk back by an additional sizeof(MultipleValueInstruction)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess you would need to know the subclass as well. Hmmm... let me look at this a bit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right. My point is that you can always get back to the start of the array of MultiValueInstructionResults with just the current index, so you can store the parent pointer there without having to do any other instruction-specific dispatch. But I guess you could also use instruction-specific dispatch if the start of the MultiValueInstructionResult array is always at a static offset (which would require it to always be the first trailing object).
lib/SIL/SILPrinter.cpp
Outdated
if (auto value = dyn_cast<ValueBase>(node)) { | ||
// This allows for multiple return values. | ||
llvm::SmallVector<SILValue, 8> values; | ||
if (auto *value = dyn_cast<ValueBase>(node)) { | ||
// The base pointer of the ultimate ArrayRef here is just the | ||
// ValueBase; we aren't forming a reference to a temporary array. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment is now stale with this change.
lib/SIL/SILPrinter.cpp
Outdated
case SILNodeKind::MultipleValueInstructionResult: | ||
// We do not print anything for multiple value instruction result since we | ||
// print out the result when we print out various instructions. | ||
return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No. This may only happen in debugging paths, but just like the SILArgument case, you do need to handle that — this is what will be called if someone calls dump() on a SILValue that happens to be a MultipleValueInstructionResult.
I think the appropriate debug-printing is something like printing the instruction with a special emphasis on the appropriate result, like
%1 = destructure ...
(%2, **%3**, %4) = destructure ...
lib/SIL/SILPrinter.cpp
Outdated
// we'll assign the same ID to both the instruction and the | ||
// first result. | ||
for (auto result : results) { | ||
ValueToIDMap[result] = idx++; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was this change just a de-indenting? It looks fine to me, but I think it's probably unnecessarily confusing to do in the same patch as a bunch of multi-result compatibility fixes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I committed this separately. I just need to rebase.
lib/SIL/SILValue.cpp
Outdated
return DefiningInstructionResult{ inst, 0 }; | ||
// TODO: MultiValueInstruction | ||
if (auto *result = dyn_cast<MultipleValueInstructionResult>(this)) | ||
return DefiningInstructionResult{result->getParent(), result->getIndex()}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The style immediately above is to put spaces after the {
; you should be consistent one way or the other.
lib/SIL/SILValue.cpp
Outdated
} | ||
|
||
if (auto *MVIR = dyn_cast<MultipleValueInstructionResult>(this)) { | ||
return MVIR->getCanonicalSILNodeInObject(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getParent()
2e610f0
to
6387352
Compare
53dbf2c
to
f8aaa54
Compare
Hmm... looks like I lost a part of a commit while rebasing... |
@swift-ci test |
1 similar comment
@swift-ci test |
@swift-ci Please Test OS X Source Compatibility |
@swift-ci Please Test Source Compatibility |
1 similar comment
@swift-ci Please Test Source Compatibility |
@rjmccall This is ready for review. |
include/swift/SIL/SILValue.h
Outdated
friend class Operand; | ||
|
||
/// A 32 bit field of data that we provide for abstract subclasses to use. | ||
uint32_t SubclassData; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this in the base class. Why not putting the info in MultipleValueInstructionResult?
@rjmccall maybe a question to you
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because the space is already there in the base class because of alignment padding.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In a follow on commit, I will add some static_asserts/comments that says this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Er, wait, I was assuming you would add this to SILNode. It is not using spare bits when you add it to ValueBase like this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I read the first part of your previous comment where you were talking about putting this in the spare bits of ValueBase. For whatever reason I didn't grok the 2nd part of the sentence. I will fix this.
docs/SIL.rst
Outdated
@@ -784,8 +784,12 @@ Basic Blocks | |||
sil-label ::= sil-identifier ('(' sil-argument (',' sil-argument)* ')')? ':' | |||
sil-argument ::= sil-value-name ':' sil-type | |||
|
|||
sil-instruction-def ::= (sil-value-name '=')? sil-instruction | |||
(',' sil-loc)? (',' sil-scope-ref)? | |||
sil-instruction-result ::= sil-value-name '=' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
None of these should end in a '=', since you've made that part of sil-instruction-def.
docs/SIL.rst
Outdated
(',' sil-loc)? (',' sil-scope-ref)? | ||
sil-instruction-result ::= sil-value-name '=' | ||
sil-instruction-result ::= '(' sil-value-name? ')' | ||
sil-instruction-result ::= '(' sil-value-name (',' sil-value-name)* ')' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(sil-value-name (',' sil-value-name)*)?
is cleaner and doesn't create a formal ambiguity. It's how we specify e.g. the arguments to apply
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't make sense to me. You are not specifying the '(' and ')' that you need (unless I am missing something).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant for the contents of the parens. I'm just suggesting how to solve the "problem" that '(' sil-value-name ')'
technically matches both of those productions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand now. Thank you.
docs/SIL.rst
Outdated
// %eltN must have the type $EltNTy | ||
|
||
Given a tuple value, split the value into its constituant elements. The reason | ||
why we provide this is to ensure that +1 tuple can be split at one time into +1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"constituent"
You don't need to include a rationale here.
docs/SIL.rst
Outdated
|
||
Given a struct, split the struct into its constituant fields. The | ||
reason why we provide this is to ensure that +1 struct can be split at one time | ||
into +1 subobjects. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as for destructure_tuple
.
include/swift/SIL/SILInstruction.h
Outdated
class MultipleValueInstructionResult : public ValueBase { | ||
// Bits 0-2 of the first byte of SubclassData is used for the | ||
// ValueOwnershipKind. | ||
static constexpr unsigned NumBitsForOwnershipKind = 3; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The normal naming convention for this would be something like NumOwnershipKindBits, and it should probably be declared next to ValueOwnershipKind instead of being defined here.
include/swift/SIL/SILValue.h
Outdated
friend class Operand; | ||
|
||
/// A 32 bit field of data that we provide for abstract subclasses to use. | ||
uint32_t SubclassData; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Er, wait, I was assuming you would add this to SILNode. It is not using spare bits when you add it to ValueBase like this.
include/swift/SIL/SILValue.h
Outdated
|
||
MutableArrayRef<uint8_t> getSubclassData() { | ||
return {reinterpret_cast<uint8_t *>(&SubclassData), sizeof(SubclassData)}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems unnecessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was just trying to provide a nice wrapper. I can't do this anyways, once I pack into a bitfield in SILNode.
lib/SIL/SILPrinter.cpp
Outdated
@@ -922,6 +921,12 @@ class SILPrinter : public SILInstructionVisitor<SILPrinter> { | |||
case SILNodeKind::SILUndef: | |||
printSILUndef(cast<SILUndef>(node)); | |||
return; | |||
|
|||
#define MULTIPLE_VALUE_INST_RESULT(ID, PARENT) case SILNodeKind::ID: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pattern in this file is to put the case on the following line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, this was git-clang-format I think.
lib/SIL/SILOwnershipVerifier.cpp
Outdated
|
||
// Now, we /must/ have a guaranteed subobject, so lets assert that the | ||
// user | ||
// is actually guaranteed and add the subobject's users to our worklist. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"let's", word wrap.
lib/SIL/SILValue.cpp
Outdated
assert(hasMultipleSILNodes(getKind())); | ||
return &static_cast<const SILInstruction &>( | ||
static_cast<const SingleValueInstruction &>( | ||
static_cast<const ValueBase &>(*this))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the old indentation pattern looked nicer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just did git-clang-format.
5530fbb
to
b6f3599
Compare
@swift-ci smoke test |
@swift-ci Please Test Source Compatibility |
1 similar comment
@swift-ci Please Test Source Compatibility |
@swift-ci smoke test |
1 similar comment
@swift-ci smoke test |
…alueInstruction{,Result}. rdar://31521023
b6f3599
to
69d7227
Compare
@swift-ci smoke test |
1 similar comment
@swift-ci smoke test |
@swift-ci Please Test Source Compatibility |
1 similar comment
@swift-ci Please Test Source Compatibility |
@rjmccall This is ready for another round. If it is possible, I would like to do further changes in separate PRs as long as the high level functionality is correct. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. I'm fine with these comments being fixed in a follow-up patch.
} | ||
|
||
LLVM_ATTRIBUTE_ALWAYS_INLINE | ||
SILNodeKind getKind() const { | ||
return SILNodeKind(Kind); | ||
} | ||
|
||
/// Return the SILNodeKind of this node's canonical SILNode. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"representative"
} | ||
|
||
LLVM_ATTRIBUTE_ALWAYS_INLINE | ||
SILNodeKind getKind() const { | ||
return SILNodeKind(Kind); | ||
} | ||
|
||
/// Return the SILNodeKind of this node's canonical SILNode. | ||
/// | ||
/// TODO: Find a better name for this. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this name is good enough that we don't need this TODO anymore.
const unsigned Kind : NumKindBits; | ||
const unsigned StorageLoc : NumStorageLocBits; | ||
const unsigned IsRepresentativeNode : NumIsRepresentativeBits; | ||
uint64_t SubclassData : NumSubclassDataBits; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In order to pack these effectively on all platforms, please make them all uint64_t.
Instruction | ||
static constexpr unsigned NumKindBits = NumSILNodeKindBits; | ||
static constexpr unsigned NumStorageLocBits = 1; | ||
static constexpr unsigned NumIsRepresentativeBits = 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These three ought to be private.
static bool hasMultipleSILNodes(SILNodeKind kind) { | ||
public: | ||
/// Does the given kind of node inherit from multiple multiple SILNode base | ||
/// classes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is a question, it should end in a question mark.
return const_cast<MultipleValueInstructionResult *>(this)->getParent(); | ||
} | ||
|
||
unsigned getIndex() const; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be implemented inline, right? It's important enough to make sure it can be inlined even in non-WMO builds.
ValueOwnershipKind getOwnershipKind() const; | ||
|
||
SILNode *getCanonicalSILNodeInObject(); | ||
const SILNode *getCanonicalSILNodeInObject() const; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know why you have these overrides in subclasses, but they have the wrong name now.
"the SILInstruction subobject is always canonical"); | ||
return static_cast<SILInstruction*>(this); | ||
} | ||
const SILNode *getCanonicalSILNodeInObject() const { | ||
assert(SILInstruction::isCanonicalSILNodeInObject() && | ||
assert(SILInstruction::isRepresentativeSILNodeInObject() && | ||
"the SILInstruction subobject is always canonical"); | ||
return static_cast<const SILInstruction*>(this); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These have the wrong name now, if they're really needed at all.
"the SILInstruction subobject is always canonical"); | ||
return this; | ||
} | ||
const SILNode *getCanonicalSILNodeInObject() const { | ||
assert(isCanonicalSILNodeInObject() && | ||
assert(isRepresentativeSILNodeInObject() && | ||
"the SILInstruction subobject is always canonical"); | ||
return this; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These have the wrong name now, if they're really needed at all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was cargo-culting your design from other places. I will remove them.
return; | ||
auto *DataPtr = this->template getTrailingObjects<DerivedResult>(); | ||
for (unsigned i : range(NumResults)) | ||
DataPtr[i].~DerivedResult(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably worth leaving a comment that this is just for the assertion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no assertion here. Can you elaborate?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did the rest of the changes here: #12612. Once you elaborate, I'll take care of this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The assertion in ~ValueBase()
.
Thanks John! |
nice work! |
= ). I also want to give thanks to John for his great review! |
[sil] Add support for multiple value instructions by adding MultipleValueInstruction{,Result}.
rdar://31521023
I am just trying to get feedback started while I wait for @rjmccall to finish looking at the other PR.