Skip to content

Commit 6ae0b22

Browse files
committed
SILOptimizer: handle copies in LetPropertiesOpt.
When the initializer of a property is analyzed we now don't bail if such a property is copied from another instance of a struct/class. This fixes a strange performance regression with constant let properties in structs which conform to an unrelated protocol. SR-7713 rdar://problem/40332203
1 parent 6d3f74a commit 6ae0b22

File tree

2 files changed

+41
-5
lines changed

2 files changed

+41
-5
lines changed

lib/SILOptimizer/IPO/LetPropertiesOpts.cpp

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,16 @@ bool LetPropertiesOpt::isConstantLetProperty(VarDecl *Property) {
388388
return true;
389389
}
390390

391+
static bool isProjectionOfProperty(SILValue addr, VarDecl *Property) {
392+
if (auto *REA = dyn_cast<RefElementAddrInst>(addr)) {
393+
return REA->getField() == Property;
394+
}
395+
if (auto *SEA = dyn_cast<StructElementAddrInst>(addr)) {
396+
return SEA->getField() == Property;
397+
}
398+
return false;
399+
}
400+
391401
// Analyze the init value being stored by the instruction into a property.
392402
bool
393403
LetPropertiesOpt::analyzeInitValue(SILInstruction *I, VarDecl *Property) {
@@ -398,15 +408,19 @@ LetPropertiesOpt::analyzeInitValue(SILInstruction *I, VarDecl *Property) {
398408
} else if (auto SI = dyn_cast<StoreInst>(I)) {
399409
auto Dest = stripAddressAccess(SI->getDest());
400410

401-
assert(((isa<RefElementAddrInst>(Dest) &&
402-
cast<RefElementAddrInst>(Dest)->getField() == Property) ||
403-
(isa<StructElementAddrInst>(Dest) &&
404-
cast<StructElementAddrInst>(Dest)->getField() == Property)) &&
405-
"Store instruction should store into a proper let property");
411+
assert(isProjectionOfProperty(stripAddressAccess(SI->getDest()), Property)
412+
&& "Store instruction should store into a proper let property");
406413
(void) Dest;
407414
value = SI->getSrc();
408415
}
409416

417+
// Check if it's just a copy from another instance of the struct.
418+
if (auto *LI = dyn_cast<LoadInst>(value)) {
419+
SILValue addr = LI->getOperand();
420+
if (isProjectionOfProperty(addr, Property))
421+
return true;
422+
}
423+
410424
// Bail if a value of a property is not a statically known constant init.
411425
if (!analyzeStaticInitializer(value, ReverseInsns))
412426
return false;

test/SILOptimizer/let_properties_opts.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,3 +354,25 @@ public func useInitializers() -> StructWithPublicAndInternalLetProperties {
354354
public func useInitializers() -> StructWithPublicAndInternalAndPrivateLetProperties {
355355
return StructWithPublicAndInternalAndPrivateLetProperties(1, 1)
356356
}
357+
358+
struct RACStruct {
359+
private let end = 27
360+
361+
var startIndex: Int { return 0 }
362+
363+
364+
// CHECK-LABEL: RACStruct.endIndex.getter
365+
// CHECK-NEXT: sil hidden @{{.*}}endIndexSivg
366+
// CHECK-NEXT: bb0
367+
// CHECK-NEXT: %1 = integer_literal $Builtin.Int{{.*}}, 27
368+
// CHECK-NEXT: %2 = struct $Int (%1 : $Builtin.Int{{.*}})
369+
// CHECK-NEXT: return %2 : $Int
370+
var endIndex: Int { return end }
371+
372+
subscript(_ bitIndex: Int) -> Bool {
373+
get { return false }
374+
set { }
375+
}
376+
}
377+
378+
extension RACStruct : RandomAccessCollection {}

0 commit comments

Comments
 (0)