-
Notifications
You must be signed in to change notification settings - Fork 13.7k
[CIR] Upstream ArraySubscriptExpr for fixed size array #134536
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
81e1cd7
8d2acb1
e7d093b
e069e0e
ac0e8c3
33eff17
9d07a29
abd9621
bd7f0cc
fb439ca
e6fe258
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "CIRGenBuilder.h" | ||
|
||
using namespace clang::CIRGen; | ||
|
||
mlir::Value CIRGenBuilderTy::maybeBuildArrayDecay(mlir::Location loc, | ||
mlir::Value arrayPtr, | ||
mlir::Type eltTy) { | ||
const auto arrayPtrTy = mlir::cast<cir::PointerType>(arrayPtr.getType()); | ||
const auto arrayTy = mlir::dyn_cast<cir::ArrayType>(arrayPtrTy.getPointee()); | ||
|
||
if (arrayTy) { | ||
const cir::PointerType flatPtrTy = getPointerTo(arrayTy.getEltType()); | ||
return create<cir::CastOp>(loc, flatPtrTy, cir::CastKind::array_to_ptrdecay, | ||
arrayPtr); | ||
} | ||
|
||
assert(arrayPtrTy.getPointee() == eltTy && | ||
"flat pointee type must match original array element type"); | ||
return arrayPtr; | ||
} | ||
|
||
mlir::Value CIRGenBuilderTy::getArrayElement(mlir::Location arrayLocBegin, | ||
mlir::Location arrayLocEnd, | ||
mlir::Value arrayPtr, | ||
mlir::Type eltTy, mlir::Value idx, | ||
bool shouldDecay) { | ||
mlir::Value basePtr = arrayPtr; | ||
if (shouldDecay) | ||
basePtr = maybeBuildArrayDecay(arrayLocBegin, arrayPtr, eltTy); | ||
const mlir::Type flatPtrTy = basePtr.getType(); | ||
return create<cir::PtrStrideOp>(arrayLocEnd, flatPtrTy, basePtr, idx); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,7 @@ | |
|
||
#include "Address.h" | ||
#include "CIRGenFunction.h" | ||
#include "CIRGenModule.h" | ||
#include "CIRGenValue.h" | ||
#include "mlir/IR/BuiltinAttributes.h" | ||
#include "clang/AST/Attr.h" | ||
|
@@ -430,6 +431,143 @@ LValue CIRGenFunction::emitUnaryOpLValue(const UnaryOperator *e) { | |
llvm_unreachable("Unknown unary operator kind!"); | ||
} | ||
|
||
/// If the specified expr is a simple decay from an array to pointer, | ||
/// return the array subexpression. | ||
/// FIXME: this could be abstracted into a common AST helper. | ||
static const Expr *getSimpleArrayDecayOperand(const Expr *e) { | ||
// If this isn't just an array->pointer decay, bail out. | ||
const auto *castExpr = dyn_cast<CastExpr>(e); | ||
if (!castExpr || castExpr->getCastKind() != CK_ArrayToPointerDecay) | ||
return nullptr; | ||
|
||
// If this is a decay from variable width array, bail out. | ||
const Expr *subExpr = castExpr->getSubExpr(); | ||
if (subExpr->getType()->isVariableArrayType()) | ||
return nullptr; | ||
|
||
return subExpr; | ||
} | ||
|
||
static cir::IntAttr getConstantIndexOrNull(mlir::Value idx) { | ||
// TODO(cir): should we consider using MLIRs IndexType instead of IntegerAttr? | ||
if (auto constantOp = dyn_cast<cir::ConstantOp>(idx.getDefiningOp())) | ||
return mlir::dyn_cast<cir::IntAttr>(constantOp.getValue()); | ||
return {}; | ||
} | ||
|
||
static CharUnits getArrayElementAlign(CharUnits arrayAlign, mlir::Value idx, | ||
CharUnits eltSize) { | ||
// If we have a constant index, we can use the exact offset of the | ||
// element we're accessing. | ||
const cir::IntAttr constantIdx = getConstantIndexOrNull(idx); | ||
if (constantIdx) { | ||
const CharUnits offset = constantIdx.getValue().getZExtValue() * eltSize; | ||
return arrayAlign.alignmentAtOffset(offset); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we have a test case where this would return something different than There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am thinking for test case that can be used There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In order to find a test case for this, I modified the equivalent classic clang codegen implementation so that it would always go to the else case here. That caused 15 tests to fail, but we don't have enough support implemented to run any of the failing tests with CIR. There were 12 OpenMP failures, two PowerPC intrinsics, and one HLSL. |
||
} | ||
// Otherwise, use the worst-case alignment for any element. | ||
return arrayAlign.alignmentOfArrayElement(eltSize); | ||
} | ||
|
||
static QualType getFixedSizeElementType(const ASTContext &astContext, | ||
const VariableArrayType *vla) { | ||
QualType eltType; | ||
do { | ||
eltType = vla->getElementType(); | ||
} while ((vla = astContext.getAsVariableArrayType(eltType))); | ||
return eltType; | ||
} | ||
|
||
static mlir::Value emitArraySubscriptPtr(CIRGenFunction &cgf, | ||
mlir::Location beginLoc, | ||
mlir::Location endLoc, mlir::Value ptr, | ||
mlir::Type eltTy, mlir::Value idx, | ||
bool shouldDecay) { | ||
CIRGenModule &cgm = cgf.getCIRGenModule(); | ||
// TODO(cir): LLVM codegen emits in bound gep check here, is there anything | ||
// that would enhance tracking this later in CIR? | ||
assert(!cir::MissingFeatures::emitCheckedInBoundsGEP()); | ||
return cgm.getBuilder().getArrayElement(beginLoc, endLoc, ptr, eltTy, idx, | ||
shouldDecay); | ||
} | ||
|
||
static Address emitArraySubscriptPtr(CIRGenFunction &cgf, | ||
mlir::Location beginLoc, | ||
mlir::Location endLoc, Address addr, | ||
QualType eltType, mlir::Value idx, | ||
mlir::Location loc, bool shouldDecay) { | ||
|
||
// Determine the element size of the statically-sized base. This is | ||
// the thing that the indices are expressed in terms of. | ||
if (const VariableArrayType *vla = | ||
cgf.getContext().getAsVariableArrayType(eltType)) { | ||
eltType = getFixedSizeElementType(cgf.getContext(), vla); | ||
} | ||
|
||
// We can use that to compute the best alignment of the element. | ||
const CharUnits eltSize = cgf.getContext().getTypeSizeInChars(eltType); | ||
const CharUnits eltAlign = | ||
getArrayElementAlign(addr.getAlignment(), idx, eltSize); | ||
|
||
assert(!cir::MissingFeatures::preservedAccessIndexRegion()); | ||
const mlir::Value eltPtr = | ||
emitArraySubscriptPtr(cgf, beginLoc, endLoc, addr.getPointer(), | ||
addr.getElementType(), idx, shouldDecay); | ||
const mlir::Type elementType = cgf.convertTypeForMem(eltType); | ||
return Address(eltPtr, elementType, eltAlign); | ||
} | ||
|
||
LValue | ||
CIRGenFunction::emitArraySubscriptExpr(const clang::ArraySubscriptExpr *e) { | ||
if (e->getBase()->getType()->isVectorType() && | ||
!isa<ExtVectorElementExpr>(e->getBase())) { | ||
cgm.errorNYI(e->getSourceRange(), "emitArraySubscriptExpr: VectorType"); | ||
return LValue::makeAddr(Address::invalid(), e->getType(), LValueBaseInfo()); | ||
} | ||
|
||
if (isa<ExtVectorElementExpr>(e->getBase())) { | ||
cgm.errorNYI(e->getSourceRange(), | ||
"emitArraySubscriptExpr: ExtVectorElementExpr"); | ||
return LValue::makeAddr(Address::invalid(), e->getType(), LValueBaseInfo()); | ||
} | ||
|
||
if (getContext().getAsVariableArrayType(e->getType())) { | ||
cgm.errorNYI(e->getSourceRange(), | ||
"emitArraySubscriptExpr: VariableArrayType"); | ||
return LValue::makeAddr(Address::invalid(), e->getType(), LValueBaseInfo()); | ||
} | ||
|
||
if (e->getType()->getAs<ObjCObjectType>()) { | ||
cgm.errorNYI(e->getSourceRange(), "emitArraySubscriptExpr: ObjCObjectType"); | ||
return LValue::makeAddr(Address::invalid(), e->getType(), LValueBaseInfo()); | ||
} | ||
|
||
// The index must always be an integer, which is not an aggregate. Emit it | ||
// in lexical order (this complexity is, sadly, required by C++17). | ||
assert((e->getIdx() == e->getLHS() || e->getIdx() == e->getRHS()) && | ||
"index was neither LHS nor RHS"); | ||
const mlir::Value idx = emitScalarExpr(e->getIdx()); | ||
if (const Expr *array = getSimpleArrayDecayOperand(e->getBase())) { | ||
LValue arrayLV; | ||
if (const auto *ase = dyn_cast<ArraySubscriptExpr>(array)) | ||
arrayLV = emitArraySubscriptExpr(ase); | ||
else | ||
arrayLV = emitLValue(array); | ||
|
||
// Propagate the alignment from the array itself to the result. | ||
const Address addr = emitArraySubscriptPtr( | ||
*this, cgm.getLoc(array->getBeginLoc()), cgm.getLoc(array->getEndLoc()), | ||
arrayLV.getAddress(), e->getType(), idx, cgm.getLoc(e->getExprLoc()), | ||
/*shouldDecay=*/true); | ||
|
||
return LValue::makeAddr(addr, e->getType(), LValueBaseInfo()); | ||
} | ||
|
||
// The base must be a pointer; emit it with an estimate of its alignment. | ||
cgm.errorNYI(e->getSourceRange(), | ||
"emitArraySubscriptExpr: The base must be a pointer"); | ||
return {}; | ||
} | ||
|
||
LValue CIRGenFunction::emitBinaryOperatorLValue(const BinaryOperator *e) { | ||
// Comma expressions just emit their LHS then their RHS as an l-value. | ||
if (e->getOpcode() == BO_Comma) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this need an Assert/NYI/etc here? Seems like the purpose of MissingFeatures
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As far as I understand, it's internal to be nullptr, not a missing feature or implementation similar to Clang
llvm-project/clang/lib/CodeGen/CGExpr.cpp
Lines 4054 to 4068 in 783201b