Skip to content

Commit b89f58d

Browse files
committed
SILCombine: replace Array.capacity with 0 if it's the empty array singleton
We already do that for Array.count. Now add Array.capacity.
1 parent 5090603 commit b89f58d

File tree

2 files changed

+36
-9
lines changed

2 files changed

+36
-9
lines changed

lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -804,6 +804,18 @@ SILInstruction *SILCombiner::optimizeLoadFromStringLiteral(LoadInst *LI) {
804804
return Builder.createIntegerLiteral(LI->getLoc(), LI->getType(), str[index]);
805805
}
806806

807+
static bool isShiftRightByAtLeastOne(SILInstruction *inst) {
808+
auto *bi = dyn_cast<BuiltinInst>(inst);
809+
if (!bi)
810+
return false;
811+
if (bi->getBuiltinInfo().ID != BuiltinValueKind::LShr)
812+
return false;
813+
auto *shiftVal = dyn_cast<IntegerLiteralInst>(bi->getArguments()[1]);
814+
if (!shiftVal)
815+
return false;
816+
return shiftVal->getValue().isStrictlyPositive();
817+
}
818+
807819
/// Returns true if \p LI loads a zero integer from the empty Array, Dictionary
808820
/// or Set singleton.
809821
static bool isZeroLoadFromEmptyCollection(SingleValueInstruction *LI) {
@@ -826,15 +838,23 @@ static bool isZeroLoadFromEmptyCollection(SingleValueInstruction *LI) {
826838
}
827839
case ValueKind::StructElementAddrInst: {
828840
auto *SEA = cast<StructElementAddrInst>(addr);
829-
// For Array, we only support "count". The value of "capacityAndFlags"
830-
// is not defined in the ABI and could change in another version of the
831-
// runtime (the capacity must be 0, but the flags may be not 0).
832-
if (SEA->getStructDecl()->getName().is("_SwiftArrayBodyStorage") &&
833-
!SEA->getField()->getName().is("count")) {
834-
return false;
835-
}
836841
addr = SEA->getOperand();
837-
break;
842+
if (!SEA->getStructDecl()->getName().is("_SwiftArrayBodyStorage"))
843+
break;
844+
if (SEA->getField()->getName().is("count"))
845+
break;
846+
// For Array, the value of `capacityAndFlags` has only a zero capacity
847+
// but not necessarily a zero flag (in fact, the flag is 1).
848+
// Therefore only replace `capacityAndFlags` with zero if the flag is
849+
// masked out by a right-shift of 1.
850+
if (SEA->getField()->getName().is("_capacityAndFlags")) {
851+
for (Operand *loadUse : LI->getUses()) {
852+
if (!isShiftRightByAtLeastOne(loadUse->getUser()))
853+
return false;
854+
}
855+
break;
856+
}
857+
return false;
838858
}
839859
case ValueKind::RefElementAddrInst: {
840860
auto *REA = cast<RefElementAddrInst>(addr);
@@ -858,6 +878,13 @@ static bool isZeroLoadFromEmptyCollection(SingleValueInstruction *LI) {
858878
case ValueKind::EndCOWMutationInst:
859879
addr = cast<SingleValueInstruction>(addr)->getOperand(0);
860880
break;
881+
case ValueKind::MultipleValueInstructionResult:
882+
if (auto *bci = dyn_cast<BeginCOWMutationInst>(
883+
addr->getDefiningInstruction())) {
884+
addr = bci->getOperand();
885+
break;
886+
}
887+
return false;
861888
default:
862889
return false;
863890
}

test/SILOptimizer/empty_collection_count.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
// CHECK: return [[I]]
1414
public func testArray() -> Int {
1515
let d = Array<Int>()
16-
return d.count
16+
return d.count + d.capacity
1717
}
1818

1919
// CHECK-LABEL: sil @{{.*}}testDictionary

0 commit comments

Comments
 (0)