SILInliner: Critical edges have no code size impact.

I think unconditional branches should be free, period. They will
mostly be removed during LLVM code gen. However, fixing this requires
signficant adjustments to inlining heuristics to avoid microbenchmark
regressions at -Osize. So, instead I am just making this less
sensitive to critical edges for the sake of pipeline stability.
This commit is contained in:
Andrew Trick
2018-09-26 16:26:32 -07:00
parent d1bfe027c0
commit d82e0ff781
3 changed files with 31 additions and 21 deletions

View File

@@ -802,10 +802,12 @@ static int getThreadingCost(SILInstruction *I) {
return 0; return 0;
} }
static int maxBranchRecursionDepth = 6;
/// couldSimplifyUsers - Check to see if any simplifications are possible if /// couldSimplifyUsers - Check to see if any simplifications are possible if
/// "Val" is substituted for BBArg. If so, return true, if nothing obvious /// "Val" is substituted for BBArg. If so, return true, if nothing obvious
/// is possible, return false. /// is possible, return false.
static bool couldSimplifyEnumUsers(SILArgument *BBArg, int Budget) { static bool couldSimplifyEnumUsers(SILArgument *BBArg, int Budget,
int recursionDepth = 0) {
SILBasicBlock *BB = BBArg->getParent(); SILBasicBlock *BB = BBArg->getParent();
int BudgetForBranch = 100; int BudgetForBranch = 100;
@@ -833,6 +835,9 @@ static bool couldSimplifyEnumUsers(SILArgument *BBArg, int Budget) {
} }
if (auto *BI = dyn_cast<BranchInst>(User)) { if (auto *BI = dyn_cast<BranchInst>(User)) {
if (recursionDepth >= maxBranchRecursionDepth) {
return false;
}
if (BudgetForBranch > Budget) { if (BudgetForBranch > Budget) {
BudgetForBranch = Budget; BudgetForBranch = Budget;
for (SILInstruction &I : *BB) { for (SILInstruction &I : *BB) {
@@ -844,7 +849,8 @@ static bool couldSimplifyEnumUsers(SILArgument *BBArg, int Budget) {
if (BudgetForBranch > 0) { if (BudgetForBranch > 0) {
SILBasicBlock *DestBB = BI->getDestBB(); SILBasicBlock *DestBB = BI->getDestBB();
unsigned OpIdx = UI->getOperandNumber(); unsigned OpIdx = UI->getOperandNumber();
if (couldSimplifyEnumUsers(DestBB->getArgument(OpIdx), BudgetForBranch)) if (couldSimplifyEnumUsers(DestBB->getArgument(OpIdx), BudgetForBranch,
recursionDepth + 1))
return true; return true;
} }
} }

View File

@@ -790,6 +790,11 @@ InlineCost swift::instructionInlineCost(SILInstruction &I) {
case SILInstructionKind::GetAsyncContinuationInst: case SILInstructionKind::GetAsyncContinuationInst:
return InlineCost::Free; return InlineCost::Free;
// Unconditional branch is free in empty blocks.
case SILInstructionKind::BranchInst:
return (I.getIterator() == I.getParent()->begin())
? InlineCost::Free : InlineCost::Expensive;
case SILInstructionKind::AbortApplyInst: case SILInstructionKind::AbortApplyInst:
case SILInstructionKind::ApplyInst: case SILInstructionKind::ApplyInst:
case SILInstructionKind::TryApplyInst: case SILInstructionKind::TryApplyInst:
@@ -804,7 +809,6 @@ InlineCost swift::instructionInlineCost(SILInstruction &I) {
case SILInstructionKind::WitnessMethodInst: case SILInstructionKind::WitnessMethodInst:
case SILInstructionKind::AssignInst: case SILInstructionKind::AssignInst:
case SILInstructionKind::AssignByWrapperInst: case SILInstructionKind::AssignByWrapperInst:
case SILInstructionKind::BranchInst:
case SILInstructionKind::CheckedCastBranchInst: case SILInstructionKind::CheckedCastBranchInst:
case SILInstructionKind::CheckedCastValueBranchInst: case SILInstructionKind::CheckedCastValueBranchInst:
case SILInstructionKind::CheckedCastAddrBranchInst: case SILInstructionKind::CheckedCastAddrBranchInst:

View File

@@ -19,10 +19,10 @@ bb0:
} }
// CHECK-LABEL: SPA @test_if_then_else // CHECK-LABEL: SPA @test_if_then_else
// CHECK-NEXT: bb0: length=1+0, d-entry=0, d-exit=2 // CHECK-NEXT: bb0: length=1+0, d-entry=0, d-exit=1
// CHECK-NEXT: bb1: length=3+0, d-entry=1, d-exit=3 // CHECK-NEXT: bb1: length=3+0, d-entry=1, d-exit=3
// CHECK-NEXT: bb2: length=1+0, d-entry=1, d-exit=1 // CHECK-NEXT: bb2: length=0+0, d-entry=1, d-exit=0
// CHECK-NEXT: bb3: length=0+0, d-entry=2, d-exit=0 // CHECK-NEXT: bb3: length=0+0, d-entry=1, d-exit=0
sil @test_if_then_else : $@convention(thin) () -> () { sil @test_if_then_else : $@convention(thin) () -> () {
bb0: bb0:
@@ -42,9 +42,9 @@ bb3:
} }
// CHECK-LABEL: SPA @test_simple_loop // CHECK-LABEL: SPA @test_simple_loop
// CHECK-NEXT: bb0: length=1+0, d-entry=0, d-exit=34 // CHECK-NEXT: bb0: length=0+0, d-entry=0, d-exit=33
// CHECK-NEXT: bb1: length=3+30, d-entry=1, d-exit=33 // CHECK-NEXT: bb1: length=3+30, d-entry=0, d-exit=33
// CHECK-NEXT: bb2: length=0+0, d-entry=34, d-exit=0 // CHECK-NEXT: bb2: length=0+0, d-entry=33, d-exit=0
// CHECK-NEXT: Loop bb1: // CHECK-NEXT: Loop bb1:
// CHECK-NEXT: bb1: length=3+0, d-entry=0, d-exit=3 // CHECK-NEXT: bb1: length=3+0, d-entry=0, d-exit=3
@@ -64,9 +64,9 @@ bb2:
// CHECK-LABEL: SPA @test_loop_with_bypass_edge // CHECK-LABEL: SPA @test_loop_with_bypass_edge
// CHECK-NEXT: bb0: length=1+30, d-entry=0, d-exit=31 // CHECK-NEXT: bb0: length=1+30, d-entry=0, d-exit=31
// CHECK-NEXT: bb1: length=1+0, d-entry=31, d-exit=5 // CHECK-NEXT: bb1: length=0+0, d-entry=31, d-exit=3
// CHECK-NEXT: bb2: length=3+0, d-entry=32, d-exit=4 // CHECK-NEXT: bb2: length=3+0, d-entry=31, d-exit=3
// CHECK-NEXT: bb3: length=1+0, d-entry=35, d-exit=1 // CHECK-NEXT: bb3: length=0+0, d-entry=34, d-exit=0
// CHECK-NEXT: bb4: length=0+0, d-entry=31, d-exit=0 // CHECK-NEXT: bb4: length=0+0, d-entry=31, d-exit=0
// CHECK-NEXT: Loop bb2: // CHECK-NEXT: Loop bb2:
// CHECK-NEXT: bb2: length=3+0, d-entry=0, d-exit=3 // CHECK-NEXT: bb2: length=3+0, d-entry=0, d-exit=3
@@ -93,12 +93,12 @@ bb4:
// CHECK-LABEL: SPA @test_nested_loops // CHECK-LABEL: SPA @test_nested_loops
// CHECK-NEXT: bb0: length=1+40, d-entry=0, d-exit=41 // CHECK-NEXT: bb0: length=1+40, d-entry=0, d-exit=41
// CHECK-NEXT: bb1: length=1+0, d-entry=41, d-exit=6 // CHECK-NEXT: bb1: length=0+0, d-entry=41, d-exit=4
// CHECK-NEXT: bb2: length=1+0, d-entry=42, d-exit=5 // CHECK-NEXT: bb2: length=1+0, d-entry=41, d-exit=4
// CHECK-NEXT: bb3: length=3+0, d-entry=43, d-exit=5 // CHECK-NEXT: bb3: length=3+0, d-entry=42, d-exit=4
// CHECK-NEXT: bb4: length=2+0, d-entry=43, d-exit=4 // CHECK-NEXT: bb4: length=2+0, d-entry=42, d-exit=3
// CHECK-NEXT: bb5: length=1+0, d-entry=45, d-exit=2 // CHECK-NEXT: bb5: length=1+0, d-entry=44, d-exit=1
// CHECK-NEXT: bb6: length=1+0, d-entry=46, d-exit=1 // CHECK-NEXT: bb6: length=0+0, d-entry=45, d-exit=0
// CHECK-NEXT: bb7: length=0+0, d-entry=41, d-exit=0 // CHECK-NEXT: bb7: length=0+0, d-entry=41, d-exit=0
// CHECK-NEXT: Loop bb2: // CHECK-NEXT: Loop bb2:
// CHECK-NEXT: bb2: length=1+0, d-entry=0, d-exit=4 // CHECK-NEXT: bb2: length=1+0, d-entry=0, d-exit=4
@@ -146,9 +146,9 @@ bb0:
} }
// CHECK-LABEL: SPA @test_call_of_noreturn_in_loop // CHECK-LABEL: SPA @test_call_of_noreturn_in_loop
// CHECK-NEXT: bb0: length=1+0, d-entry=0, d-exit=133 // CHECK-NEXT: bb0: length=0+0, d-entry=0, d-exit=132
// CHECK-NEXT: bb1: length=12+120, d-entry=1, d-exit=132 // CHECK-NEXT: bb1: length=12+120, d-entry=0, d-exit=132
// CHECK-NEXT: bb2: length=0+0, d-entry=133, d-exit=0 // CHECK-NEXT: bb2: length=0+0, d-entry=132, d-exit=0
// CHECK-NEXT: Loop bb1: // CHECK-NEXT: Loop bb1:
// CHECK-NEXT: bb1: length=12+0, d-entry=0, d-exit=12 // CHECK-NEXT: bb1: length=12+0, d-entry=0, d-exit=12
sil @test_call_of_noreturn_in_loop : $@convention(thin) () -> () { sil @test_call_of_noreturn_in_loop : $@convention(thin) () -> () {