Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,14 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
return createGlobal(module, loc, uniqueName, type, isConstant, linkage);
}

cir::StackSaveOp createStackSave(mlir::Location loc, mlir::Type ty) {
return cir::StackSaveOp::create(*this, loc, ty);
}

cir::StackRestoreOp createStackRestore(mlir::Location loc, mlir::Value v) {
return cir::StackRestoreOp::create(*this, loc, v);
}

mlir::Value createSetBitfield(mlir::Location loc, mlir::Type resultType,
Address dstAddr, mlir::Type storageType,
mlir::Value src, const CIRGenBitFieldInfo &info,
Expand Down
98 changes: 72 additions & 26 deletions clang/lib/CIR/CodeGen/CIRGenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,38 +44,70 @@ CIRGenFunction::emitAutoVarAlloca(const VarDecl &d,

// If the type is variably-modified, emit all the VLA sizes for it.
if (ty->isVariablyModifiedType())
cgm.errorNYI(d.getSourceRange(), "emitAutoVarDecl: variably modified type");
emitVariablyModifiedType(ty);

assert(!cir::MissingFeatures::openMP());

Address address = Address::invalid();
if (!ty->isConstantSizeType())
cgm.errorNYI(d.getSourceRange(), "emitAutoVarDecl: non-constant size type");

// A normal fixed sized variable becomes an alloca in the entry block,
// unless:
// - it's an NRVO variable.
// - we are compiling OpenMP and it's an OpenMP local variable.
if (nrvo) {
// The named return value optimization: allocate this variable in the
// return slot, so that we can elide the copy when returning this
// variable (C++0x [class.copy]p34).
address = returnValue;

if (const RecordDecl *rd = ty->getAsRecordDecl()) {
if (const auto *cxxrd = dyn_cast<CXXRecordDecl>(rd);
(cxxrd && !cxxrd->hasTrivialDestructor()) ||
rd->isNonTrivialToPrimitiveDestroy())
cgm.errorNYI(d.getSourceRange(), "emitAutoVarAlloca: set NRVO flag");
if (ty->isConstantSizeType()) {
// A normal fixed sized variable becomes an alloca in the entry block,
// unless:
// - it's an NRVO variable.
// - we are compiling OpenMP and it's an OpenMP local variable.
if (nrvo) {
// The named return value optimization: allocate this variable in the
// return slot, so that we can elide the copy when returning this
// variable (C++0x [class.copy]p34).
address = returnValue;

if (const RecordDecl *rd = ty->getAsRecordDecl()) {
if (const auto *cxxrd = dyn_cast<CXXRecordDecl>(rd);
(cxxrd && !cxxrd->hasTrivialDestructor()) ||
rd->isNonTrivialToPrimitiveDestroy())
cgm.errorNYI(d.getSourceRange(), "emitAutoVarAlloca: set NRVO flag");
}
} else {
// A normal fixed sized variable becomes an alloca in the entry block,
mlir::Type allocaTy = convertTypeForMem(ty);
// Create the temp alloca and declare variable using it.
address = createTempAlloca(allocaTy, alignment, loc, d.getName(),
/*arraySize=*/nullptr, /*alloca=*/nullptr, ip);
declare(address.getPointer(), &d, ty, getLoc(d.getSourceRange()),
alignment);
}
} else {
// A normal fixed sized variable becomes an alloca in the entry block,
mlir::Type allocaTy = convertTypeForMem(ty);
// Create the temp alloca and declare variable using it.
address = createTempAlloca(allocaTy, alignment, loc, d.getName(),
/*arraySize=*/nullptr, /*alloca=*/nullptr, ip);
declare(address.getPointer(), &d, ty, getLoc(d.getSourceRange()),
alignment);
// Non-constant size type
assert(!cir::MissingFeatures::openMP());
if (!didCallStackSave) {
// Save the stack.
auto defaultTy = AllocaInt8PtrTy;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
auto defaultTy = AllocaInt8PtrTy;
cir::PointerType defaultTy = AllocaInt8PtrTy;

CharUnits align = CharUnits::fromQuantity(
cgm.getDataLayout().getAlignment(defaultTy, false));
Address stack = createTempAlloca(defaultTy, align, loc, "saved_stack");

mlir::Value v = builder.createStackSave(loc, defaultTy);
assert(v.getType() == AllocaInt8PtrTy);
builder.createStore(loc, v, stack);

didCallStackSave = true;

// Push a cleanup block and restore the stack there.
// FIXME: in general circumstances, this should be an EH cleanup.
pushStackRestore(NormalCleanup, stack);
}

auto vlaSize = getVLASize(ty);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
auto vlaSize = getVLASize(ty);
VlaSizePair vlaSize = getVLASize(ty);

mlir::Type memTy = convertTypeForMem(vlaSize.type);

// Allocate memory for the array.
address =
createTempAlloca(memTy, alignment, loc, d.getName(), vlaSize.numElts,
/*alloca=*/nullptr, builder.saveInsertionPoint());

// If we have debug info enabled, properly describe the VLA dimensions for
// this type by registering the vla size expression for each of the
// dimensions.
assert(!cir::MissingFeatures::generateDebugInfo());
}

emission.addr = address;
Expand Down Expand Up @@ -696,6 +728,16 @@ struct DestroyObject final : EHScopeStack::Cleanup {
cgf.emitDestroy(addr, type, destroyer);
}
};

struct CallStackRestore final : EHScopeStack::Cleanup {
Address stack;
CallStackRestore(Address stack) : stack(stack) {}
void emit(CIRGenFunction &cgf) override {
auto loc = stack.getPointer().getLoc();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
auto loc = stack.getPointer().getLoc();
mlir::Location loc = stack.getPointer().getLoc();

mlir::Value v = cgf.getBuilder().createLoad(loc, stack);
cgf.getBuilder().createStackRestore(loc, v);
}
};
} // namespace

void CIRGenFunction::pushDestroy(CleanupKind cleanupKind, Address addr,
Expand Down Expand Up @@ -805,6 +847,10 @@ CIRGenFunction::getDestroyer(QualType::DestructionKind kind) {
llvm_unreachable("Unknown DestructionKind");
}

void CIRGenFunction::pushStackRestore(CleanupKind kind, Address spMem) {
ehStack.pushCleanup<CallStackRestore>(kind, spMem);
}

/// Enter a destroy cleanup for the given local variable.
void CIRGenFunction::emitAutoVarTypeCleanup(
const CIRGenFunction::AutoVarEmission &emission,
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/CIR/CodeGen/CIRGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2068,7 +2068,7 @@ mlir::Value CIRGenFunction::emitAlloca(StringRef name, mlir::Type ty,
mlir::OpBuilder::InsertionGuard guard(builder);
builder.restoreInsertionPoint(ip);
addr = builder.createAlloca(loc, /*addr type*/ localVarPtrTy,
/*var type*/ ty, name, alignIntAttr);
/*var type*/ ty, name, alignIntAttr, arraySize);
assert(!cir::MissingFeatures::astVarDeclInterface());
}
return addr;
Expand Down
58 changes: 57 additions & 1 deletion clang/lib/CIR/CodeGen/CIRGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,8 @@ void CIRGenFunction::startFunction(GlobalDecl gd, QualType returnType,
curFn = fn;

const Decl *d = gd.getDecl();

didCallStackSave = false;
curCodeDecl = d;
const auto *fd = dyn_cast_or_null<FunctionDecl>(d);
curFuncDecl = d->getNonClosureContext();
Expand Down Expand Up @@ -1006,6 +1008,41 @@ mlir::Value CIRGenFunction::emitAlignmentAssumption(
offsetValue);
}

CIRGenFunction::VlaSizePair CIRGenFunction::getVLASize(QualType type) {
const VariableArrayType *vla =
cgm.getASTContext().getAsVariableArrayType(type);
assert(vla && "type was not a variable array type!");
return getVLASize(vla);
}

CIRGenFunction::VlaSizePair
CIRGenFunction::getVLASize(const VariableArrayType *type) {
// The number of elements so far; always size_t.
mlir::Value numElements;

QualType elementType;
do {
elementType = type->getElementType();
mlir::Value vlaSize = vlaSizeMap[type->getSizeExpr()];
assert(vlaSize && "no size for VLA!");
assert(vlaSize.getType() == SizeTy);

if (!numElements) {
numElements = vlaSize;
} else {
// It's undefined behavior if this wraps around, so mark it that way.
// FIXME: Teach -fsanitize=undefined to trap this.

numElements =
builder.createMul(numElements.getLoc(), numElements, vlaSize,
cir::OverflowBehavior::NoUnsignedWrap);
}
} while ((type = getContext().getAsVariableArrayType(elementType)));

assert(numElements && "Undefined elements number");
return {numElements, elementType};
}

// TODO(cir): Most of this function can be shared between CIRGen
// and traditional LLVM codegen
void CIRGenFunction::emitVariablyModifiedType(QualType type) {
Expand Down Expand Up @@ -1086,7 +1123,26 @@ void CIRGenFunction::emitVariablyModifiedType(QualType type) {
break;

case Type::VariableArray: {
cgm.errorNYI("CIRGenFunction::emitVariablyModifiedType VLA");
// Losing element qualification here is fine.
const VariableArrayType *vat = cast<clang::VariableArrayType>(ty);

// Unknown size indication requires no size computation.
// Otherwise, evaluate and record it.
if (const Expr *sizeExpr = vat->getSizeExpr()) {
// It's possible that we might have emitted this already,
// e.g. with a typedef and a pointer to it.
mlir::Value &entry = vlaSizeMap[sizeExpr];
if (!entry) {
mlir::Value size = emitScalarExpr(sizeExpr);
assert(!cir::MissingFeatures::sanitizers());

// Always zexting here would be wrong if it weren't
// undefined behavior to have a negative bound.
// FIXME: What about when size's type is larger than size_t?
entry = builder.createIntCast(size, SizeTy);
}
}
type = vat->getElementType();
break;
}

Expand Down
32 changes: 32 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,10 @@ class CIRGenFunction : public CIRGenTypeCache {
using SymTableTy = llvm::ScopedHashTable<const clang::Decl *, mlir::Value>;
SymTableTy symbolTable;

/// Whether a cir.stacksave operation has been added. Used to avoid
/// inserting cir.stacksave for multiple VLAs in the same scope.
bool didCallStackSave = false;

/// Whether or not a Microsoft-style asm block has been processed within
/// this fuction. These can potentially set the return value.
bool sawAsmBlock = false;
Expand Down Expand Up @@ -188,6 +192,14 @@ class CIRGenFunction : public CIRGenTypeCache {
llvm::DenseMap<const OpaqueValueExpr *, LValue> opaqueLValues;
llvm::DenseMap<const OpaqueValueExpr *, RValue> opaqueRValues;

// This keeps track of the associated size for each VLA type.
// We track this by the size expression rather than the type itself because
// in certain situations, like a const qualifier applied to an VLA typedef,
// multiple VLA types can share the same size expression.
// FIXME: Maybe this could be a stack of maps that is pushed/popped as we
// enter/leave scopes.
llvm::DenseMap<const Expr *, mlir::Value> vlaSizeMap;

public:
/// A non-RAII class containing all the information about a bound
/// opaque value. OpaqueValueMapping, below, is a RAII wrapper for
Expand Down Expand Up @@ -436,6 +448,20 @@ class CIRGenFunction : public CIRGenTypeCache {
}
};

struct VlaSizePair {
mlir::Value numElts;
QualType type;

VlaSizePair(mlir::Value num, QualType ty) : numElts(num), type(ty) {}
};

/// Returns an MLIR::Value+QualType pair that corresponds to the size,
/// in non-variably-sized elements, of a variable length array type,
/// plus that largest non-variably-sized element type. Assumes that
/// the type has already been emitted with emitVariablyModifiedType.
VlaSizePair getVLASize(const VariableArrayType *type);
VlaSizePair getVLASize(QualType type);

void finishFunction(SourceLocation endLoc);

/// Determine whether the given initializer is trivial in the sense
Expand Down Expand Up @@ -583,6 +609,8 @@ class CIRGenFunction : public CIRGenTypeCache {
return needsEHCleanup(kind) ? NormalAndEHCleanup : NormalCleanup;
}

void pushStackRestore(CleanupKind kind, Address spMem);

/// Set the address of a local variable.
void setAddrOfLocalVar(const clang::VarDecl *vd, Address addr) {
assert(!localDeclMap.count(vd) && "Decl already exists in LocalDeclMap!");
Expand Down Expand Up @@ -854,6 +882,7 @@ class CIRGenFunction : public CIRGenTypeCache {

protected:
bool performCleanup;
bool oldDidCallStackSave;

private:
RunCleanupsScope(const RunCleanupsScope &) = delete;
Expand All @@ -867,6 +896,8 @@ class CIRGenFunction : public CIRGenTypeCache {
explicit RunCleanupsScope(CIRGenFunction &cgf)
: performCleanup(true), cgf(cgf) {
cleanupStackDepth = cgf.ehStack.stable_begin();
oldDidCallStackSave = cgf.didCallStackSave;
cgf.didCallStackSave = false;
oldCleanupStackDepth = cgf.currentCleanupStackDepth;
cgf.currentCleanupStackDepth = cleanupStackDepth;
}
Expand All @@ -883,6 +914,7 @@ class CIRGenFunction : public CIRGenTypeCache {
assert(performCleanup && "Already forced cleanup");
{
mlir::OpBuilder::InsertionGuard guard(cgf.getBuilder());
cgf.didCallStackSave = oldDidCallStackSave;
cgf.popCleanupBlocks(cleanupStackDepth);
performCleanup = false;
cgf.currentCleanupStackDepth = oldCleanupStackDepth;
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ CIRGenModule::CIRGenModule(mlir::MLIRContext &mlirContext,
FP80Ty = cir::FP80Type::get(&getMLIRContext());
FP128Ty = cir::FP128Type::get(&getMLIRContext());

AllocaInt8PtrTy = cir::PointerType::get(UInt8Ty, cirAllocaAddressSpace);

PointerAlignInBytes =
astContext
.toCharUnitsFromBits(
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenTypeCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ struct CIRGenTypeCache {
cir::PointerType VoidPtrTy;
cir::PointerType UInt8PtrTy;

/// void* in alloca address space
cir::PointerType AllocaInt8PtrTy;

/// The size and alignment of a pointer into the generic address space.
union {
unsigned char PointerAlignInBytes;
Expand Down
10 changes: 10 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,16 @@ mlir::Type CIRGenTypes::convertType(QualType type) {
break;
}

case Type::VariableArray: {
const VariableArrayType *a = cast<VariableArrayType>(ty);
if (a->getIndexTypeCVRQualifiers() != 0)
cgm.errorNYI(SourceLocation(), "non trivial array types", type);
// VLAs resolve to the innermost element type; this matches
// the return of alloca, and there isn't any obviously better choice.
resultType = convertTypeForMem(a->getElementType());
break;
}

case Type::IncompleteArray: {
const IncompleteArrayType *arrTy = cast<IncompleteArrayType>(ty);
if (arrTy->getIndexTypeCVRQualifiers() != 0)
Expand Down
Loading