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

@@ -379,7 +379,8 @@ namespace {
}
return getSingleton()->getExtraInhabitantIndex(IGF,
getSingletonAddress(IGF, src), T);
getSingletonAddress(IGF, src),
getSingletonType(IGF.IGM, T));
}
void storeExtraInhabitant(IRGenFunction &IGF,
@@ -390,7 +391,8 @@ namespace {
return;
}
getSingleton()->storeExtraInhabitant(IGF, index,
getSingletonAddress(IGF, dest), T);
getSingletonAddress(IGF, dest),
getSingletonType(IGF.IGM, T));
}
unsigned getFixedExtraInhabitantCount(IRGenModule &IGM) const override {
@@ -998,6 +1000,8 @@ namespace {
};
CopyDestroyStrategy CopyDestroyKind;
unsigned NumExtraInhabitantTagValues = ~0U;
public:
SinglePayloadEnumImplStrategy(IRGenModule &IGM,
@@ -1036,6 +1040,13 @@ namespace {
// TODO: Same for single unknown-refcounted pointers.
}
/// Return the number of tag values represented with extra
/// inhabitants in the payload.
unsigned getNumExtraInhabitantTagValues() const {
assert(NumExtraInhabitantTagValues != ~0U);
return NumExtraInhabitantTagValues;
}
/// The payload for a single-payload enum is always placed in front and
/// will never have interleaved tag bits, so we can just bitcast the enum
@@ -1137,8 +1148,7 @@ namespace {
if (payloadTy)
payload = value.claimNext();
llvm::BasicBlock *payloadDest = blockForCase(getPayloadElement());
unsigned extraInhabitantCount
= getFixedPayloadTypeInfo().getFixedExtraInhabitantCount(IGF.IGM);
unsigned extraInhabitantCount = getNumExtraInhabitantTagValues();
// If there are extra tag bits, switch over them first.
SmallVector<llvm::BasicBlock*, 2> tagBitBlocks;
@@ -1193,7 +1203,9 @@ namespace {
= getFixedPayloadTypeInfo().getFixedSize().getValueInBits();
if (extraInhabitantCount > 0) {
assert(payload && "extra inhabitants with empty payload?!");
auto *swi = IGF.Builder.CreateSwitch(payload, payloadDest);
auto *switchValue =
getFixedPayloadTypeInfo().maskFixedExtraInhabitant(IGF, payload);
auto *swi = IGF.Builder.CreateSwitch(switchValue, payloadDest);
for (unsigned i = 0; i < extraInhabitantCount && elti != eltEnd; ++i) {
auto v = getFixedPayloadTypeInfo().getFixedExtraInhabitantValue(
IGF.IGM, payloadBits, i);
@@ -1363,8 +1375,7 @@ namespace {
// Non-payload cases use extra inhabitants, if any, or are discriminated
// by setting the tag bits.
unsigned tagIndex = getSimpleElementTagIndex(elt);
unsigned numExtraInhabitants
= getFixedPayloadTypeInfo().getFixedExtraInhabitantCount(IGM);
unsigned numExtraInhabitants = getNumExtraInhabitantTagValues();
llvm::ConstantInt *payload = nullptr;
unsigned extraTagValue;
if (tagIndex < numExtraInhabitants) {
@@ -1465,11 +1476,15 @@ namespace {
// If we used extra inhabitants to represent empty case discriminators,
// weed them out.
unsigned numExtraInhabitants
= getFixedPayloadTypeInfo().getFixedExtraInhabitantCount(IGF.IGM);
unsigned numExtraInhabitants = getNumExtraInhabitantTagValues();
if (numExtraInhabitants > 0) {
unsigned bitWidth =
getFixedPayloadTypeInfo().getFixedSize().getValueInBits();
auto *payloadBB = llvm::BasicBlock::Create(IGF.IGM.getLLVMContext());
auto *swi = IGF.Builder.CreateSwitch(payload, payloadBB);
auto *switchValue =
getFixedPayloadTypeInfo().maskFixedExtraInhabitant(IGF, payload);
auto *swi = IGF.Builder.CreateSwitch(switchValue, payloadBB);
auto elements = getPayloadElement()->getParentEnum()->getAllElements();
unsigned inhabitant = 0;
@@ -1482,9 +1497,7 @@ namespace {
break;
}
auto xi = getFixedPayloadTypeInfo().getFixedExtraInhabitantValue(
IGF.IGM,
getFixedPayloadTypeInfo().getFixedSize().getValueInBits(),
inhabitant);
IGF.IGM, bitWidth, inhabitant);
swi->addCase(xi, falseBB);
}
@@ -2001,15 +2014,8 @@ namespace {
}
unsigned getFixedExtraInhabitantCount(IRGenModule &IGM) const override {
unsigned payloadXI
= getFixedPayloadTypeInfo().getFixedExtraInhabitantCount(IGM);
unsigned numEmptyCases = ElementsWithNoPayload.size();
if (payloadXI <= numEmptyCases)
return 0;
return payloadXI - numEmptyCases;
return getFixedPayloadTypeInfo().getFixedExtraInhabitantCount(IGM)
- getNumExtraInhabitantTagValues();
}
llvm::ConstantInt *
@@ -2018,7 +2024,7 @@ namespace {
unsigned index) const override {
return getFixedPayloadTypeInfo()
.getFixedExtraInhabitantValue(IGM, bits,
index + ElementsWithNoPayload.size());
index + getNumExtraInhabitantTagValues());
}
llvm::Value *
@@ -3550,9 +3556,9 @@ namespace {
// Determine how many tag bits we need. Given N extra inhabitants, we
// represent the first N tags using those inhabitants. For additional tags,
// we use discriminator bit(s) to inhabit the full bit size of the payload.
unsigned tagsWithoutInhabitants = numTags <= fixedExtraInhabitants
? 0 : numTags - fixedExtraInhabitants;
NumExtraInhabitantTagValues = std::min(numTags, fixedExtraInhabitants);
unsigned tagsWithoutInhabitants = numTags - NumExtraInhabitantTagValues;
if (tagsWithoutInhabitants == 0) {
ExtraTagBitCount = 0;
NumExtraTagValues = 0;