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
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
|
//===----------------------------------------------------------------------===//
//
// Part of the LLVM 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
//
//===----------------------------------------------------------------------===//
//
// These classes implement wrappers around mlir::Value in order to fully
// represent the range of values for C L- and R- values.
//
//===----------------------------------------------------------------------===//
#ifndef CLANG_LIB_CIR_CIRGENVALUE_H
#define CLANG_LIB_CIR_CIRGENVALUE_H
#include "Address.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/Type.h"
#include "CIRGenRecordLayout.h"
#include "mlir/IR/Value.h"
#include "clang/CIR/MissingFeatures.h"
namespace clang::CIRGen {
/// This trivial value class is used to represent the result of an
/// expression that is evaluated. It can be one of three things: either a
/// simple MLIR SSA value, a pair of SSA values for complex numbers, or the
/// address of an aggregate value in memory.
class RValue {
enum Flavor { Scalar, Complex, Aggregate };
union {
mlir::Value value;
// Stores aggregate address.
Address aggregateAddr;
};
unsigned isVolatile : 1;
unsigned flavor : 2;
public:
RValue() : value(nullptr), flavor(Scalar) {}
bool isScalar() const { return flavor == Scalar; }
bool isComplex() const { return flavor == Complex; }
bool isAggregate() const { return flavor == Aggregate; }
bool isVolatileQualified() const { return isVolatile; }
/// Return the value of this scalar value.
mlir::Value getValue() const {
assert(isScalar() && "Not a scalar!");
return value;
}
/// Return the value of this complex value.
mlir::Value getComplexValue() const {
assert(isComplex() && "Not a complex!");
return value;
}
/// Return the value of the address of the aggregate.
Address getAggregateAddress() const {
assert(isAggregate() && "Not an aggregate!");
return aggregateAddr;
}
mlir::Value getAggregatePointer(QualType pointeeType) const {
return getAggregateAddress().getPointer();
}
static RValue getIgnored() {
// FIXME: should we make this a more explicit state?
return get(nullptr);
}
static RValue get(mlir::Value v) {
RValue er;
er.value = v;
er.flavor = Scalar;
er.isVolatile = false;
return er;
}
static RValue getComplex(mlir::Value v) {
RValue er;
er.value = v;
er.flavor = Complex;
er.isVolatile = false;
return er;
}
// volatile or not. Remove default to find all places that probably get this
// wrong.
/// Convert an Address to an RValue. If the Address is not
/// signed, create an RValue using the unsigned address. Otherwise, resign the
/// address using the provided type.
static RValue getAggregate(Address addr, bool isVolatile = false) {
RValue er;
er.aggregateAddr = addr;
er.flavor = Aggregate;
er.isVolatile = isVolatile;
return er;
}
};
/// The source of the alignment of an l-value; an expression of
/// confidence in the alignment actually matching the estimate.
enum class AlignmentSource {
/// The l-value was an access to a declared entity or something
/// equivalently strong, like the address of an array allocated by a
/// language runtime.
Decl,
/// The l-value was considered opaque, so the alignment was
/// determined from a type, but that type was an explicitly-aligned
/// typedef.
AttributedType,
/// The l-value was considered opaque, so the alignment was
/// determined from a type.
Type
};
/// Given that the base address has the given alignment source, what's
/// our confidence in the alignment of the field?
static inline AlignmentSource getFieldAlignmentSource(AlignmentSource source) {
// For now, we don't distinguish fields of opaque pointers from
// top-level declarations, but maybe we should.
return AlignmentSource::Decl;
}
class LValueBaseInfo {
AlignmentSource alignSource;
public:
explicit LValueBaseInfo(AlignmentSource source = AlignmentSource::Type)
: alignSource(source) {}
AlignmentSource getAlignmentSource() const { return alignSource; }
void setAlignmentSource(AlignmentSource source) { alignSource = source; }
void mergeForCast(const LValueBaseInfo &info) {
setAlignmentSource(info.getAlignmentSource());
}
};
class LValue {
enum {
Simple, // This is a normal l-value, use getAddress().
VectorElt, // This is a vector element l-value (V[i]), use getVector*
BitField, // This is a bitfield l-value, use getBitfield*.
ExtVectorElt, // This is an extended vector subset, use getExtVectorComp
GlobalReg, // This is a register l-value, use getGlobalReg()
MatrixElt // This is a matrix element, use getVector*
} lvType;
clang::QualType type;
clang::Qualifiers quals;
// The alignment to use when accessing this lvalue. (For vector elements,
// this is the alignment of the whole vector)
unsigned alignment;
mlir::Value v;
mlir::Value vectorIdx; // Index for vector subscript
mlir::Type elementType;
LValueBaseInfo baseInfo;
const CIRGenBitFieldInfo *bitFieldInfo{nullptr};
void initialize(clang::QualType type, clang::Qualifiers quals,
clang::CharUnits alignment, LValueBaseInfo baseInfo) {
assert((!alignment.isZero() || type->isIncompleteType()) &&
"initializing l-value with zero alignment!");
this->type = type;
this->quals = quals;
const unsigned maxAlign = 1U << 31;
this->alignment = alignment.getQuantity() <= maxAlign
? alignment.getQuantity()
: maxAlign;
assert(this->alignment == alignment.getQuantity() &&
"Alignment exceeds allowed max!");
this->baseInfo = baseInfo;
}
public:
bool isSimple() const { return lvType == Simple; }
bool isVectorElt() const { return lvType == VectorElt; }
bool isBitField() const { return lvType == BitField; }
bool isVolatile() const { return quals.hasVolatile(); }
bool isVolatileQualified() const { return quals.hasVolatile(); }
unsigned getVRQualifiers() const {
return quals.getCVRQualifiers() & ~clang::Qualifiers::Const;
}
clang::QualType getType() const { return type; }
mlir::Value getPointer() const { return v; }
clang::CharUnits getAlignment() const {
return clang::CharUnits::fromQuantity(alignment);
}
void setAlignment(clang::CharUnits a) { alignment = a.getQuantity(); }
Address getAddress() const {
return Address(getPointer(), elementType, getAlignment());
}
const clang::Qualifiers &getQuals() const { return quals; }
clang::Qualifiers &getQuals() { return quals; }
LValueBaseInfo getBaseInfo() const { return baseInfo; }
void setBaseInfo(LValueBaseInfo info) { baseInfo = info; }
static LValue makeAddr(Address address, clang::QualType t,
LValueBaseInfo baseInfo) {
// Classic codegen sets the objc gc qualifier here. That requires an
// ASTContext, which is passed in from CIRGenFunction::makeAddrLValue.
assert(!cir::MissingFeatures::objCGC());
LValue r;
r.lvType = Simple;
r.v = address.getPointer();
r.elementType = address.getElementType();
r.initialize(t, t.getQualifiers(), address.getAlignment(), baseInfo);
return r;
}
Address getVectorAddress() const {
return Address(getVectorPointer(), elementType, getAlignment());
}
mlir::Value getVectorPointer() const {
assert(isVectorElt());
return v;
}
mlir::Value getVectorIdx() const {
assert(isVectorElt());
return vectorIdx;
}
static LValue makeVectorElt(Address vecAddress, mlir::Value index,
clang::QualType t, LValueBaseInfo baseInfo) {
LValue r;
r.lvType = VectorElt;
r.v = vecAddress.getPointer();
r.elementType = vecAddress.getElementType();
r.vectorIdx = index;
r.initialize(t, t.getQualifiers(), vecAddress.getAlignment(), baseInfo);
return r;
}
// bitfield lvalue
Address getBitFieldAddress() const {
return Address(getBitFieldPointer(), elementType, getAlignment());
}
mlir::Value getBitFieldPointer() const {
assert(isBitField());
return v;
}
const CIRGenBitFieldInfo &getBitFieldInfo() const {
assert(isBitField());
return *bitFieldInfo;
}
/// Create a new object to represent a bit-field access.
///
/// \param Addr - The base address of the bit-field sequence this
/// bit-field refers to.
/// \param Info - The information describing how to perform the bit-field
/// access.
static LValue makeBitfield(Address addr, const CIRGenBitFieldInfo &info,
clang::QualType type, LValueBaseInfo baseInfo) {
LValue r;
r.lvType = BitField;
r.v = addr.getPointer();
r.elementType = addr.getElementType();
r.bitFieldInfo = &info;
r.initialize(type, type.getQualifiers(), addr.getAlignment(), baseInfo);
return r;
}
};
/// An aggregate value slot.
class AggValueSlot {
Address addr;
clang::Qualifiers quals;
/// This is set to true if some external code is responsible for setting up a
/// destructor for the slot. Otherwise the code which constructs it should
/// push the appropriate cleanup.
LLVM_PREFERRED_TYPE(bool)
LLVM_ATTRIBUTE_UNUSED unsigned destructedFlag : 1;
/// This is set to true if the memory in the slot is known to be zero before
/// the assignment into it. This means that zero fields don't need to be set.
LLVM_PREFERRED_TYPE(bool)
unsigned zeroedFlag : 1;
/// This is set to true if the slot might be aliased and it's not undefined
/// behavior to access it through such an alias. Note that it's always
/// undefined behavior to access a C++ object that's under construction
/// through an alias derived from outside the construction process.
///
/// This flag controls whether calls that produce the aggregate
/// value may be evaluated directly into the slot, or whether they
/// must be evaluated into an unaliased temporary and then memcpy'ed
/// over. Since it's invalid in general to memcpy a non-POD C++
/// object, it's important that this flag never be set when
/// evaluating an expression which constructs such an object.
LLVM_PREFERRED_TYPE(bool)
LLVM_ATTRIBUTE_UNUSED unsigned aliasedFlag : 1;
/// This is set to true if the tail padding of this slot might overlap
/// another object that may have already been initialized (and whose
/// value must be preserved by this initialization). If so, we may only
/// store up to the dsize of the type. Otherwise we can widen stores to
/// the size of the type.
LLVM_PREFERRED_TYPE(bool)
LLVM_ATTRIBUTE_UNUSED unsigned overlapFlag : 1;
public:
enum IsDestructed_t { IsNotDestructed, IsDestructed };
enum IsZeroed_t { IsNotZeroed, IsZeroed };
enum IsAliased_t { IsNotAliased, IsAliased };
enum Overlap_t { MayOverlap, DoesNotOverlap };
/// Returns an aggregate value slot indicating that the aggregate
/// value is being ignored.
static AggValueSlot ignored() {
return forAddr(Address::invalid(), clang::Qualifiers(), IsNotDestructed,
IsNotAliased, DoesNotOverlap);
}
AggValueSlot(Address addr, clang::Qualifiers quals, bool destructedFlag,
bool zeroedFlag, bool aliasedFlag, bool overlapFlag)
: addr(addr), quals(quals), destructedFlag(destructedFlag),
zeroedFlag(zeroedFlag), aliasedFlag(aliasedFlag),
overlapFlag(overlapFlag) {}
static AggValueSlot forAddr(Address addr, clang::Qualifiers quals,
IsDestructed_t isDestructed,
IsAliased_t isAliased, Overlap_t mayOverlap,
IsZeroed_t isZeroed = IsNotZeroed) {
return AggValueSlot(addr, quals, isDestructed, isZeroed, isAliased,
mayOverlap);
}
static AggValueSlot forLValue(const LValue &LV, IsDestructed_t isDestructed,
IsAliased_t isAliased, Overlap_t mayOverlap,
IsZeroed_t isZeroed = IsNotZeroed) {
return forAddr(LV.getAddress(), LV.getQuals(), isDestructed, isAliased,
mayOverlap, isZeroed);
}
clang::Qualifiers getQualifiers() const { return quals; }
Address getAddress() const { return addr; }
bool isIgnored() const { return !addr.isValid(); }
mlir::Value getPointer() const { return addr.getPointer(); }
IsZeroed_t isZeroed() const { return IsZeroed_t(zeroedFlag); }
RValue asRValue() const {
if (isIgnored())
return RValue::getIgnored();
assert(!cir::MissingFeatures::aggValueSlot());
return RValue::getAggregate(getAddress());
}
};
} // namespace clang::CIRGen
#endif // CLANG_LIB_CIR_CIRGENVALUE_H
|