|
12 | 12 |
|
13 | 13 | #include "Address.h"
|
14 | 14 | #include "CIRGenFunction.h"
|
| 15 | +#include "CIRGenModule.h" |
15 | 16 | #include "CIRGenValue.h"
|
16 | 17 | #include "mlir/IR/BuiltinAttributes.h"
|
17 | 18 | #include "clang/AST/Attr.h"
|
@@ -232,6 +233,161 @@ LValue CIRGenFunction::emitUnaryOpLValue(const UnaryOperator *e) {
|
232 | 233 | llvm_unreachable("Unknown unary operator kind!");
|
233 | 234 | }
|
234 | 235 |
|
| 236 | +/// If the specified expr is a simple decay from an array to pointer, |
| 237 | +/// return the array subexpression. |
| 238 | +/// FIXME: this could be abstracted into a commeon AST helper. |
| 239 | +static const Expr *isSimpleArrayDecayOperand(const Expr *e) { |
| 240 | + // If this isn't just an array->pointer decay, bail out. |
| 241 | + const auto *castExpr = dyn_cast<CastExpr>(e); |
| 242 | + if (!castExpr || castExpr->getCastKind() != CK_ArrayToPointerDecay) |
| 243 | + return nullptr; |
| 244 | + |
| 245 | + // If this is a decay from variable width array, bail out. |
| 246 | + const Expr *subExpr = castExpr->getSubExpr(); |
| 247 | + if (subExpr->getType()->isVariableArrayType()) |
| 248 | + return nullptr; |
| 249 | + |
| 250 | + return subExpr; |
| 251 | +} |
| 252 | + |
| 253 | +static mlir::IntegerAttr getConstantIndexOrNull(mlir::Value idx) { |
| 254 | + // TODO(cir): should we consider using MLIRs IndexType instead of IntegerAttr? |
| 255 | + if (auto constantOp = dyn_cast<cir::ConstantOp>(idx.getDefiningOp())) |
| 256 | + return mlir::dyn_cast<mlir::IntegerAttr>(constantOp.getValue()); |
| 257 | + return {}; |
| 258 | +} |
| 259 | + |
| 260 | +static CharUnits getArrayElementAlign(CharUnits arrayAlign, mlir::Value idx, |
| 261 | + CharUnits eltSize) { |
| 262 | + // If we have a constant index, we can use the exact offset of the |
| 263 | + // element we're accessing. |
| 264 | + const mlir::IntegerAttr constantIdx = getConstantIndexOrNull(idx); |
| 265 | + if (constantIdx) { |
| 266 | + const CharUnits offset = constantIdx.getValue().getZExtValue() * eltSize; |
| 267 | + return arrayAlign.alignmentAtOffset(offset); |
| 268 | + } |
| 269 | + // Otherwise, use the worst-case alignment for any element. |
| 270 | + return arrayAlign.alignmentOfArrayElement(eltSize); |
| 271 | +} |
| 272 | + |
| 273 | +static QualType getFixedSizeElementType(const ASTContext &astContext, |
| 274 | + const VariableArrayType *vla) { |
| 275 | + QualType eltType; |
| 276 | + do { |
| 277 | + eltType = vla->getElementType(); |
| 278 | + } while ((vla = astContext.getAsVariableArrayType(eltType))); |
| 279 | + return eltType; |
| 280 | +} |
| 281 | + |
| 282 | +static mlir::Value |
| 283 | +emitArraySubscriptPtr(CIRGenFunction &cgf, mlir::Location beginLoc, |
| 284 | + mlir::Location endLoc, mlir::Value ptr, mlir::Type eltTy, |
| 285 | + ArrayRef<mlir::Value> indices, bool inbounds, |
| 286 | + bool signedIndices, bool shouldDecay, |
| 287 | + const llvm::Twine &name = "arrayidx") { |
| 288 | + if (indices.size() > 1) { |
| 289 | + cgf.cgm.errorNYI("emitArraySubscriptPtr: handle multiple indices"); |
| 290 | + return {}; |
| 291 | + } |
| 292 | + |
| 293 | + const mlir::Value idx = indices.back(); |
| 294 | + CIRGenModule &cgm = cgf.getCIRGenModule(); |
| 295 | + // TODO(cir): LLVM codegen emits in bound gep check here, is there anything |
| 296 | + // that would enhance tracking this later in CIR? |
| 297 | + if (inbounds) |
| 298 | + assert(!cir::MissingFeatures::emitCheckedInBoundsGEP() && "NYI"); |
| 299 | + return cgm.getBuilder().getArrayElement(beginLoc, endLoc, ptr, eltTy, idx, |
| 300 | + shouldDecay); |
| 301 | +} |
| 302 | + |
| 303 | +static Address emitArraySubscriptPtr( |
| 304 | + CIRGenFunction &cgf, mlir::Location beginLoc, mlir::Location endLoc, |
| 305 | + Address addr, ArrayRef<mlir::Value> indices, QualType eltType, |
| 306 | + bool inbounds, bool signedIndices, mlir::Location loc, bool shouldDecay, |
| 307 | + QualType *arrayType = nullptr, const Expr *base = nullptr, |
| 308 | + const llvm::Twine &name = "arrayidx") { |
| 309 | + |
| 310 | + // Determine the element size of the statically-sized base. This is |
| 311 | + // the thing that the indices are expressed in terms of. |
| 312 | + if (const VariableArrayType *vla = |
| 313 | + cgf.getContext().getAsVariableArrayType(eltType)) { |
| 314 | + eltType = getFixedSizeElementType(cgf.getContext(), vla); |
| 315 | + } |
| 316 | + |
| 317 | + // We can use that to compute the best alignment of the element. |
| 318 | + const CharUnits eltSize = cgf.getContext().getTypeSizeInChars(eltType); |
| 319 | + const CharUnits eltAlign = |
| 320 | + getArrayElementAlign(addr.getAlignment(), indices.back(), eltSize); |
| 321 | + |
| 322 | + mlir::Value eltPtr; |
| 323 | + const mlir::IntegerAttr lastIndex = getConstantIndexOrNull(indices.back()); |
| 324 | + if (!lastIndex) { |
| 325 | + eltPtr = emitArraySubscriptPtr(cgf, beginLoc, endLoc, addr.getPointer(), |
| 326 | + addr.getElementType(), indices, inbounds, |
| 327 | + signedIndices, shouldDecay, name); |
| 328 | + } |
| 329 | + const mlir::Type elementType = cgf.convertTypeForMem(eltType); |
| 330 | + return Address(eltPtr, elementType, eltAlign); |
| 331 | +} |
| 332 | + |
| 333 | +LValue |
| 334 | +CIRGenFunction::emitArraySubscriptExpr(const clang::ArraySubscriptExpr *e) { |
| 335 | + if (e->getBase()->getType()->isVectorType() && |
| 336 | + !isa<ExtVectorElementExpr>(e->getBase())) { |
| 337 | + cgm.errorNYI(e->getSourceRange(), "emitArraySubscriptExpr: VectorType"); |
| 338 | + return {}; |
| 339 | + } |
| 340 | + |
| 341 | + if (isa<ExtVectorElementExpr>(e->getBase())) { |
| 342 | + cgm.errorNYI(e->getSourceRange(), |
| 343 | + "emitArraySubscriptExpr: ExtVectorElementExpr"); |
| 344 | + return {}; |
| 345 | + } |
| 346 | + |
| 347 | + if (getContext().getAsVariableArrayType(e->getType())) { |
| 348 | + cgm.errorNYI(e->getSourceRange(), |
| 349 | + "emitArraySubscriptExpr: VariableArrayType"); |
| 350 | + return {}; |
| 351 | + } |
| 352 | + |
| 353 | + if (e->getType()->getAs<ObjCObjectType>()) { |
| 354 | + cgm.errorNYI(e->getSourceRange(), "emitArraySubscriptExpr: ObjCObjectType"); |
| 355 | + return {}; |
| 356 | + } |
| 357 | + |
| 358 | + // The index must always be an integer, which is not an aggregate. Emit it |
| 359 | + // in lexical order (this complexity is, sadly, required by C++17). |
| 360 | + assert((e->getIdx() == e->getLHS() || e->getIdx() == e->getRHS()) && |
| 361 | + "index was neither LHS nor RHS"); |
| 362 | + const mlir::Value idx = emitScalarExpr(e->getIdx()); |
| 363 | + const QualType idxTy = e->getIdx()->getType(); |
| 364 | + const bool signedIndices = idxTy->isSignedIntegerOrEnumerationType(); |
| 365 | + |
| 366 | + if (const Expr *array = isSimpleArrayDecayOperand(e->getBase())) { |
| 367 | + LValue arrayLV; |
| 368 | + if (const auto *ase = dyn_cast<ArraySubscriptExpr>(array)) |
| 369 | + arrayLV = emitArraySubscriptExpr(ase); |
| 370 | + else |
| 371 | + arrayLV = emitLValue(array); |
| 372 | + |
| 373 | + // Propagate the alignment from the array itself to the result. |
| 374 | + QualType arrayType = array->getType(); |
| 375 | + const Address addr = emitArraySubscriptPtr( |
| 376 | + *this, cgm.getLoc(array->getBeginLoc()), cgm.getLoc(array->getEndLoc()), |
| 377 | + arrayLV.getAddress(), {idx}, e->getType(), |
| 378 | + !getLangOpts().isSignedOverflowDefined(), signedIndices, |
| 379 | + cgm.getLoc(e->getExprLoc()), /*shouldDecay=*/true, &arrayType, |
| 380 | + e->getBase()); |
| 381 | + |
| 382 | + return LValue::makeAddr(addr, e->getType()); |
| 383 | + } |
| 384 | + |
| 385 | + // The base must be a pointer; emit it with an estimate of its alignment. |
| 386 | + cgm.errorNYI(e->getSourceRange(), |
| 387 | + "emitArraySubscriptExpr: The base must be a pointer"); |
| 388 | + return {}; |
| 389 | +} |
| 390 | + |
235 | 391 | LValue CIRGenFunction::emitBinaryOperatorLValue(const BinaryOperator *e) {
|
236 | 392 | // Comma expressions just emit their LHS then their RHS as an l-value.
|
237 | 393 | if (e->getOpcode() == BO_Comma) {
|
|
0 commit comments