447 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8//9// These classes implement wrappers around mlir::Value in order to fully10// represent the range of values for C L- and R- values.11//12//===----------------------------------------------------------------------===//13 14#ifndef CLANG_LIB_CIR_CIRGENVALUE_H15#define CLANG_LIB_CIR_CIRGENVALUE_H16 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 27namespace clang::CIRGen {28 29/// This trivial value class is used to represent the result of an30/// expression that is evaluated. It can be one of three things: either a31/// simple MLIR SSA value, a pair of SSA values for complex numbers, or the32/// address of an aggregate value in memory.33class 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 46public:47 RValue() : value(nullptr), flavor(Scalar) {}48 49 bool isScalar() const { return flavor == Scalar; }50 bool isComplex() const { return flavor == Complex; }51 bool isAggregate() const { return flavor == Aggregate; }52 bool isIgnored() const { return isScalar() && !getValue(); }53 54 bool isVolatileQualified() const { return isVolatile; }55 56 /// Return the value of this scalar value.57 mlir::Value getValue() const {58 assert(isScalar() && "Not a scalar!");59 return value;60 }61 62 /// Return the value of this complex value.63 mlir::Value getComplexValue() const {64 assert(isComplex() && "Not a complex!");65 return value;66 }67 68 /// Return the value of the address of the aggregate.69 Address getAggregateAddress() const {70 assert(isAggregate() && "Not an aggregate!");71 return aggregateAddr;72 }73 74 mlir::Value getAggregatePointer(QualType pointeeType) const {75 return getAggregateAddress().getPointer();76 }77 78 static RValue getIgnored() {79 // FIXME: should we make this a more explicit state?80 return get(nullptr);81 }82 83 static RValue get(mlir::Value v) {84 RValue er;85 er.value = v;86 er.flavor = Scalar;87 er.isVolatile = false;88 return er;89 }90 91 static RValue getComplex(mlir::Value v) {92 RValue er;93 er.value = v;94 er.flavor = Complex;95 er.isVolatile = false;96 return er;97 }98 99 // volatile or not. Remove default to find all places that probably get this100 // wrong.101 102 /// Convert an Address to an RValue. If the Address is not103 /// signed, create an RValue using the unsigned address. Otherwise, resign the104 /// address using the provided type.105 static RValue getAggregate(Address addr, bool isVolatile = false) {106 RValue er;107 er.aggregateAddr = addr;108 er.flavor = Aggregate;109 er.isVolatile = isVolatile;110 return er;111 }112};113 114/// The source of the alignment of an l-value; an expression of115/// confidence in the alignment actually matching the estimate.116enum class AlignmentSource {117 /// The l-value was an access to a declared entity or something118 /// equivalently strong, like the address of an array allocated by a119 /// language runtime.120 Decl,121 122 /// The l-value was considered opaque, so the alignment was123 /// determined from a type, but that type was an explicitly-aligned124 /// typedef.125 AttributedType,126 127 /// The l-value was considered opaque, so the alignment was128 /// determined from a type.129 Type130};131 132/// Given that the base address has the given alignment source, what's133/// our confidence in the alignment of the field?134static inline AlignmentSource getFieldAlignmentSource(AlignmentSource source) {135 // For now, we don't distinguish fields of opaque pointers from136 // top-level declarations, but maybe we should.137 return AlignmentSource::Decl;138}139 140class LValueBaseInfo {141 AlignmentSource alignSource;142 143public:144 explicit LValueBaseInfo(AlignmentSource source = AlignmentSource::Type)145 : alignSource(source) {}146 AlignmentSource getAlignmentSource() const { return alignSource; }147 void setAlignmentSource(AlignmentSource source) { alignSource = source; }148 149 void mergeForCast(const LValueBaseInfo &info) {150 setAlignmentSource(info.getAlignmentSource());151 }152};153 154class LValue {155 enum {156 Simple, // This is a normal l-value, use getAddress().157 VectorElt, // This is a vector element l-value (V[i]), use getVector*158 BitField, // This is a bitfield l-value, use getBitfield*.159 ExtVectorElt, // This is an extended vector subset, use getExtVectorComp160 GlobalReg, // This is a register l-value, use getGlobalReg()161 MatrixElt // This is a matrix element, use getVector*162 } lvType;163 clang::QualType type;164 clang::Qualifiers quals;165 166 // The alignment to use when accessing this lvalue. (For vector elements,167 // this is the alignment of the whole vector)168 unsigned alignment;169 mlir::Value v;170 mlir::Value vectorIdx; // Index for vector subscript171 mlir::Attribute vectorElts; // ExtVector element subset: V.xyx172 mlir::Type elementType;173 LValueBaseInfo baseInfo;174 const CIRGenBitFieldInfo *bitFieldInfo{nullptr};175 176 void initialize(clang::QualType type, clang::Qualifiers quals,177 clang::CharUnits alignment, LValueBaseInfo baseInfo) {178 assert((!alignment.isZero() || type->isIncompleteType()) &&179 "initializing l-value with zero alignment!");180 this->type = type;181 this->quals = quals;182 const unsigned maxAlign = 1U << 31;183 this->alignment = alignment.getQuantity() <= maxAlign184 ? alignment.getQuantity()185 : maxAlign;186 assert(this->alignment == alignment.getQuantity() &&187 "Alignment exceeds allowed max!");188 this->baseInfo = baseInfo;189 }190 191public:192 bool isSimple() const { return lvType == Simple; }193 bool isVectorElt() const { return lvType == VectorElt; }194 bool isBitField() const { return lvType == BitField; }195 bool isExtVectorElt() const { return lvType == ExtVectorElt; }196 bool isGlobalReg() const { return lvType == GlobalReg; }197 bool isVolatile() const { return quals.hasVolatile(); }198 199 bool isVolatileQualified() const { return quals.hasVolatile(); }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(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 void setAddress(Address address) {219 assert(isSimple());220 v = address.getPointer();221 elementType = address.getElementType();222 alignment = address.getAlignment().getQuantity();223 assert(!cir::MissingFeatures::addressIsKnownNonNull());224 }225 226 const clang::Qualifiers &getQuals() const { return quals; }227 clang::Qualifiers &getQuals() { return quals; }228 229 LValueBaseInfo getBaseInfo() const { return baseInfo; }230 void setBaseInfo(LValueBaseInfo info) { baseInfo = info; }231 232 static LValue makeAddr(Address address, clang::QualType t,233 LValueBaseInfo baseInfo) {234 // Classic codegen sets the objc gc qualifier here. That requires an235 // ASTContext, which is passed in from CIRGenFunction::makeAddrLValue.236 assert(!cir::MissingFeatures::objCGC());237 238 LValue r;239 r.lvType = Simple;240 r.v = address.getPointer();241 r.elementType = address.getElementType();242 r.initialize(t, t.getQualifiers(), address.getAlignment(), baseInfo);243 return r;244 }245 246 Address getVectorAddress() const {247 return Address(getVectorPointer(), elementType, getAlignment());248 }249 250 mlir::Value getVectorPointer() const {251 assert(isVectorElt());252 return v;253 }254 255 mlir::Value getVectorIdx() const {256 assert(isVectorElt());257 return vectorIdx;258 }259 260 // extended vector elements.261 Address getExtVectorAddress() const {262 assert(isExtVectorElt());263 return Address(getExtVectorPointer(), elementType, getAlignment());264 }265 266 mlir::Value getExtVectorPointer() const {267 assert(isExtVectorElt());268 return v;269 }270 271 mlir::ArrayAttr getExtVectorElts() const {272 assert(isExtVectorElt());273 return mlir::cast<mlir::ArrayAttr>(vectorElts);274 }275 276 static LValue makeVectorElt(Address vecAddress, mlir::Value index,277 clang::QualType t, LValueBaseInfo baseInfo) {278 LValue r;279 r.lvType = VectorElt;280 r.v = vecAddress.getPointer();281 r.elementType = vecAddress.getElementType();282 r.vectorIdx = index;283 r.initialize(t, t.getQualifiers(), vecAddress.getAlignment(), baseInfo);284 return r;285 }286 287 static LValue makeExtVectorElt(Address vecAddress, mlir::ArrayAttr elts,288 clang::QualType type,289 LValueBaseInfo baseInfo) {290 LValue r;291 r.lvType = ExtVectorElt;292 r.v = vecAddress.getPointer();293 r.elementType = vecAddress.getElementType();294 r.vectorElts = elts;295 r.initialize(type, type.getQualifiers(), vecAddress.getAlignment(),296 baseInfo);297 return r;298 }299 300 // bitfield lvalue301 Address getBitFieldAddress() const {302 return Address(getBitFieldPointer(), elementType, getAlignment());303 }304 305 mlir::Value getBitFieldPointer() const {306 assert(isBitField());307 return v;308 }309 310 const CIRGenBitFieldInfo &getBitFieldInfo() const {311 assert(isBitField());312 return *bitFieldInfo;313 }314 315 /// Create a new object to represent a bit-field access.316 ///317 /// \param Addr - The base address of the bit-field sequence this318 /// bit-field refers to.319 /// \param Info - The information describing how to perform the bit-field320 /// access.321 static LValue makeBitfield(Address addr, const CIRGenBitFieldInfo &info,322 clang::QualType type, LValueBaseInfo baseInfo) {323 LValue r;324 r.lvType = BitField;325 r.v = addr.getPointer();326 r.elementType = addr.getElementType();327 r.bitFieldInfo = &info;328 r.initialize(type, type.getQualifiers(), addr.getAlignment(), baseInfo);329 return r;330 }331};332 333/// An aggregate value slot.334class AggValueSlot {335 336 Address addr;337 clang::Qualifiers quals;338 339 /// This is set to true if some external code is responsible for setting up a340 /// destructor for the slot. Otherwise the code which constructs it should341 /// push the appropriate cleanup.342 [[maybe_unused]]343 LLVM_PREFERRED_TYPE(bool) unsigned destructedFlag : 1;344 345 /// This is set to true if the memory in the slot is known to be zero before346 /// the assignment into it. This means that zero fields don't need to be set.347 LLVM_PREFERRED_TYPE(bool)348 unsigned zeroedFlag : 1;349 350 /// This is set to true if the slot might be aliased and it's not undefined351 /// behavior to access it through such an alias. Note that it's always352 /// undefined behavior to access a C++ object that's under construction353 /// through an alias derived from outside the construction process.354 ///355 /// This flag controls whether calls that produce the aggregate356 /// value may be evaluated directly into the slot, or whether they357 /// must be evaluated into an unaliased temporary and then memcpy'ed358 /// over. Since it's invalid in general to memcpy a non-POD C++359 /// object, it's important that this flag never be set when360 /// evaluating an expression which constructs such an object.361 [[maybe_unused]]362 LLVM_PREFERRED_TYPE(bool) unsigned aliasedFlag : 1;363 364 /// This is set to true if the tail padding of this slot might overlap365 /// another object that may have already been initialized (and whose366 /// value must be preserved by this initialization). If so, we may only367 /// store up to the dsize of the type. Otherwise we can widen stores to368 /// the size of the type.369 [[maybe_unused]]370 LLVM_PREFERRED_TYPE(bool) unsigned overlapFlag : 1;371 372public:373 enum IsDestructed_t { IsNotDestructed, IsDestructed };374 enum IsZeroed_t { IsNotZeroed, IsZeroed };375 enum IsAliased_t { IsNotAliased, IsAliased };376 enum Overlap_t { MayOverlap, DoesNotOverlap };377 378 /// Returns an aggregate value slot indicating that the aggregate379 /// value is being ignored.380 static AggValueSlot ignored() {381 return forAddr(Address::invalid(), clang::Qualifiers(), IsNotDestructed,382 IsNotAliased, DoesNotOverlap);383 }384 385 AggValueSlot(Address addr, clang::Qualifiers quals, bool destructedFlag,386 bool zeroedFlag, bool aliasedFlag, bool overlapFlag)387 : addr(addr), quals(quals), destructedFlag(destructedFlag),388 zeroedFlag(zeroedFlag), aliasedFlag(aliasedFlag),389 overlapFlag(overlapFlag) {}390 391 static AggValueSlot forAddr(Address addr, clang::Qualifiers quals,392 IsDestructed_t isDestructed,393 IsAliased_t isAliased, Overlap_t mayOverlap,394 IsZeroed_t isZeroed = IsNotZeroed) {395 return AggValueSlot(addr, quals, isDestructed, isZeroed, isAliased,396 mayOverlap);397 }398 399 static AggValueSlot forLValue(const LValue &LV, IsDestructed_t isDestructed,400 IsAliased_t isAliased, Overlap_t mayOverlap,401 IsZeroed_t isZeroed = IsNotZeroed) {402 return forAddr(LV.getAddress(), LV.getQuals(), isDestructed, isAliased,403 mayOverlap, isZeroed);404 }405 406 IsDestructed_t isExternallyDestructed() const {407 return IsDestructed_t(destructedFlag);408 }409 void setExternallyDestructed(bool destructed = true) {410 destructedFlag = destructed;411 }412 413 clang::Qualifiers getQualifiers() const { return quals; }414 415 bool isVolatile() const { return quals.hasVolatile(); }416 417 void setVolatile(bool flag) {418 if (flag)419 quals.addVolatile();420 else421 quals.removeVolatile();422 }423 424 Address getAddress() const { return addr; }425 426 bool isIgnored() const { return !addr.isValid(); }427 428 mlir::Value getPointer() const { return addr.getPointer(); }429 430 Overlap_t mayOverlap() const { return Overlap_t(overlapFlag); }431 432 IsZeroed_t isZeroed() const { return IsZeroed_t(zeroedFlag); }433 434 IsAliased_t isPotentiallyAliased() const { return IsAliased_t(aliasedFlag); }435 436 RValue asRValue() const {437 if (isIgnored())438 return RValue::getIgnored();439 assert(!cir::MissingFeatures::aggValueSlot());440 return RValue::getAggregate(getAddress());441 }442};443 444} // namespace clang::CIRGen445 446#endif // CLANG_LIB_CIR_CIRGENVALUE_H447