Skip to content

Commit ae0027a

Browse files
authored
Merge pull request #15033 from rjmccall/fixed-field-offset-vectors
2 parents 39dc184 + 9c8bdf2 commit ae0027a

File tree

4 files changed

+128
-27
lines changed

4 files changed

+128
-27
lines changed

lib/IRGen/GenMeta.cpp

Lines changed: 101 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5037,6 +5037,10 @@ namespace {
50375037
public:
50385038
void noteStartOfTypeSpecificMembers() {}
50395039

5040+
SILType getLoweredType() {
5041+
return IGM.getLoweredType(Target->getDeclaredTypeInContext());
5042+
}
5043+
50405044
MetadataKind getMetadataKind() {
50415045
return MetadataKind::Struct;
50425046
}
@@ -5067,8 +5071,7 @@ namespace {
50675071
void addFieldOffset(VarDecl *var) {
50685072
assert(var->hasStorage() &&
50695073
"storing field offset for computed property?!");
5070-
SILType structType =
5071-
IGM.getLoweredType(Target->getDeclaredTypeInContext());
5074+
SILType structType = getLoweredType();
50725075

50735076
llvm::Constant *offset =
50745077
emitPhysicalStructMemberFixedOffset(IGM, structType, var);
@@ -5162,19 +5165,64 @@ namespace {
51625165
HasDependentVWT);
51635166
}
51645167

5165-
bool hasCompletionFunction() {
5166-
// TODO: recognize cases where this is not required
5168+
bool hasExtraDataPattern() {
5169+
auto &ti = IGM.getTypeInfo(getLoweredType());
5170+
if (!isa<FixedTypeInfo>(ti))
5171+
return false;
5172+
5173+
if (Target->getStoredProperties().empty())
5174+
return false;
5175+
51675176
return true;
51685177
}
5169-
5178+
5179+
/// Fill in a constant field offset vector if possible.
5180+
PartialPattern buildExtraDataPattern() {
5181+
ConstantInitBuilder builder(IGM);
5182+
auto init = builder.beginArray(IGM.SizeTy);
5183+
5184+
struct Scanner : StructMetadataScanner<Scanner> {
5185+
SILType Type;
5186+
ConstantArrayBuilder &B;
5187+
Scanner(IRGenModule &IGM, StructDecl *target, SILType type,
5188+
ConstantArrayBuilder &B)
5189+
: StructMetadataScanner(IGM, target), Type(type), B(B) {}
5190+
5191+
void addFieldOffset(VarDecl *field) {
5192+
auto offset = emitPhysicalStructMemberFixedOffset(IGM, Type, field);
5193+
if (offset) {
5194+
B.add(offset);
5195+
return;
5196+
}
5197+
assert(IGM.isKnownEmpty(Type.getFieldType(field, IGM.getSILModule()),
5198+
ResilienceExpansion::Maximal));
5199+
B.addInt(IGM.SizeTy, 0);
5200+
}
5201+
};
5202+
Scanner(IGM, Target, getLoweredType(), init).layout();
5203+
Size vectorSize = init.getNextOffsetFromGlobal();
5204+
5205+
auto global = init.finishAndCreateGlobal("", IGM.getPointerAlignment(),
5206+
/*constant*/ true);
5207+
5208+
auto &layout = IGM.getMetadataLayout(Target);
5209+
return { global,
5210+
layout.getFieldOffsetVectorOffset().getStatic()
5211+
- IGM.getOffsetOfStructTypeSpecificMetadataMembers(),
5212+
vectorSize };
5213+
}
5214+
5215+
bool hasCompletionFunction() {
5216+
return !isa<FixedTypeInfo>(IGM.getTypeInfo(getLoweredType()));
5217+
}
5218+
51705219
void emitInitializeMetadata(IRGenFunction &IGF,
51715220
llvm::Value *metadata,
51725221
bool isVWTMutable) {
51735222
// Nominal types are always preserved through SIL lowering.
5174-
auto structTy = Target->getDeclaredTypeInContext()->getCanonicalType();
5175-
IGM.getTypeInfoForUnlowered(structTy)
5176-
.initializeMetadata(IGF, metadata, isVWTMutable,
5177-
IGF.IGM.getLoweredType(structTy));
5223+
auto loweredTy = getLoweredType();
5224+
IGM.getTypeInfo(loweredTy)
5225+
.initializeMetadata(IGF, metadata, isVWTMutable, loweredTy);
51785226
}
51795227
};
51805228
} // end anonymous namespace
@@ -5231,6 +5279,10 @@ namespace {
52315279
: super(IGM, theEnum), B(B) {
52325280
}
52335281

5282+
SILType getLoweredType() {
5283+
return IGM.getLoweredType(Target->getDeclaredTypeInContext());
5284+
}
5285+
52345286
public:
52355287
void noteStartOfTypeSpecificMembers() {}
52365288

@@ -5270,6 +5322,19 @@ namespace {
52705322
void addGenericWitnessTable(CanType type, ProtocolConformanceRef conf) {
52715323
B.addNullPointer(IGM.WitnessTablePtrTy);
52725324
}
5325+
5326+
Optional<Size> getConstantPayloadSize() {
5327+
auto enumTy = Target->getDeclaredTypeInContext()->getCanonicalType();
5328+
auto &enumTI = IGM.getTypeInfoForUnlowered(enumTy);
5329+
if (!enumTI.isFixedSize(ResilienceExpansion::Maximal)) {
5330+
return None;
5331+
}
5332+
5333+
assert(!enumTI.isFixedSize(ResilienceExpansion::Minimal) &&
5334+
"non-generic, non-resilient enums don't need payload size in metadata");
5335+
auto &strategy = getEnumImplStrategy(IGM, enumTy);
5336+
return Size(strategy.getPayloadSizeForMetadata());
5337+
}
52735338
};
52745339

52755340
class EnumMetadataBuilder
@@ -5281,19 +5346,17 @@ namespace {
52815346
ConstantStructBuilder &B)
52825347
: EnumMetadataBuilderBase(IGM, theEnum, B) {}
52835348

5349+
5350+
52845351
void addPayloadSize() {
5285-
auto enumTy = Target->getDeclaredTypeInContext()->getCanonicalType();
5286-
auto &enumTI = IGM.getTypeInfoForUnlowered(enumTy);
5287-
if (!enumTI.isFixedSize(ResilienceExpansion::Maximal)) {
5352+
auto payloadSize = getConstantPayloadSize();
5353+
if (!payloadSize) {
52885354
B.addInt(IGM.IntPtrTy, 0);
52895355
HasUnfilledPayloadSize = true;
52905356
return;
52915357
}
52925358

5293-
assert(!enumTI.isFixedSize(ResilienceExpansion::Minimal) &&
5294-
"non-generic, non-resilient enums don't need payload size in metadata");
5295-
auto &strategy = getEnumImplStrategy(IGM, enumTy);
5296-
B.addInt(IGM.IntPtrTy, strategy.getPayloadSizeForMetadata());
5359+
B.addInt(IGM.IntPtrTy, payloadSize->getValue());
52975360
}
52985361

52995362
bool canBeConstant() {
@@ -5325,9 +5388,24 @@ namespace {
53255388
- IGM.getOffsetOfEnumTypeSpecificMetadataMembers();
53265389
auto extraSizeV = IGM.getSize(extraSize);
53275390

5328-
return IGF.Builder.CreateCall(IGM.getAllocateGenericValueMetadataFn(),
5329-
{descriptor, arguments, templatePointer,
5330-
extraSizeV});
5391+
auto metadata =
5392+
IGF.Builder.CreateCall(IGM.getAllocateGenericValueMetadataFn(),
5393+
{descriptor, arguments, templatePointer,
5394+
extraSizeV});
5395+
5396+
// Initialize the payload-size field if we have a constant value for it.
5397+
// This is so small that we just do it inline instead of bothering
5398+
// with a pattern.
5399+
if (layout.hasPayloadSizeOffset()) {
5400+
if (auto size = getConstantPayloadSize()) {
5401+
auto offset = layout.getPayloadSizeOffset();
5402+
auto slot = IGF.emitAddressAtOffset(metadata, offset, IGM.SizeTy,
5403+
IGM.getPointerAlignment());
5404+
IGF.Builder.CreateStore(IGM.getSize(*size), slot);
5405+
}
5406+
}
5407+
5408+
return metadata;
53315409
}
53325410

53335411
llvm::Constant *emitValueWitnessTable() {
@@ -5336,18 +5414,16 @@ namespace {
53365414
}
53375415

53385416
bool hasCompletionFunction() {
5339-
// TODO: recognize cases where this is not required
5340-
return true;
5417+
return !isa<FixedTypeInfo>(IGM.getTypeInfo(getLoweredType()));
53415418
}
53425419

53435420
void emitInitializeMetadata(IRGenFunction &IGF,
53445421
llvm::Value *metadata,
53455422
bool isVWTMutable) {
53465423
// Nominal types are always preserved through SIL lowering.
5347-
auto enumTy = Target->getDeclaredTypeInContext()->getCanonicalType();
5348-
IGM.getTypeInfoForUnlowered(enumTy)
5349-
.initializeMetadata(IGF, metadata, isVWTMutable,
5350-
IGF.IGM.getLoweredType(enumTy));
5424+
auto enumTy = getLoweredType();
5425+
IGM.getTypeInfo(enumTy)
5426+
.initializeMetadata(IGF, metadata, isVWTMutable, enumTy);
53515427
}
53525428
};
53535429

stdlib/public/runtime/Metadata.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,7 @@ initializeValueMetadataFromPattern(ValueMetadata *metadata,
397397

398398
if (pattern->hasExtraDataPattern()) {
399399
void **metadataExtraData =
400-
reinterpret_cast<void**>(rawMetadata) + sizeof(ValueMetadata);
400+
reinterpret_cast<void**>(rawMetadata + sizeof(ValueMetadata));
401401
auto extraDataPattern = pattern->getExtraDataPattern();
402402

403403
// Zero memory up to the offset.

test/IRGen/enum_value_semantics.sil

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,10 @@ enum GenericFixedLayout<T> {
159159
// CHECK-SAME: @"$S20enum_value_semantics18GenericFixedLayoutOMP"
160160

161161
// CHECK-LABEL: @"$S20enum_value_semantics18GenericFixedLayoutOMP" = internal constant <{ {{.*}} }> <{
162+
// Instantiation function.
162163
// CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (%swift.type* (%swift.type_descriptor*, i8**, i8**)* @"$S20enum_value_semantics18GenericFixedLayoutOMi" to i64), i64 ptrtoint (<{ i32, i32, i32, i32 }>* @"$S20enum_value_semantics18GenericFixedLayoutOMP" to i64)) to i32),
163-
// CHECK-SAME: @"$S20enum_value_semantics18GenericFixedLayoutOMr"
164+
// Completion function.
165+
// CHECK-SAME: i32 0,
164166
// Pattern flags. 0x400000 == (MetadataKind::Enum << 21).
165167
// CHECK-SAME: i32 4194304,
166168
// Value witness table.

test/IRGen/generic_structs.sil

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,23 @@
66

77
import Builtin
88

9+
// -- Generic structs with fixed layout should have no completion function
10+
// and emit the field offset vector as part of the pattern.
11+
// CHECK: [[PATTERN:@.*]] = internal constant [3 x i64] [i64 0, i64 1, i64 8]
12+
// CHECK-LABEL: @"$S15generic_structs18FixedLayoutGenericVMP" = internal constant <{ {{.*}} }> <{
13+
// -- instantiation function
14+
// CHECK-SAME: %swift.type* (%swift.type_descriptor*, i8**, i8**)* @"$S15generic_structs18FixedLayoutGenericVMi"
15+
// -- completion function
16+
// CHECK-SAME: i32 0,
17+
// -- pattern flags
18+
// CHECK-SAME: i32 2097153,
19+
// -- vwtable pointer
20+
// CHECK-SAME: @"$S15generic_structs18FixedLayoutGenericVWV"
21+
// -- extra data pattern
22+
// CHECK-SAME: [3 x i64]* [[PATTERN]]
23+
// CHECK-SAME: i16 1,
24+
// CHECK-SAME: i16 3 }>
25+
926
// -- Generic structs with dynamic layout contain the vwtable pattern as part
1027
// of the metadata pattern, and no independent vwtable symbol
1128
// CHECK: @"$S15generic_structs13SingleDynamicVWV" = internal constant
@@ -88,6 +105,12 @@ import Builtin
88105
// CHECK-SAME: i64 0, i64 8, i64 16
89106
// CHECK-SAME: }>
90107

108+
struct FixedLayoutGeneric<T> {
109+
var x: Byteful
110+
var y: Byteful
111+
var z: Intish
112+
}
113+
91114
struct SingleDynamic<T> {
92115
var x : T
93116
}

0 commit comments

Comments
 (0)