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 "CIRGenRecordLayout.h"
23 #include "mlir/IR/Value.h"
24
25 #include "clang/CIR/MissingFeatures.h"
26
27 namespace clang::CIRGen {
28
29 /// This trivial value class is used to represent the result of an
30 /// expression that is evaluated. It can be one of three things: either a
31 /// simple MLIR SSA value, a pair of SSA values for complex numbers, or the
32 /// address of an aggregate value in memory.
33 class RValue {
34 enum Flavor { Scalar, Complex, Aggregate };
35
36 union {
37 mlir::Value value;
38
39 // Stores aggregate address.
40 Address aggregateAddr;
41 };
42
43 unsigned isVolatile : 1;
44 unsigned flavor : 2;
45
46 public:
RValue()47 RValue() : value(nullptr), flavor(Scalar) {}
48
isScalar()49 bool isScalar() const { return flavor == Scalar; }
isComplex()50 bool isComplex() const { return flavor == Complex; }
isAggregate()51 bool isAggregate() const { return flavor == Aggregate; }
52
isVolatileQualified()53 bool isVolatileQualified() const { return isVolatile; }
54
55 /// Return the value of this scalar value.
getValue()56 mlir::Value getValue() const {
57 assert(isScalar() && "Not a scalar!");
58 return value;
59 }
60
61 /// Return the value of the address of the aggregate.
getAggregateAddress()62 Address getAggregateAddress() const {
63 assert(isAggregate() && "Not an aggregate!");
64 return aggregateAddr;
65 }
66
getAggregatePointer(QualType pointeeType)67 mlir::Value getAggregatePointer(QualType pointeeType) const {
68 return getAggregateAddress().getPointer();
69 }
70
getIgnored()71 static RValue getIgnored() {
72 // FIXME: should we make this a more explicit state?
73 return get(nullptr);
74 }
75
get(mlir::Value v)76 static RValue get(mlir::Value v) {
77 RValue er;
78 er.value = v;
79 er.flavor = Scalar;
80 er.isVolatile = false;
81 return er;
82 }
83
getComplex(mlir::Value v)84 static RValue getComplex(mlir::Value v) {
85 RValue er;
86 er.value = v;
87 er.flavor = Complex;
88 er.isVolatile = false;
89 return er;
90 }
91
92 // volatile or not. Remove default to find all places that probably get this
93 // wrong.
94
95 /// Convert an Address to an RValue. If the Address is not
96 /// signed, create an RValue using the unsigned address. Otherwise, resign the
97 /// address using the provided type.
98 static RValue getAggregate(Address addr, bool isVolatile = false) {
99 RValue er;
100 er.aggregateAddr = addr;
101 er.flavor = Aggregate;
102 er.isVolatile = isVolatile;
103 return er;
104 }
105 };
106
107 /// The source of the alignment of an l-value; an expression of
108 /// confidence in the alignment actually matching the estimate.
109 enum class AlignmentSource {
110 /// The l-value was an access to a declared entity or something
111 /// equivalently strong, like the address of an array allocated by a
112 /// language runtime.
113 Decl,
114
115 /// The l-value was considered opaque, so the alignment was
116 /// determined from a type, but that type was an explicitly-aligned
117 /// typedef.
118 AttributedType,
119
120 /// The l-value was considered opaque, so the alignment was
121 /// determined from a type.
122 Type
123 };
124
125 /// Given that the base address has the given alignment source, what's
126 /// our confidence in the alignment of the field?
getFieldAlignmentSource(AlignmentSource source)127 static inline AlignmentSource getFieldAlignmentSource(AlignmentSource source) {
128 // For now, we don't distinguish fields of opaque pointers from
129 // top-level declarations, but maybe we should.
130 return AlignmentSource::Decl;
131 }
132
133 class LValueBaseInfo {
134 AlignmentSource alignSource;
135
136 public:
137 explicit LValueBaseInfo(AlignmentSource source = AlignmentSource::Type)
alignSource(source)138 : alignSource(source) {}
getAlignmentSource()139 AlignmentSource getAlignmentSource() const { return alignSource; }
setAlignmentSource(AlignmentSource source)140 void setAlignmentSource(AlignmentSource source) { alignSource = source; }
141
mergeForCast(const LValueBaseInfo & info)142 void mergeForCast(const LValueBaseInfo &info) {
143 setAlignmentSource(info.getAlignmentSource());
144 }
145 };
146
147 class LValue {
148 enum {
149 Simple, // This is a normal l-value, use getAddress().
150 VectorElt, // This is a vector element l-value (V[i]), use getVector*
151 BitField, // This is a bitfield l-value, use getBitfield*.
152 ExtVectorElt, // This is an extended vector subset, use getExtVectorComp
153 GlobalReg, // This is a register l-value, use getGlobalReg()
154 MatrixElt // This is a matrix element, use getVector*
155 } lvType;
156 clang::QualType type;
157 clang::Qualifiers quals;
158
159 // The alignment to use when accessing this lvalue. (For vector elements,
160 // this is the alignment of the whole vector)
161 unsigned alignment;
162 mlir::Value v;
163 mlir::Value vectorIdx; // Index for vector subscript
164 mlir::Type elementType;
165 LValueBaseInfo baseInfo;
166 const CIRGenBitFieldInfo *bitFieldInfo{nullptr};
167
initialize(clang::QualType type,clang::Qualifiers quals,clang::CharUnits alignment,LValueBaseInfo baseInfo)168 void initialize(clang::QualType type, clang::Qualifiers quals,
169 clang::CharUnits alignment, LValueBaseInfo baseInfo) {
170 assert((!alignment.isZero() || type->isIncompleteType()) &&
171 "initializing l-value with zero alignment!");
172 this->type = type;
173 this->quals = quals;
174 const unsigned maxAlign = 1U << 31;
175 this->alignment = alignment.getQuantity() <= maxAlign
176 ? alignment.getQuantity()
177 : maxAlign;
178 assert(this->alignment == alignment.getQuantity() &&
179 "Alignment exceeds allowed max!");
180 this->baseInfo = baseInfo;
181 }
182
183 public:
isSimple()184 bool isSimple() const { return lvType == Simple; }
isVectorElt()185 bool isVectorElt() const { return lvType == VectorElt; }
isBitField()186 bool isBitField() const { return lvType == BitField; }
isVolatile()187 bool isVolatile() const { return quals.hasVolatile(); }
188
isVolatileQualified()189 bool isVolatileQualified() const { return quals.hasVolatile(); }
190
getVRQualifiers()191 unsigned getVRQualifiers() const {
192 return quals.getCVRQualifiers() & ~clang::Qualifiers::Const;
193 }
194
getType()195 clang::QualType getType() const { return type; }
196
getPointer()197 mlir::Value getPointer() const { return v; }
198
getAlignment()199 clang::CharUnits getAlignment() const {
200 return clang::CharUnits::fromQuantity(alignment);
201 }
setAlignment(clang::CharUnits a)202 void setAlignment(clang::CharUnits a) { alignment = a.getQuantity(); }
203
getAddress()204 Address getAddress() const {
205 return Address(getPointer(), elementType, getAlignment());
206 }
207
getQuals()208 const clang::Qualifiers &getQuals() const { return quals; }
getQuals()209 clang::Qualifiers &getQuals() { return quals; }
210
getBaseInfo()211 LValueBaseInfo getBaseInfo() const { return baseInfo; }
setBaseInfo(LValueBaseInfo info)212 void setBaseInfo(LValueBaseInfo info) { baseInfo = info; }
213
makeAddr(Address address,clang::QualType t,LValueBaseInfo baseInfo)214 static LValue makeAddr(Address address, clang::QualType t,
215 LValueBaseInfo baseInfo) {
216 // Classic codegen sets the objc gc qualifier here. That requires an
217 // ASTContext, which is passed in from CIRGenFunction::makeAddrLValue.
218 assert(!cir::MissingFeatures::objCGC());
219
220 LValue r;
221 r.lvType = Simple;
222 r.v = address.getPointer();
223 r.elementType = address.getElementType();
224 r.initialize(t, t.getQualifiers(), address.getAlignment(), baseInfo);
225 return r;
226 }
227
getVectorAddress()228 Address getVectorAddress() const {
229 return Address(getVectorPointer(), elementType, getAlignment());
230 }
231
getVectorPointer()232 mlir::Value getVectorPointer() const {
233 assert(isVectorElt());
234 return v;
235 }
236
getVectorIdx()237 mlir::Value getVectorIdx() const {
238 assert(isVectorElt());
239 return vectorIdx;
240 }
241
makeVectorElt(Address vecAddress,mlir::Value index,clang::QualType t,LValueBaseInfo baseInfo)242 static LValue makeVectorElt(Address vecAddress, mlir::Value index,
243 clang::QualType t, LValueBaseInfo baseInfo) {
244 LValue r;
245 r.lvType = VectorElt;
246 r.v = vecAddress.getPointer();
247 r.elementType = vecAddress.getElementType();
248 r.vectorIdx = index;
249 r.initialize(t, t.getQualifiers(), vecAddress.getAlignment(), baseInfo);
250 return r;
251 }
252
253 // bitfield lvalue
getBitFieldAddress()254 Address getBitFieldAddress() const {
255 return Address(getBitFieldPointer(), elementType, getAlignment());
256 }
257
getBitFieldPointer()258 mlir::Value getBitFieldPointer() const {
259 assert(isBitField());
260 return v;
261 }
262
getBitFieldInfo()263 const CIRGenBitFieldInfo &getBitFieldInfo() const {
264 assert(isBitField());
265 return *bitFieldInfo;
266 }
267
268 /// Create a new object to represent a bit-field access.
269 ///
270 /// \param Addr - The base address of the bit-field sequence this
271 /// bit-field refers to.
272 /// \param Info - The information describing how to perform the bit-field
273 /// access.
makeBitfield(Address addr,const CIRGenBitFieldInfo & info,clang::QualType type,LValueBaseInfo baseInfo)274 static LValue makeBitfield(Address addr, const CIRGenBitFieldInfo &info,
275 clang::QualType type, LValueBaseInfo baseInfo) {
276 LValue r;
277 r.lvType = BitField;
278 r.v = addr.getPointer();
279 r.elementType = addr.getElementType();
280 r.bitFieldInfo = &info;
281 r.initialize(type, type.getQualifiers(), addr.getAlignment(), baseInfo);
282 return r;
283 }
284 };
285
286 /// An aggregate value slot.
287 class AggValueSlot {
288
289 Address addr;
290 clang::Qualifiers quals;
291
292 /// This is set to true if some external code is responsible for setting up a
293 /// destructor for the slot. Otherwise the code which constructs it should
294 /// push the appropriate cleanup.
295 LLVM_PREFERRED_TYPE(bool)
296 LLVM_ATTRIBUTE_UNUSED unsigned destructedFlag : 1;
297
298 /// This is set to true if the memory in the slot is known to be zero before
299 /// the assignment into it. This means that zero fields don't need to be set.
300 LLVM_PREFERRED_TYPE(bool)
301 unsigned zeroedFlag : 1;
302
303 /// This is set to true if the slot might be aliased and it's not undefined
304 /// behavior to access it through such an alias. Note that it's always
305 /// undefined behavior to access a C++ object that's under construction
306 /// through an alias derived from outside the construction process.
307 ///
308 /// This flag controls whether calls that produce the aggregate
309 /// value may be evaluated directly into the slot, or whether they
310 /// must be evaluated into an unaliased temporary and then memcpy'ed
311 /// over. Since it's invalid in general to memcpy a non-POD C++
312 /// object, it's important that this flag never be set when
313 /// evaluating an expression which constructs such an object.
314 LLVM_PREFERRED_TYPE(bool)
315 LLVM_ATTRIBUTE_UNUSED unsigned aliasedFlag : 1;
316
317 /// This is set to true if the tail padding of this slot might overlap
318 /// another object that may have already been initialized (and whose
319 /// value must be preserved by this initialization). If so, we may only
320 /// store up to the dsize of the type. Otherwise we can widen stores to
321 /// the size of the type.
322 LLVM_PREFERRED_TYPE(bool)
323 LLVM_ATTRIBUTE_UNUSED unsigned overlapFlag : 1;
324
325 public:
326 enum IsDestructed_t { IsNotDestructed, IsDestructed };
327 enum IsZeroed_t { IsNotZeroed, IsZeroed };
328 enum IsAliased_t { IsNotAliased, IsAliased };
329 enum Overlap_t { MayOverlap, DoesNotOverlap };
330
331 /// Returns an aggregate value slot indicating that the aggregate
332 /// value is being ignored.
ignored()333 static AggValueSlot ignored() {
334 return forAddr(Address::invalid(), clang::Qualifiers(), IsNotDestructed,
335 IsNotAliased, DoesNotOverlap);
336 }
337
AggValueSlot(Address addr,clang::Qualifiers quals,bool destructedFlag,bool zeroedFlag,bool aliasedFlag,bool overlapFlag)338 AggValueSlot(Address addr, clang::Qualifiers quals, bool destructedFlag,
339 bool zeroedFlag, bool aliasedFlag, bool overlapFlag)
340 : addr(addr), quals(quals), destructedFlag(destructedFlag),
341 zeroedFlag(zeroedFlag), aliasedFlag(aliasedFlag),
342 overlapFlag(overlapFlag) {}
343
344 static AggValueSlot forAddr(Address addr, clang::Qualifiers quals,
345 IsDestructed_t isDestructed,
346 IsAliased_t isAliased, Overlap_t mayOverlap,
347 IsZeroed_t isZeroed = IsNotZeroed) {
348 return AggValueSlot(addr, quals, isDestructed, isZeroed, isAliased,
349 mayOverlap);
350 }
351
352 static AggValueSlot forLValue(const LValue &LV, IsDestructed_t isDestructed,
353 IsAliased_t isAliased, Overlap_t mayOverlap,
354 IsZeroed_t isZeroed = IsNotZeroed) {
355 return forAddr(LV.getAddress(), LV.getQuals(), isDestructed, isAliased,
356 mayOverlap, isZeroed);
357 }
358
getQualifiers()359 clang::Qualifiers getQualifiers() const { return quals; }
360
getAddress()361 Address getAddress() const { return addr; }
362
isIgnored()363 bool isIgnored() const { return !addr.isValid(); }
364
getPointer()365 mlir::Value getPointer() const { return addr.getPointer(); }
366
isZeroed()367 IsZeroed_t isZeroed() const { return IsZeroed_t(zeroedFlag); }
368
asRValue()369 RValue asRValue() const {
370 if (isIgnored())
371 return RValue::getIgnored();
372 assert(!cir::MissingFeatures::aggValueSlot());
373 return RValue::getAggregate(getAddress());
374 }
375 };
376
377 } // namespace clang::CIRGen
378
379 #endif // CLANG_LIB_CIR_CIRGENVALUE_H
380