Skip to content

Commit 17cba85

Browse files
authored
Merge pull request #67072 from meg-gupta/forwardingwrappertypepr
Introduce ForwardingOperation wrapper type
2 parents 31176c7 + 0786344 commit 17cba85

File tree

11 files changed

+455
-381
lines changed

11 files changed

+455
-381
lines changed

include/swift/SIL/InstWrappers.h

Lines changed: 326 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,326 @@
1+
//===--- InstructionUtils.h - Utilities for SIL instructions ----*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef SWIFT_SIL_WRAPPERTYPES_H
14+
#define SWIFT_SIL_WRAPPERTYPES_H
15+
16+
#include "swift/SIL/SILInstruction.h"
17+
18+
namespace swift {
19+
/// An abstraction over LoadInst/LoadBorrowInst so one can handle both types of
20+
/// load using common code.
21+
struct LoadOperation {
22+
llvm::PointerUnion<LoadInst *, LoadBorrowInst *> value;
23+
24+
LoadOperation() : value() {}
25+
LoadOperation(SILInstruction *input) : value(nullptr) {
26+
if (auto *li = dyn_cast<LoadInst>(input)) {
27+
value = li;
28+
return;
29+
}
30+
31+
if (auto *lbi = dyn_cast<LoadBorrowInst>(input)) {
32+
value = lbi;
33+
return;
34+
}
35+
}
36+
37+
explicit operator bool() const { return !value.isNull(); }
38+
39+
SingleValueInstruction *getLoadInst() const {
40+
if (value.is<LoadInst *>())
41+
return value.get<LoadInst *>();
42+
return value.get<LoadBorrowInst *>();
43+
}
44+
45+
SingleValueInstruction *operator*() const { return getLoadInst(); }
46+
47+
const SingleValueInstruction *operator->() const { return getLoadInst(); }
48+
49+
SingleValueInstruction *operator->() { return getLoadInst(); }
50+
51+
SILValue getOperand() const {
52+
if (value.is<LoadInst *>())
53+
return value.get<LoadInst *>()->getOperand();
54+
return value.get<LoadBorrowInst *>()->getOperand();
55+
}
56+
57+
/// Return the ownership qualifier of the underlying load if we have a load or
58+
/// None if we have a load_borrow.
59+
///
60+
/// TODO: Rather than use an optional here, we should include an invalid
61+
/// representation in LoadOwnershipQualifier.
62+
llvm::Optional<LoadOwnershipQualifier> getOwnershipQualifier() const {
63+
if (auto *lbi = value.dyn_cast<LoadBorrowInst *>()) {
64+
return llvm::None;
65+
}
66+
67+
return value.get<LoadInst *>()->getOwnershipQualifier();
68+
}
69+
};
70+
71+
/// A wrapper type for writing generic code against conversion instructions.
72+
struct ConversionOperation {
73+
SingleValueInstruction *inst = nullptr;
74+
75+
ConversionOperation() = default;
76+
77+
explicit ConversionOperation(SILInstruction *inst) {
78+
auto *svi = dyn_cast<SingleValueInstruction>(inst);
79+
if (!svi) {
80+
return;
81+
}
82+
if (!ConversionOperation::isa(svi)) {
83+
return;
84+
}
85+
this->inst = svi;
86+
}
87+
88+
explicit ConversionOperation(SILValue value) {
89+
auto *inst = value->getDefiningInstruction();
90+
if (!inst) {
91+
return;
92+
}
93+
auto *svi = dyn_cast<SingleValueInstruction>(inst);
94+
if (!svi) {
95+
return;
96+
}
97+
if (!ConversionOperation::isa(svi)) {
98+
return;
99+
}
100+
this->inst = svi;
101+
}
102+
103+
operator bool() const { return inst != nullptr; }
104+
105+
SingleValueInstruction *operator->() { return inst; }
106+
SingleValueInstruction *operator->() const { return inst; }
107+
SingleValueInstruction *operator*() { return inst; }
108+
SingleValueInstruction *operator*() const { return inst; }
109+
110+
static bool isa(SILInstruction *inst) {
111+
switch (inst->getKind()) {
112+
case SILInstructionKind::ConvertFunctionInst:
113+
case SILInstructionKind::UpcastInst:
114+
case SILInstructionKind::AddressToPointerInst:
115+
case SILInstructionKind::UncheckedTrivialBitCastInst:
116+
case SILInstructionKind::UncheckedAddrCastInst:
117+
case SILInstructionKind::UncheckedBitwiseCastInst:
118+
case SILInstructionKind::RefToRawPointerInst:
119+
case SILInstructionKind::RawPointerToRefInst:
120+
case SILInstructionKind::ConvertEscapeToNoEscapeInst:
121+
case SILInstructionKind::RefToBridgeObjectInst:
122+
case SILInstructionKind::BridgeObjectToRefInst:
123+
case SILInstructionKind::BridgeObjectToWordInst:
124+
case SILInstructionKind::ThinToThickFunctionInst:
125+
case SILInstructionKind::ThickToObjCMetatypeInst:
126+
case SILInstructionKind::ObjCToThickMetatypeInst:
127+
case SILInstructionKind::ObjCMetatypeToObjectInst:
128+
case SILInstructionKind::ObjCExistentialMetatypeToObjectInst:
129+
case SILInstructionKind::UnconditionalCheckedCastInst:
130+
case SILInstructionKind::UncheckedRefCastInst:
131+
case SILInstructionKind::UncheckedValueCastInst:
132+
case SILInstructionKind::RefToUnmanagedInst:
133+
case SILInstructionKind::RefToUnownedInst:
134+
case SILInstructionKind::UnmanagedToRefInst:
135+
case SILInstructionKind::UnownedToRefInst:
136+
return true;
137+
default:
138+
return false;
139+
}
140+
}
141+
142+
SILValue getConverted() { return inst->getOperand(0); }
143+
};
144+
145+
/// A wrapper type for writing generic code against SelectEnumAddrInst and
146+
/// SelectEnumInst.
147+
///
148+
/// We use this instead of SelectEnumInstBase in order to avoid the need for
149+
/// templating SelectEnumInstBase.
150+
class SelectEnumOperation {
151+
PointerUnion<SelectEnumAddrInst *, SelectEnumInst *> value;
152+
153+
public:
154+
SelectEnumOperation(SelectEnumAddrInst *seai) : value(seai) {}
155+
SelectEnumOperation(SelectEnumInst *seai) : value(seai) {}
156+
SelectEnumOperation(SILInstruction *i) : value(nullptr) {
157+
if (auto *seai = dyn_cast<SelectEnumAddrInst>(i)) {
158+
value = seai;
159+
return;
160+
}
161+
162+
if (auto *sei = dyn_cast<SelectEnumInst>(i)) {
163+
value = sei;
164+
return;
165+
}
166+
}
167+
168+
SelectEnumOperation(const SILInstruction *i)
169+
: SelectEnumOperation(const_cast<SILInstruction *>(i)) {}
170+
171+
operator SingleValueInstruction *() const {
172+
if (auto *seai = value.dyn_cast<SelectEnumAddrInst *>())
173+
return seai;
174+
return value.get<SelectEnumInst *>();
175+
}
176+
177+
SingleValueInstruction *operator*() const {
178+
if (auto *seai = value.dyn_cast<SelectEnumAddrInst *>())
179+
return seai;
180+
return value.get<SelectEnumInst *>();
181+
}
182+
183+
SingleValueInstruction *operator->() const {
184+
if (auto *seai = value.dyn_cast<SelectEnumAddrInst *>())
185+
return seai;
186+
return value.get<SelectEnumInst *>();
187+
}
188+
189+
operator bool() const { return bool(value); }
190+
191+
SILValue getOperand() {
192+
if (auto *sei = value.dyn_cast<SelectEnumInst *>())
193+
return sei->getOperand();
194+
return value.get<SelectEnumAddrInst *>()->getOperand();
195+
}
196+
197+
SILValue getEnumOperand() { return getOperand(); }
198+
199+
const Operand &getEnumOperandRef() {
200+
if (auto *sei = value.dyn_cast<SelectEnumInst *>())
201+
return sei->getEnumOperandRef();
202+
return value.get<SelectEnumAddrInst *>()->getEnumOperandRef();
203+
}
204+
205+
unsigned getNumCases() const {
206+
if (auto *sei = value.dyn_cast<SelectEnumInst *>())
207+
return sei->getNumCases();
208+
return value.get<SelectEnumAddrInst *>()->getNumCases();
209+
}
210+
211+
std::pair<EnumElementDecl *, SILValue> getCase(unsigned i) const {
212+
if (auto *sei = value.dyn_cast<SelectEnumInst *>())
213+
return sei->getCase(i);
214+
return value.get<SelectEnumAddrInst *>()->getCase(i);
215+
}
216+
/// Return the value that will be used as the result for the specified enum
217+
/// case.
218+
SILValue getCaseResult(EnumElementDecl *D) {
219+
if (auto *sei = value.dyn_cast<SelectEnumInst *>())
220+
return sei->getCaseResult(D);
221+
return value.get<SelectEnumAddrInst *>()->getCaseResult(D);
222+
}
223+
224+
/// If the default refers to exactly one case decl, return it.
225+
NullablePtr<EnumElementDecl> getUniqueCaseForDefault();
226+
227+
bool hasDefault() const {
228+
if (auto *sei = value.dyn_cast<SelectEnumInst *>())
229+
return sei->hasDefault();
230+
return value.get<SelectEnumAddrInst *>()->hasDefault();
231+
}
232+
233+
SILValue getDefaultResult() const {
234+
if (auto *sei = value.dyn_cast<SelectEnumInst *>())
235+
return sei->getDefaultResult();
236+
return value.get<SelectEnumAddrInst *>()->getDefaultResult();
237+
}
238+
};
239+
240+
class ForwardingOperation {
241+
SILInstruction *forwardingInst = nullptr;
242+
243+
public:
244+
explicit ForwardingOperation(SILInstruction *inst);
245+
246+
operator bool() const { return bool(forwardingInst); }
247+
const SILInstruction *operator->() const { return forwardingInst; }
248+
SILInstruction *operator->() { return forwardingInst; }
249+
const SILInstruction *operator*() const { return forwardingInst; }
250+
SILInstruction *operator*() { return forwardingInst; }
251+
252+
ValueOwnershipKind getForwardingOwnershipKind();
253+
bool preservesOwnership();
254+
255+
// FIXME: Find a better name. Even unary instructions like struct_extract
256+
// forward "all" operands.
257+
bool canForwardAllOperands() const {
258+
switch (forwardingInst->getKind()) {
259+
case SILInstructionKind::StructInst:
260+
case SILInstructionKind::TupleInst:
261+
case SILInstructionKind::LinearFunctionInst:
262+
case SILInstructionKind::DifferentiableFunctionInst:
263+
return true;
264+
default:
265+
return false;
266+
}
267+
}
268+
269+
// FIXME: Find a better name. Even instructions that forward all operands can
270+
// forward the first operand.
271+
bool canForwardFirstOperandOnly() const {
272+
return !canForwardAllOperands() && forwardingInst->getNumRealOperands() > 0;
273+
}
274+
275+
ArrayRef<Operand> getForwardedOperands() const {
276+
if (canForwardAllOperands()) {
277+
return forwardingInst->getAllOperands();
278+
}
279+
if (canForwardFirstOperandOnly()) {
280+
return forwardingInst->getOperandRef(0);
281+
}
282+
return {};
283+
}
284+
285+
MutableArrayRef<Operand> getForwardedOperands() {
286+
if (canForwardAllOperands()) {
287+
return forwardingInst->getAllOperands();
288+
}
289+
if (canForwardFirstOperandOnly()) {
290+
return forwardingInst->getOperandRef(0);
291+
}
292+
return {};
293+
}
294+
295+
bool canForwardOwnedCompatibleValuesOnly() {
296+
switch (forwardingInst->getKind()) {
297+
case SILInstructionKind::MarkUninitializedInst:
298+
return true;
299+
default:
300+
return false;
301+
}
302+
}
303+
304+
bool canForwardGuaranteedCompatibleValuesOnly() {
305+
switch (forwardingInst->getKind()) {
306+
case SILInstructionKind::TupleExtractInst:
307+
case SILInstructionKind::StructExtractInst:
308+
case SILInstructionKind::DifferentiableFunctionExtractInst:
309+
case SILInstructionKind::LinearFunctionExtractInst:
310+
return true;
311+
default:
312+
return false;
313+
}
314+
}
315+
316+
/// Return true if the forwarded value has the same representation. If true,
317+
/// then the result can be mapped to the same storage without a move or copy.
318+
bool hasSameRepresentation() const;
319+
320+
/// Return true if the forwarded value is address-only either before or after
321+
/// forwarding.
322+
bool isAddressOnly() const;
323+
};
324+
} // end namespace swift
325+
326+
#endif

0 commit comments

Comments
 (0)