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
26namespace 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.
32class 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
49public:
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.
120enum 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?
138static 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
144class LValueBaseInfo {
145 AlignmentSource alignSource;
146
147public:
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
158class 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
193public:
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.
265class 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
274public:
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

source code of clang/lib/CIR/CodeGen/CIRGenValue.h