Use the first element of structs and tuples as a source

for extra inhabitants.

For structs in particular, this eliminates a major source
of abstraction penatlies.  For example, an optional struct
containing an object pointer is now represented the same
way as an optional object pointer, which is critical for
correctly importing CF types as Unmanaged<T>!.

In time, we should generalize this to consider all elements
as sources for extra inhabitants, as well as exploiting
spare bits in the representation, but getting the
single-element case right really provides the bulk of the
benefit.

This commit restores r17242 and r17243 with a fix to use
value witnesses that actually forward the right type metadata
down.  We were already generating these value witnesses in
the dependent struct VWT pattern, but I was being too clever
and trying to use the underlying value witness directly.

Swift SVN r17267
This commit is contained in:
John McCall
2014-05-02 20:17:14 +00:00
parent 0f8733867b
commit c57dac63ae
8 changed files with 304 additions and 85 deletions

View File

@@ -123,6 +123,62 @@ namespace {
}
return nullptr;
}
// For now, just use extra inhabitants from the first field.
// FIXME: generalize
bool mayHaveExtraInhabitants(IRGenModule &IGM) const override {
if (asImpl().getFields().empty()) return false;
return asImpl().getFields()[0].getTypeInfo().mayHaveExtraInhabitants(IGM);
}
// This is dead code in NonFixedStructTypeInfo.
unsigned getFixedExtraInhabitantCount(IRGenModule &IGM) const {
if (asImpl().getFields().empty()) return 0;
auto &fieldTI = cast<FixedTypeInfo>(asImpl().getFields()[0].getTypeInfo());
return fieldTI.getFixedExtraInhabitantCount(IGM);
}
// This is dead code in NonFixedStructTypeInfo.
llvm::ConstantInt *getFixedExtraInhabitantValue(IRGenModule &IGM,
unsigned bits,
unsigned index) const {
auto &fieldTI = cast<FixedTypeInfo>(asImpl().getFields()[0].getTypeInfo());
return fieldTI.getFixedExtraInhabitantValue(IGM, bits, index);
}
// This is dead code in NonFixedStructTypeInfo.
llvm::Value *maskFixedExtraInhabitant(IRGenFunction &IGF,
llvm::Value *structValue) const {
// Truncate down to the width of the field, mask it recursively,
// and then zext back out to the payload size.
auto &fieldTI = cast<FixedTypeInfo>(asImpl().getFields()[0].getTypeInfo());
unsigned fieldWidth = fieldTI.getFixedSize().getValueInBits();
auto fieldTy = llvm::IntegerType::get(IGF.IGM.getLLVMContext(), fieldWidth);
auto fieldValue = IGF.Builder.CreateTrunc(structValue, fieldTy);
fieldValue = fieldTI.maskFixedExtraInhabitant(IGF, fieldValue);
return IGF.Builder.CreateZExt(fieldValue, structValue->getType());
}
llvm::Value *getExtraInhabitantIndex(IRGenFunction &IGF,
Address structAddr,
CanType structType) const override {
auto &field = asImpl().getFields()[0];
Address fieldAddr =
asImpl().projectFieldAddress(IGF, structAddr, structType, field.Field);
return field.getTypeInfo().getExtraInhabitantIndex(IGF, fieldAddr,
field.getType(IGF.IGM, structType));
}
void storeExtraInhabitant(IRGenFunction &IGF,
llvm::Value *index,
Address structAddr,
CanType structType) const override {
auto &field = asImpl().getFields()[0];
Address fieldAddr =
asImpl().projectFieldAddress(IGF, structAddr, structType, field.Field);
field.getTypeInfo().storeExtraInhabitant(IGF, index, fieldAddr,
field.getType(IGF.IGM, structType));
}
};
@@ -149,14 +205,6 @@ namespace {
Nothing_t getNonFixedOffsets(IRGenFunction &IGF) const {
return Nothing;
}
// FIXME: Suppress use of extra inhabitants for single-payload enum layout
// until we're ready to handle the runtime logic for exporting extra
// inhabitants through generic structs.
bool mayHaveExtraInhabitants(IRGenModule&) const override { return false; }
unsigned getFixedExtraInhabitantCount(IRGenModule&) const override {
return 0;
}
};
/// A type implementation for non-loadable but fixed-size struct types.
@@ -176,14 +224,6 @@ namespace {
return Nothing;
}
Nothing_t getNonFixedOffsets(IRGenFunction &IGF) const { return Nothing; }
// FIXME: Suppress use of extra inhabitants for single-payload enum layout
// until we're ready to handle the runtime logic for exporting extra
// inhabitants through generic structs.
bool mayHaveExtraInhabitants(IRGenModule&) const override { return false; }
unsigned getFixedExtraInhabitantCount(IRGenModule&) const override {
return 0;
}
};
/// Find the beginning of the field offset vector in a struct's metadata.