xref: /freebsd/contrib/llvm-project/clang/lib/CIR/CodeGen/CIRGenValue.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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