Skip to content

Commit 6810a46

Browse files
committed
LargeTypesReg2Mem: Avoid building an explosion schema just to count the number of registers for very large types
Computing the explosion schema for large types can be expensive. E.g the following example would spend multiple seconds to compute the explosion scheme for the array type. It is not worth adding the complexity to have a special case explosion schema that handles types like that since exploding a value like that is going to be detrimental. ``` struct Test { private var values: [0xfffffff of [UInt32]] = InlineArray(repeating: []) } ``` rdar://165202495
1 parent d019f37 commit 6810a46

File tree

4 files changed

+42
-7
lines changed

4 files changed

+42
-7
lines changed

include/swift/SIL/SILTypeProperties.h

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,13 @@ enum MayHaveCustomDeinit_t : bool {
128128
MayHaveCustomDeinit = true,
129129
};
130130

131+
/// Is this a very large type whose expansion into SSA values is likely
132+
/// detrimential i.e should be kept indirect.
133+
enum IsVeryLargeType_t : bool {
134+
IsNotVeryLargeType = false,
135+
IsVeryLargeType = true
136+
};
137+
131138
class SILTypeProperties {
132139
// These are chosen so that bitwise-or merges the flags properly.
133140
//
@@ -145,6 +152,7 @@ class SILTypeProperties {
145152
AddressableForDependenciesFlag = 1 << 9,
146153
HasRawLayoutFlag = 1 << 10,
147154
CustomDeinitFlag = 1 << 11,
155+
IsVeryLargeTypeFlag = 1 << 12,
148156
};
149157
// clang-format on
150158

@@ -164,7 +172,8 @@ class SILTypeProperties {
164172
IsLexical_t isLexical = IsNotLexical, HasPack_t hasPack = HasNoPack,
165173
IsAddressableForDependencies_t isAFD = IsNotAddressableForDependencies,
166174
HasRawLayout_t hasRawLayout = DoesNotHaveRawLayout,
167-
MayHaveCustomDeinit_t customDeinit = HasOnlyDefaultDeinit)
175+
MayHaveCustomDeinit_t customDeinit = HasOnlyDefaultDeinit,
176+
IsVeryLargeType_t largeType = IsNotVeryLargeType )
168177
: Flags((isTrivial ? 0U : NonTrivialFlag) |
169178
(isFixedABI ? 0U : NonFixedABIFlag) |
170179
(isAddressOnly ? AddressOnlyFlag : 0U) |
@@ -175,7 +184,8 @@ class SILTypeProperties {
175184
(hasPack ? HasPackFlag : 0U) |
176185
(isAFD ? AddressableForDependenciesFlag : 0U) |
177186
(hasRawLayout ? HasRawLayoutFlag : 0U) |
178-
(customDeinit ? CustomDeinitFlag : 0U)) {}
187+
(customDeinit ? CustomDeinitFlag : 0U) |
188+
(largeType ? IsVeryLargeTypeFlag : 0U)) {}
179189

180190
constexpr bool operator==(SILTypeProperties p) const {
181191
return Flags == p.Flags;
@@ -261,6 +271,9 @@ class SILTypeProperties {
261271
MayHaveCustomDeinit_t mayHaveCustomDeinit() const {
262272
return MayHaveCustomDeinit_t((Flags & CustomDeinitFlag) != 0);
263273
}
274+
IsVeryLargeType_t isVeryLargeType() const {
275+
return IsVeryLargeType_t((Flags & IsVeryLargeTypeFlag) != 0);
276+
}
264277

265278
void setNonTrivial() { Flags |= NonTrivialFlag; }
266279
void setIsOrContainsRawPointer() { Flags |= HasRawPointerFlag; }
@@ -287,6 +300,7 @@ class SILTypeProperties {
287300
Flags = (Flags & ~CustomDeinitFlag)
288301
| (hasCustomDeinit ? CustomDeinitFlag : 0);
289302
}
303+
void setVeryLargeType() { Flags |= IsVeryLargeTypeFlag; }
290304
};
291305

292306
} // end namespace swift

lib/IRGen/FixedTypeInfo.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ class FixedTypeInfo : public TypeInfo {
6666
SpecialTypeInfoKind stik = SpecialTypeInfoKind::Fixed)
6767
: TypeInfo(type, align, pod, bt, copy, alwaysFixedSize, isABIAccessible, stik),
6868
SpareBits(std::move(spareBits)) {
69-
assert(SpareBits.size() == size.getValueInBits());
69+
// SpareBits implementation is limited to 32bits.
70+
assert(SpareBits.size() == (size.getValueInBits() & 0xFFFFFFFF));
7071
assert(isFixedSize());
7172
Bits.FixedTypeInfo.Size = size.getValue();
7273
assert(Bits.FixedTypeInfo.Size == size.getValue() && "truncation");

lib/IRGen/LoadableByAddress.cpp

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3511,6 +3511,7 @@ namespace {
35113511
class LargeLoadableHeuristic {
35123512
GenericEnvironment *genEnv;
35133513
IRGenModule *irgenModule;
3514+
SILFunction &fun;
35143515

35153516
llvm::DenseMap<SILType, Properties> largeTypeProperties;
35163517

@@ -3522,8 +3523,9 @@ class LargeLoadableHeuristic {
35223523

35233524
public:
35243525
LargeLoadableHeuristic(IRGenModule *irgenModule, GenericEnvironment *genEnv,
3526+
SILFunction &f,
35253527
bool UseAggressiveHeuristic)
3526-
: genEnv(genEnv), irgenModule(irgenModule),
3528+
: genEnv(genEnv), irgenModule(irgenModule), fun(f),
35273529
UseAggressiveHeuristic(UseAggressiveHeuristic) {}
35283530

35293531
void visit(SILInstruction *i);
@@ -3558,6 +3560,16 @@ class LargeLoadableHeuristic {
35583560
if (cached)
35593561
return cached;
35603562

3563+
// Avoid computing an explosion schema for very large types as this can be
3564+
// very compile time intensive.
3565+
if (fun.getTypeProperties(ty).isVeryLargeType()) {
3566+
unsigned veryLargeTypeRegisterCount =
3567+
BuiltinFixedArrayType::MaximumLoadableSize;
3568+
entry.setNumRegisters(veryLargeTypeRegisterCount);
3569+
largeTypeProperties[ty] = entry;
3570+
return veryLargeTypeRegisterCount;
3571+
}
3572+
35613573
const TypeInfo &TI = irgenModule->getTypeInfoForLowered(canType);
35623574
auto &nativeSchemaOrigParam = TI.nativeParameterValueSchema(*irgenModule);
35633575
// Passed compactly in registers but kept in many explosions.
@@ -3603,6 +3615,9 @@ void LargeLoadableHeuristic::propagate(PostOrderFunctionInfo &po) {
36033615
}
36043616

36053617
void LargeLoadableHeuristic::visit(SILArgument *arg) {
3618+
if (arg->getType().isAddress())
3619+
return;
3620+
36063621
auto objType = arg->getType().getObjectType();
36073622
if (numRegisters(objType) < NumRegistersLargeType)
36083623
return;
@@ -3651,6 +3666,8 @@ void LargeLoadableHeuristic::visit(SILInstruction *i) {
36513666
for (const auto &opd : i->getAllOperands()) {
36523667
auto opdTy = opd.get()->getType();
36533668
auto objType = opdTy.getObjectType();
3669+
bool isAddress = opdTy.isAddress();
3670+
36543671
auto registerCount = numRegisters(objType);
36553672
if (registerCount < NumRegistersLargeType)
36563673
continue;
@@ -3699,10 +3716,12 @@ void LargeLoadableHeuristic::visit(SILInstruction *i) {
36993716
case SILInstructionKind::PartialApplyInst:
37003717
case SILInstructionKind::TryApplyInst:
37013718
case SILInstructionKind::BeginApplyInst:
3702-
entry.addFunctionUseOrReturn();
3719+
if (!isAddress)
3720+
entry.addFunctionUseOrReturn();
37033721
break;
37043722
default:
3705-
entry.addUse();
3723+
if (!isAddress)
3724+
entry.addUse();
37063725
break;
37073726
}
37083727

@@ -4735,7 +4754,7 @@ static void runPeepholesAndReg2Mem(SILPassManager *pm, SILModule *silMod,
47354754
// copy_addr peepholes
47364755
bool UseAggressiveHeuristic =
47374756
silMod->getOptions().UseAggressiveReg2MemForCodeSize;
4738-
LargeLoadableHeuristic heuristic(irgenModule, genEnv,
4757+
LargeLoadableHeuristic heuristic(irgenModule, genEnv, currF,
47394758
UseAggressiveHeuristic);
47404759
Peepholes opts(pm, silMod, irgenModule);
47414760
for (SILBasicBlock &BB : currF) {

lib/SIL/IR/TypeLowering.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,7 @@ namespace {
404404
&& (!fixedSize.has_value()
405405
|| *fixedSize > BuiltinFixedArrayType::MaximumLoadableSize)) {
406406
props.setAddressOnly();
407+
props.setVeryLargeType();
407408
}
408409
return props;
409410
}

0 commit comments

Comments
 (0)