|
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"
|
@@ -430,6 +431,143 @@ LValue CIRGenFunction::emitUnaryOpLValue(const UnaryOperator *e) {
|
430 | 431 | llvm_unreachable("Unknown unary operator kind!");
|
431 | 432 | }
|
432 | 433 |
|
| 434 | +/// If the specified expr is a simple decay from an array to pointer, |
| 435 | +/// return the array subexpression. |
| 436 | +/// FIXME: this could be abstracted into a common AST helper. |
| 437 | +static const Expr *getSimpleArrayDecayOperand(const Expr *e) { |
| 438 | + // If this isn't just an array->pointer decay, bail out. |
| 439 | + const auto *castExpr = dyn_cast<CastExpr>(e); |
| 440 | + if (!castExpr || castExpr->getCastKind() != CK_ArrayToPointerDecay) |
| 441 | + return nullptr; |
| 442 | + |
| 443 | + // If this is a decay from variable width array, bail out. |
| 444 | + const Expr *subExpr = castExpr->getSubExpr(); |
| 445 | + if (subExpr->getType()->isVariableArrayType()) |
| 446 | + return nullptr; |
| 447 | + |
| 448 | + return subExpr; |
| 449 | +} |
| 450 | + |
| 451 | +static cir::IntAttr getConstantIndexOrNull(mlir::Value idx) { |
| 452 | + // TODO(cir): should we consider using MLIRs IndexType instead of IntegerAttr? |
| 453 | + if (auto constantOp = dyn_cast<cir::ConstantOp>(idx.getDefiningOp())) |
| 454 | + return mlir::dyn_cast<cir::IntAttr>(constantOp.getValue()); |
| 455 | + return {}; |
| 456 | +} |
| 457 | + |
| 458 | +static CharUnits getArrayElementAlign(CharUnits arrayAlign, mlir::Value idx, |
| 459 | + CharUnits eltSize) { |
| 460 | + // If we have a constant index, we can use the exact offset of the |
| 461 | + // element we're accessing. |
| 462 | + const cir::IntAttr constantIdx = getConstantIndexOrNull(idx); |
| 463 | + if (constantIdx) { |
| 464 | + const CharUnits offset = constantIdx.getValue().getZExtValue() * eltSize; |
| 465 | + return arrayAlign.alignmentAtOffset(offset); |
| 466 | + } |
| 467 | + // Otherwise, use the worst-case alignment for any element. |
| 468 | + return arrayAlign.alignmentOfArrayElement(eltSize); |
| 469 | +} |
| 470 | + |
| 471 | +static QualType getFixedSizeElementType(const ASTContext &astContext, |
| 472 | + const VariableArrayType *vla) { |
| 473 | + QualType eltType; |
| 474 | + do { |
| 475 | + eltType = vla->getElementType(); |
| 476 | + } while ((vla = astContext.getAsVariableArrayType(eltType))); |
| 477 | + return eltType; |
| 478 | +} |
| 479 | + |
| 480 | +static mlir::Value emitArraySubscriptPtr(CIRGenFunction &cgf, |
| 481 | + mlir::Location beginLoc, |
| 482 | + mlir::Location endLoc, mlir::Value ptr, |
| 483 | + mlir::Type eltTy, mlir::Value idx, |
| 484 | + bool shouldDecay) { |
| 485 | + CIRGenModule &cgm = cgf.getCIRGenModule(); |
| 486 | + // TODO(cir): LLVM codegen emits in bound gep check here, is there anything |
| 487 | + // that would enhance tracking this later in CIR? |
| 488 | + assert(!cir::MissingFeatures::emitCheckedInBoundsGEP()); |
| 489 | + return cgm.getBuilder().getArrayElement(beginLoc, endLoc, ptr, eltTy, idx, |
| 490 | + shouldDecay); |
| 491 | +} |
| 492 | + |
| 493 | +static Address emitArraySubscriptPtr(CIRGenFunction &cgf, |
| 494 | + mlir::Location beginLoc, |
| 495 | + mlir::Location endLoc, Address addr, |
| 496 | + QualType eltType, mlir::Value idx, |
| 497 | + mlir::Location loc, bool shouldDecay) { |
| 498 | + |
| 499 | + // Determine the element size of the statically-sized base. This is |
| 500 | + // the thing that the indices are expressed in terms of. |
| 501 | + if (const VariableArrayType *vla = |
| 502 | + cgf.getContext().getAsVariableArrayType(eltType)) { |
| 503 | + eltType = getFixedSizeElementType(cgf.getContext(), vla); |
| 504 | + } |
| 505 | + |
| 506 | + // We can use that to compute the best alignment of the element. |
| 507 | + const CharUnits eltSize = cgf.getContext().getTypeSizeInChars(eltType); |
| 508 | + const CharUnits eltAlign = |
| 509 | + getArrayElementAlign(addr.getAlignment(), idx, eltSize); |
| 510 | + |
| 511 | + assert(!cir::MissingFeatures::preservedAccessIndexRegion()); |
| 512 | + const mlir::Value eltPtr = |
| 513 | + emitArraySubscriptPtr(cgf, beginLoc, endLoc, addr.getPointer(), |
| 514 | + addr.getElementType(), idx, shouldDecay); |
| 515 | + const mlir::Type elementType = cgf.convertTypeForMem(eltType); |
| 516 | + return Address(eltPtr, elementType, eltAlign); |
| 517 | +} |
| 518 | + |
| 519 | +LValue |
| 520 | +CIRGenFunction::emitArraySubscriptExpr(const clang::ArraySubscriptExpr *e) { |
| 521 | + if (e->getBase()->getType()->isVectorType() && |
| 522 | + !isa<ExtVectorElementExpr>(e->getBase())) { |
| 523 | + cgm.errorNYI(e->getSourceRange(), "emitArraySubscriptExpr: VectorType"); |
| 524 | + return LValue::makeAddr(Address::invalid(), e->getType(), LValueBaseInfo()); |
| 525 | + } |
| 526 | + |
| 527 | + if (isa<ExtVectorElementExpr>(e->getBase())) { |
| 528 | + cgm.errorNYI(e->getSourceRange(), |
| 529 | + "emitArraySubscriptExpr: ExtVectorElementExpr"); |
| 530 | + return LValue::makeAddr(Address::invalid(), e->getType(), LValueBaseInfo()); |
| 531 | + } |
| 532 | + |
| 533 | + if (getContext().getAsVariableArrayType(e->getType())) { |
| 534 | + cgm.errorNYI(e->getSourceRange(), |
| 535 | + "emitArraySubscriptExpr: VariableArrayType"); |
| 536 | + return LValue::makeAddr(Address::invalid(), e->getType(), LValueBaseInfo()); |
| 537 | + } |
| 538 | + |
| 539 | + if (e->getType()->getAs<ObjCObjectType>()) { |
| 540 | + cgm.errorNYI(e->getSourceRange(), "emitArraySubscriptExpr: ObjCObjectType"); |
| 541 | + return LValue::makeAddr(Address::invalid(), e->getType(), LValueBaseInfo()); |
| 542 | + } |
| 543 | + |
| 544 | + // The index must always be an integer, which is not an aggregate. Emit it |
| 545 | + // in lexical order (this complexity is, sadly, required by C++17). |
| 546 | + assert((e->getIdx() == e->getLHS() || e->getIdx() == e->getRHS()) && |
| 547 | + "index was neither LHS nor RHS"); |
| 548 | + const mlir::Value idx = emitScalarExpr(e->getIdx()); |
| 549 | + if (const Expr *array = getSimpleArrayDecayOperand(e->getBase())) { |
| 550 | + LValue arrayLV; |
| 551 | + if (const auto *ase = dyn_cast<ArraySubscriptExpr>(array)) |
| 552 | + arrayLV = emitArraySubscriptExpr(ase); |
| 553 | + else |
| 554 | + arrayLV = emitLValue(array); |
| 555 | + |
| 556 | + // Propagate the alignment from the array itself to the result. |
| 557 | + const Address addr = emitArraySubscriptPtr( |
| 558 | + *this, cgm.getLoc(array->getBeginLoc()), cgm.getLoc(array->getEndLoc()), |
| 559 | + arrayLV.getAddress(), e->getType(), idx, cgm.getLoc(e->getExprLoc()), |
| 560 | + /*shouldDecay=*/true); |
| 561 | + |
| 562 | + return LValue::makeAddr(addr, e->getType(), LValueBaseInfo()); |
| 563 | + } |
| 564 | + |
| 565 | + // The base must be a pointer; emit it with an estimate of its alignment. |
| 566 | + cgm.errorNYI(e->getSourceRange(), |
| 567 | + "emitArraySubscriptExpr: The base must be a pointer"); |
| 568 | + return {}; |
| 569 | +} |
| 570 | + |
433 | 571 | LValue CIRGenFunction::emitBinaryOperatorLValue(const BinaryOperator *e) {
|
434 | 572 | // Comma expressions just emit their LHS then their RHS as an l-value.
|
435 | 573 | if (e->getOpcode() == BO_Comma) {
|
|
0 commit comments