1 | //===----------------------------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // These classes implement wrappers around mlir::Value in order to fully |
10 | // represent the range of values for C L- and R- values. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #ifndef CLANG_LIB_CIR_CIRGENVALUE_H |
15 | #define CLANG_LIB_CIR_CIRGENVALUE_H |
16 | |
17 | #include "Address.h" |
18 | |
19 | #include "clang/AST/CharUnits.h" |
20 | #include "clang/AST/Type.h" |
21 | |
22 | #include "mlir/IR/Value.h" |
23 | |
24 | #include "clang/CIR/MissingFeatures.h" |
25 | |
26 | namespace clang::CIRGen { |
27 | |
28 | /// This trivial value class is used to represent the result of an |
29 | /// expression that is evaluated. It can be one of three things: either a |
30 | /// simple MLIR SSA value, a pair of SSA values for complex numbers, or the |
31 | /// address of an aggregate value in memory. |
32 | class RValue { |
33 | enum Flavor { Scalar, Complex, Aggregate }; |
34 | |
35 | union { |
36 | // Stores first and second value. |
37 | struct { |
38 | mlir::Value first; |
39 | mlir::Value second; |
40 | } vals; |
41 | |
42 | // Stores aggregate address. |
43 | Address aggregateAddr; |
44 | }; |
45 | |
46 | unsigned isVolatile : 1; |
47 | unsigned flavor : 2; |
48 | |
49 | public: |
50 | RValue() : vals{nullptr, nullptr}, flavor(Scalar) {} |
51 | |
52 | bool isScalar() const { return flavor == Scalar; } |
53 | bool isComplex() const { return flavor == Complex; } |
54 | bool isAggregate() const { return flavor == Aggregate; } |
55 | |
56 | bool isVolatileQualified() const { return isVolatile; } |
57 | |
58 | /// Return the value of this scalar value. |
59 | mlir::Value getScalarVal() const { |
60 | assert(isScalar() && "Not a scalar!" ); |
61 | return vals.first; |
62 | } |
63 | |
64 | /// Return the real/imag components of this complex value. |
65 | std::pair<mlir::Value, mlir::Value> getComplexVal() const { |
66 | return std::make_pair(vals.first, vals.second); |
67 | } |
68 | |
69 | /// Return the value of the address of the aggregate. |
70 | Address getAggregateAddress() const { |
71 | assert(isAggregate() && "Not an aggregate!" ); |
72 | return aggregateAddr; |
73 | } |
74 | |
75 | mlir::Value getAggregatePointer(QualType pointeeType) const { |
76 | return getAggregateAddress().getPointer(); |
77 | } |
78 | |
79 | static RValue getIgnored() { |
80 | // FIXME: should we make this a more explicit state? |
81 | return get(nullptr); |
82 | } |
83 | |
84 | static RValue get(mlir::Value v) { |
85 | RValue er; |
86 | er.vals.first = v; |
87 | er.flavor = Scalar; |
88 | er.isVolatile = false; |
89 | return er; |
90 | } |
91 | |
92 | static RValue getComplex(mlir::Value v1, mlir::Value v2) { |
93 | RValue er; |
94 | er.vals = {v1, v2}; |
95 | er.flavor = Complex; |
96 | er.isVolatile = false; |
97 | return er; |
98 | } |
99 | static RValue getComplex(const std::pair<mlir::Value, mlir::Value> &c) { |
100 | return getComplex(c.first, c.second); |
101 | } |
102 | // FIXME: Aggregate rvalues need to retain information about whether they are |
103 | // volatile or not. Remove default to find all places that probably get this |
104 | // wrong. |
105 | |
106 | /// Convert an Address to an RValue. If the Address is not |
107 | /// signed, create an RValue using the unsigned address. Otherwise, resign the |
108 | /// address using the provided type. |
109 | static RValue getAggregate(Address addr, bool isVolatile = false) { |
110 | RValue er; |
111 | er.aggregateAddr = addr; |
112 | er.flavor = Aggregate; |
113 | er.isVolatile = isVolatile; |
114 | return er; |
115 | } |
116 | }; |
117 | |
118 | /// The source of the alignment of an l-value; an expression of |
119 | /// confidence in the alignment actually matching the estimate. |
120 | enum class AlignmentSource { |
121 | /// The l-value was an access to a declared entity or something |
122 | /// equivalently strong, like the address of an array allocated by a |
123 | /// language runtime. |
124 | Decl, |
125 | |
126 | /// The l-value was considered opaque, so the alignment was |
127 | /// determined from a type, but that type was an explicitly-aligned |
128 | /// typedef. |
129 | AttributedType, |
130 | |
131 | /// The l-value was considered opaque, so the alignment was |
132 | /// determined from a type. |
133 | Type |
134 | }; |
135 | |
136 | /// Given that the base address has the given alignment source, what's |
137 | /// our confidence in the alignment of the field? |
138 | static inline AlignmentSource getFieldAlignmentSource(AlignmentSource source) { |
139 | // For now, we don't distinguish fields of opaque pointers from |
140 | // top-level declarations, but maybe we should. |
141 | return AlignmentSource::Decl; |
142 | } |
143 | |
144 | class LValueBaseInfo { |
145 | AlignmentSource alignSource; |
146 | |
147 | public: |
148 | explicit LValueBaseInfo(AlignmentSource source = AlignmentSource::Type) |
149 | : alignSource(source) {} |
150 | AlignmentSource getAlignmentSource() const { return alignSource; } |
151 | void setAlignmentSource(AlignmentSource source) { alignSource = source; } |
152 | |
153 | void mergeForCast(const LValueBaseInfo &info) { |
154 | setAlignmentSource(info.getAlignmentSource()); |
155 | } |
156 | }; |
157 | |
158 | class LValue { |
159 | enum { |
160 | Simple, // This is a normal l-value, use getAddress(). |
161 | VectorElt, // This is a vector element l-value (V[i]), use getVector* |
162 | BitField, // This is a bitfield l-value, use getBitfield*. |
163 | ExtVectorElt, // This is an extended vector subset, use getExtVectorComp |
164 | GlobalReg, // This is a register l-value, use getGlobalReg() |
165 | MatrixElt // This is a matrix element, use getVector* |
166 | } lvType; |
167 | clang::QualType type; |
168 | clang::Qualifiers quals; |
169 | |
170 | // The alignment to use when accessing this lvalue. (For vector elements, |
171 | // this is the alignment of the whole vector) |
172 | unsigned alignment; |
173 | mlir::Value v; |
174 | mlir::Value vectorIdx; // Index for vector subscript |
175 | mlir::Type elementType; |
176 | LValueBaseInfo baseInfo; |
177 | |
178 | void initialize(clang::QualType type, clang::Qualifiers quals, |
179 | clang::CharUnits alignment, LValueBaseInfo baseInfo) { |
180 | assert((!alignment.isZero() || type->isIncompleteType()) && |
181 | "initializing l-value with zero alignment!" ); |
182 | this->type = type; |
183 | this->quals = quals; |
184 | const unsigned maxAlign = 1U << 31; |
185 | this->alignment = alignment.getQuantity() <= maxAlign |
186 | ? alignment.getQuantity() |
187 | : maxAlign; |
188 | assert(this->alignment == alignment.getQuantity() && |
189 | "Alignment exceeds allowed max!" ); |
190 | this->baseInfo = baseInfo; |
191 | } |
192 | |
193 | public: |
194 | bool isSimple() const { return lvType == Simple; } |
195 | bool isVectorElt() const { return lvType == VectorElt; } |
196 | bool isBitField() const { return lvType == BitField; } |
197 | |
198 | // TODO: Add support for volatile |
199 | bool isVolatile() const { return false; } |
200 | |
201 | unsigned getVRQualifiers() const { |
202 | return quals.getCVRQualifiers() & ~clang::Qualifiers::Const; |
203 | } |
204 | |
205 | clang::QualType getType() const { return type; } |
206 | |
207 | mlir::Value getPointer() const { return v; } |
208 | |
209 | clang::CharUnits getAlignment() const { |
210 | return clang::CharUnits::fromQuantity(Quantity: alignment); |
211 | } |
212 | void setAlignment(clang::CharUnits a) { alignment = a.getQuantity(); } |
213 | |
214 | Address getAddress() const { |
215 | return Address(getPointer(), elementType, getAlignment()); |
216 | } |
217 | |
218 | const clang::Qualifiers &getQuals() const { return quals; } |
219 | clang::Qualifiers &getQuals() { return quals; } |
220 | |
221 | LValueBaseInfo getBaseInfo() const { return baseInfo; } |
222 | void setBaseInfo(LValueBaseInfo info) { baseInfo = info; } |
223 | |
224 | static LValue makeAddr(Address address, clang::QualType t, |
225 | LValueBaseInfo baseInfo) { |
226 | // Classic codegen sets the objc gc qualifier here. That requires an |
227 | // ASTContext, which is passed in from CIRGenFunction::makeAddrLValue. |
228 | assert(!cir::MissingFeatures::objCGC()); |
229 | |
230 | LValue r; |
231 | r.lvType = Simple; |
232 | r.v = address.getPointer(); |
233 | r.elementType = address.getElementType(); |
234 | r.initialize(type: t, quals: t.getQualifiers(), alignment: address.getAlignment(), baseInfo); |
235 | return r; |
236 | } |
237 | |
238 | Address getVectorAddress() const { |
239 | return Address(getVectorPointer(), elementType, getAlignment()); |
240 | } |
241 | |
242 | mlir::Value getVectorPointer() const { |
243 | assert(isVectorElt()); |
244 | return v; |
245 | } |
246 | |
247 | mlir::Value getVectorIdx() const { |
248 | assert(isVectorElt()); |
249 | return vectorIdx; |
250 | } |
251 | |
252 | static LValue makeVectorElt(Address vecAddress, mlir::Value index, |
253 | clang::QualType t, LValueBaseInfo baseInfo) { |
254 | LValue r; |
255 | r.lvType = VectorElt; |
256 | r.v = vecAddress.getPointer(); |
257 | r.elementType = vecAddress.getElementType(); |
258 | r.vectorIdx = index; |
259 | r.initialize(type: t, quals: t.getQualifiers(), alignment: vecAddress.getAlignment(), baseInfo); |
260 | return r; |
261 | } |
262 | }; |
263 | |
264 | /// An aggregate value slot. |
265 | class AggValueSlot { |
266 | |
267 | Address addr; |
268 | clang::Qualifiers quals; |
269 | |
270 | /// This is set to true if the memory in the slot is known to be zero before |
271 | /// the assignment into it. This means that zero fields don't need to be set. |
272 | bool zeroedFlag : 1; |
273 | |
274 | public: |
275 | enum IsZeroed_t { IsNotZeroed, IsZeroed }; |
276 | |
277 | AggValueSlot(Address addr, clang::Qualifiers quals, bool zeroedFlag) |
278 | : addr(addr), quals(quals), zeroedFlag(zeroedFlag) {} |
279 | |
280 | static AggValueSlot forAddr(Address addr, clang::Qualifiers quals, |
281 | IsZeroed_t isZeroed = IsNotZeroed) { |
282 | return AggValueSlot(addr, quals, isZeroed); |
283 | } |
284 | |
285 | static AggValueSlot forLValue(const LValue &lv) { |
286 | return forAddr(addr: lv.getAddress(), quals: lv.getQuals()); |
287 | } |
288 | |
289 | clang::Qualifiers getQualifiers() const { return quals; } |
290 | |
291 | Address getAddress() const { return addr; } |
292 | |
293 | bool isIgnored() const { return !addr.isValid(); } |
294 | |
295 | IsZeroed_t isZeroed() const { return IsZeroed_t(zeroedFlag); } |
296 | }; |
297 | |
298 | } // namespace clang::CIRGen |
299 | |
300 | #endif // CLANG_LIB_CIR_CIRGENVALUE_H |
301 | |