mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
handling non-fixed layouts. This uncovered a bug where we weren't rounding up the header size to the element alignment when allocating an array of archetypes. Writing up a detailed test case for *that* revealed that we were never initializing the length field of heap arrays. Fixing that caused a bunch of tests to crash trying to release stuff. So... I've left this in a workaround state right now because I have to catch a plane. Swift SVN r4804
203 lines
7.0 KiB
C++
203 lines
7.0 KiB
C++
//===--- StructLayout.cpp - Layout of structures -------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See http://swift.org/LICENSE.txt for license information
|
|
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements algorithms for laying out structures.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
#include "llvm/IR/DataLayout.h"
|
|
#include "llvm/IR/DerivedTypes.h"
|
|
|
|
#include "FixedTypeInfo.h"
|
|
#include "IRGenFunction.h"
|
|
#include "IRGenModule.h"
|
|
#include "StructLayout.h"
|
|
#include "TypeInfo.h"
|
|
|
|
using namespace swift;
|
|
using namespace irgen;
|
|
|
|
/// Does this layout kind require a heap header?
|
|
static bool requiresHeapHeader(LayoutKind kind) {
|
|
switch (kind) {
|
|
case LayoutKind::NonHeapObject: return false;
|
|
case LayoutKind::HeapObject: return true;
|
|
}
|
|
llvm_unreachable("bad layout kind!");
|
|
}
|
|
|
|
/// Return the size of the standard heap header.
|
|
Size irgen::getHeapHeaderSize(IRGenModule &IGM) {
|
|
return IGM.getPointerSize() * 2;
|
|
}
|
|
|
|
/// Add the fields for the standard heap header to the given layout.
|
|
void irgen::addHeapHeaderToLayout(IRGenModule &IGM,
|
|
Size &size, Alignment &align,
|
|
SmallVectorImpl<llvm::Type*> &fields) {
|
|
assert(size.isZero() && align.isOne() && fields.empty());
|
|
size = getHeapHeaderSize(IGM);
|
|
align = IGM.getPointerAlignment();
|
|
fields.push_back(IGM.RefCountedStructTy);
|
|
}
|
|
|
|
/// Perform structure layout on the given types.
|
|
StructLayout::StructLayout(IRGenModule &IGM, LayoutKind layoutKind,
|
|
LayoutStrategy strategy,
|
|
ArrayRef<const TypeInfo *> types,
|
|
llvm::StructType *typeToFill)
|
|
: Elements(types.size()) {
|
|
|
|
// Fill in the Elements array.
|
|
for (unsigned i = 0, e = types.size(); i != e; ++i)
|
|
Elements[i].Type = types[i];
|
|
|
|
assert(typeToFill == nullptr || typeToFill->isOpaque());
|
|
|
|
StructLayoutBuilder builder(IGM);
|
|
|
|
// Add the heap header if necessary.
|
|
if (requiresHeapHeader(layoutKind)) {
|
|
builder.addHeapHeader();
|
|
}
|
|
|
|
bool nonEmpty = builder.addFields(Elements, strategy);
|
|
|
|
// Special-case: there's nothing to store.
|
|
// In this case, produce an opaque type; this tends to cause lovely
|
|
// assertions.
|
|
if (!nonEmpty) {
|
|
assert(!builder.empty() == requiresHeapHeader(layoutKind));
|
|
Align = Alignment(1);
|
|
TotalSize = Size(0);
|
|
Ty = (typeToFill ? typeToFill : IGM.OpaquePtrTy->getElementType());
|
|
} else {
|
|
Align = builder.getAlignment();
|
|
TotalSize = builder.getSize();
|
|
if (typeToFill) {
|
|
builder.setAsBodyOfStruct(typeToFill);
|
|
Ty = typeToFill;
|
|
} else {
|
|
Ty = builder.getAsAnonStruct();
|
|
}
|
|
}
|
|
assert(typeToFill == nullptr || Ty == typeToFill);
|
|
}
|
|
|
|
llvm::Value *StructLayout::emitSize(IRGenFunction &IGF) const {
|
|
assert(hasStaticLayout());
|
|
return llvm::ConstantInt::get(IGF.IGM.SizeTy, getSize().getValue());
|
|
}
|
|
|
|
llvm::Value *StructLayout::emitAlign(IRGenFunction &IGF) const {
|
|
assert(hasStaticLayout());
|
|
return llvm::ConstantInt::get(IGF.IGM.SizeTy, getAlignment().getValue());
|
|
}
|
|
|
|
/// Bitcast an arbitrary pointer to be a pointer to this type.
|
|
Address StructLayout::emitCastTo(IRGenFunction &IGF,
|
|
llvm::Value *ptr,
|
|
const llvm::Twine &name) const {
|
|
llvm::Value *addr =
|
|
IGF.Builder.CreateBitCast(ptr, getType()->getPointerTo(), name);
|
|
return Address(addr, getAlignment());
|
|
}
|
|
|
|
Address ElementLayout::project(IRGenFunction &IGF, Address baseAddr,
|
|
const llvm::Twine &suffix) const {
|
|
return IGF.Builder.CreateStructGEP(baseAddr, StructIndex, ByteOffset,
|
|
baseAddr.getAddress()->getName() + suffix);
|
|
}
|
|
|
|
void StructLayoutBuilder::addHeapHeader() {
|
|
assert(StructFields.empty() && "adding heap header at a non-zero offset");
|
|
CurSize = getHeapHeaderSize(IGM);
|
|
CurAlignment = IGM.getPointerAlignment();
|
|
StructFields.push_back(IGM.RefCountedStructTy);
|
|
}
|
|
|
|
bool StructLayoutBuilder::addFields(llvm::MutableArrayRef<ElementLayout> elts,
|
|
LayoutStrategy strategy) {
|
|
// Track whether we've added any storage to our layout.
|
|
bool addedStorage = false;
|
|
|
|
// Loop through the elements. The only valid field in each element
|
|
// is Type; StructIndex and ByteOffset need to be laid out.
|
|
for (auto &elt : elts) {
|
|
auto &eltTI = *elt.Type;
|
|
|
|
// If the element type is empty, it adds nothing.
|
|
if (eltTI.isKnownEmpty()) {
|
|
elt.StructIndex = ElementLayout::NoStructIndex;
|
|
elt.ByteOffset = Size(-1);
|
|
continue;
|
|
}
|
|
|
|
// Anything else we do at least potentially adds storage requirements.
|
|
addedStorage = true;
|
|
|
|
// FIXME: handle resilient/dependently-sized types
|
|
auto &fixedEltTI = cast<FixedTypeInfo>(eltTI);
|
|
|
|
// TODO: consider using different layout rules.
|
|
// If the rules are changed so that fields aren't necessarily laid
|
|
// out sequentially, the computation of InstanceStart in the
|
|
// RO-data will need to be fixed.
|
|
|
|
// The struct alignment is the max of the alignment of the fields.
|
|
CurAlignment = std::max(CurAlignment, fixedEltTI.getFixedAlignment());
|
|
|
|
// If the current tuple size isn't a multiple of the field's
|
|
// required alignment, we need to pad out.
|
|
Alignment eltAlignment = fixedEltTI.getFixedAlignment();
|
|
if (Size offsetFromAlignment = CurSize % eltAlignment) {
|
|
unsigned paddingRequired
|
|
= eltAlignment.getValue() - offsetFromAlignment.getValue();
|
|
assert(paddingRequired != 0);
|
|
|
|
// We don't actually need to uglify the IR unless the natural
|
|
// alignment of the IR type for the field isn't good enough.
|
|
Alignment fieldIRAlignment(
|
|
IGM.DataLayout.getABITypeAlignment(eltTI.StorageType));
|
|
assert(fieldIRAlignment <= eltAlignment);
|
|
if (fieldIRAlignment != eltAlignment) {
|
|
auto paddingTy = llvm::ArrayType::get(IGM.Int8Ty, paddingRequired);
|
|
StructFields.push_back(paddingTy);
|
|
}
|
|
|
|
// Regardless, the storage size goes up.
|
|
CurSize += Size(paddingRequired);
|
|
}
|
|
|
|
// Set the element's offset and field-index.
|
|
elt.ByteOffset = CurSize;
|
|
elt.StructIndex = StructFields.size();
|
|
|
|
StructFields.push_back(eltTI.getStorageType());
|
|
CurSize += fixedEltTI.getFixedSize();
|
|
}
|
|
|
|
return addedStorage;
|
|
}
|
|
|
|
/// Produce the current fields as an anonymous structure.
|
|
llvm::StructType *StructLayoutBuilder::getAsAnonStruct() const {
|
|
return llvm::StructType::get(IGM.getLLVMContext(), StructFields);
|
|
}
|
|
|
|
/// Set the current fields as the body of the given struct type.
|
|
void StructLayoutBuilder::setAsBodyOfStruct(llvm::StructType *type) const {
|
|
assert(type->isOpaque());
|
|
type->setBody(StructFields);
|
|
}
|