Value.cpp
8.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
//===- Value.cpp - MLIR Value Classes -------------------------------------===//
//
// Part of the MLIR Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "mlir/IR/Value.h"
#include "mlir/IR/Block.h"
#include "mlir/IR/Operation.h"
#include "mlir/IR/StandardTypes.h"
using namespace mlir;
/// Construct a value.
Value::Value(detail::BlockArgumentImpl *impl)
: ownerAndKind(impl, Kind::BlockArgument) {}
Value::Value(Operation *op, unsigned resultNo) {
assert(op->getNumResults() > resultNo && "invalid result number");
if (LLVM_LIKELY(canPackResultInline(resultNo))) {
ownerAndKind = {op, static_cast<Kind>(resultNo)};
return;
}
// If we can't pack the result directly, we need to represent this as a
// trailing result.
unsigned trailingResultNo =
resultNo - static_cast<unsigned>(Kind::TrailingOpResult);
ownerAndKind = {op->getTrailingResult(trailingResultNo),
Kind::TrailingOpResult};
}
/// Return the type of this value.
Type Value::getType() const {
if (BlockArgument arg = dyn_cast<BlockArgument>())
return arg.getType();
// If this is an operation result, query the parent operation.
OpResult result = cast<OpResult>();
Operation *owner = result.getOwner();
if (owner->hasSingleResult)
return owner->resultType;
return owner->resultType.cast<TupleType>().getType(result.getResultNumber());
}
/// Mutate the type of this Value to be of the specified type.
void Value::setType(Type newType) {
if (BlockArgument arg = dyn_cast<BlockArgument>())
return arg.setType(newType);
OpResult result = cast<OpResult>();
// If the owner has a single result, simply update it directly.
Operation *owner = result.getOwner();
if (owner->hasSingleResult) {
owner->resultType = newType;
return;
}
unsigned resultNo = result.getResultNumber();
// Otherwise, rebuild the tuple if the new type is different from the current.
auto curTypes = owner->resultType.cast<TupleType>().getTypes();
if (curTypes[resultNo] == newType)
return;
auto newTypes = llvm::to_vector<4>(curTypes);
newTypes[resultNo] = newType;
owner->resultType = TupleType::get(newTypes, newType.getContext());
}
/// If this value is the result of an Operation, return the operation that
/// defines it.
Operation *Value::getDefiningOp() const {
if (auto result = dyn_cast<OpResult>())
return result.getOwner();
return nullptr;
}
Location Value::getLoc() const {
if (auto *op = getDefiningOp())
return op->getLoc();
return UnknownLoc::get(getContext());
}
/// Return the Region in which this Value is defined.
Region *Value::getParentRegion() {
if (auto *op = getDefiningOp())
return op->getParentRegion();
return cast<BlockArgument>().getOwner()->getParent();
}
//===----------------------------------------------------------------------===//
// Value::UseLists
//===----------------------------------------------------------------------===//
/// Provide the use list that is attached to this value.
IRObjectWithUseList<OpOperand> *Value::getUseList() const {
if (BlockArgument arg = dyn_cast<BlockArgument>())
return arg.getImpl();
return cast<OpResult>().getOwner();
}
/// Drop all uses of this object from their respective owners.
void Value::dropAllUses() const {
if (BlockArgument arg = dyn_cast<BlockArgument>())
return arg.getImpl()->dropAllUses();
return cast<OpResult>().getOwner()->dropAllUses(*this);
}
/// Replace all uses of 'this' value with the new value, updating anything in
/// the IR that uses 'this' to use the other value instead. When this returns
/// there are zero uses of 'this'.
void Value::replaceAllUsesWith(Value newValue) const {
if (BlockArgument arg = dyn_cast<BlockArgument>())
return arg.getImpl()->replaceAllUsesWith(newValue);
IRMultiObjectWithUseList<OpOperand> *useList = cast<OpResult>().getOwner();
useList->replaceAllUsesWith(*this, newValue);
}
//===--------------------------------------------------------------------===//
// Uses
auto Value::use_begin() const -> use_iterator {
if (BlockArgument arg = dyn_cast<BlockArgument>())
return arg.getImpl()->use_begin();
return cast<OpResult>().getOwner()->use_begin(*this);
}
/// Returns true if this value has exactly one use.
bool Value::hasOneUse() const {
if (BlockArgument arg = dyn_cast<BlockArgument>())
return arg.getImpl()->hasOneUse();
return cast<OpResult>().getOwner()->hasOneUse(*this);
}
/// Returns true if this value has no uses.
bool Value::use_empty() const {
if (BlockArgument arg = dyn_cast<BlockArgument>())
return arg.getImpl()->use_empty();
return cast<OpResult>().getOwner()->use_empty(*this);
}
//===----------------------------------------------------------------------===//
// OpResult
//===----------------------------------------------------------------------===//
/// Returns the operation that owns this result.
Operation *OpResult::getOwner() const {
// If the result is in-place, the `owner` is the operation.
if (LLVM_LIKELY(getKind() != Kind::TrailingOpResult))
return reinterpret_cast<Operation *>(ownerAndKind.getPointer());
// Otherwise, we need to do some arithmetic to get the operation pointer.
// Move the trailing owner to the start of the array.
auto *trailingIt =
static_cast<detail::TrailingOpResult *>(ownerAndKind.getPointer());
trailingIt -= trailingIt->trailingResultNumber;
// This point is the first trailing object after the operation. So all we need
// to do here is adjust for the operation size.
return reinterpret_cast<Operation *>(trailingIt) - 1;
}
/// Return the result number of this result.
unsigned OpResult::getResultNumber() const {
// If the result is in-place, we can use the kind directly.
if (LLVM_LIKELY(getKind() != Kind::TrailingOpResult))
return static_cast<unsigned>(ownerAndKind.getInt());
// Otherwise, we add the number of inline results to the trailing owner.
auto *trailingIt =
static_cast<detail::TrailingOpResult *>(ownerAndKind.getPointer());
unsigned trailingNumber = trailingIt->trailingResultNumber;
return trailingNumber + static_cast<unsigned>(Kind::TrailingOpResult);
}
/// Given a number of operation results, returns the number that need to be
/// stored as trailing.
unsigned OpResult::getNumTrailing(unsigned numResults) {
// If we can pack all of the results, there is no need for additional storage.
if (numResults <= static_cast<unsigned>(Kind::TrailingOpResult))
return 0;
return numResults - static_cast<unsigned>(Kind::TrailingOpResult);
}
//===----------------------------------------------------------------------===//
// BlockOperand
//===----------------------------------------------------------------------===//
/// Provide the use list that is attached to the given block.
IRObjectWithUseList<BlockOperand> *BlockOperand::getUseList(Block *value) {
return value;
}
/// Return which operand this is in the operand list.
unsigned BlockOperand::getOperandNumber() {
return this - &getOwner()->getBlockOperands()[0];
}
//===----------------------------------------------------------------------===//
// OpOperand
//===----------------------------------------------------------------------===//
/// Provide the use list that is attached to the given value.
IRObjectWithUseList<OpOperand> *OpOperand::getUseList(Value value) {
return value.getUseList();
}
/// Return the current value being used by this operand.
Value OpOperand::get() const {
return IROperand<OpOperand, detail::OpaqueValue>::get();
}
/// Set the operand to the given value.
void OpOperand::set(Value value) {
IROperand<OpOperand, detail::OpaqueValue>::set(value);
}
/// Return which operand this is in the operand list.
unsigned OpOperand::getOperandNumber() {
return this - &getOwner()->getOpOperands()[0];
}
//===----------------------------------------------------------------------===//
// detail::OpaqueValue
//===----------------------------------------------------------------------===//
/// Implicit conversion from 'Value'.
detail::OpaqueValue::OpaqueValue(Value value)
: impl(value.getAsOpaquePointer()) {}
/// Implicit conversion back to 'Value'.
detail::OpaqueValue::operator Value() const {
return Value::getFromOpaquePointer(impl);
}