Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

SIL Optimizations - AllocBoxToStack

688 views

Published on

iOSDC 2018

Published in: Technology
  • Be the first to comment

SIL Optimizations - AllocBoxToStack

  1. 1. SIL Optimizations AllocBoxToStack SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  2. 2. Hi, I'm Yusuke @kitasuke SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  3. 3. Why SIL?  SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  4. 4. Why SIL? SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  5. 5. Why SIL? → Better idea of Swift type system ! SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  6. 6. Why SIL? → Better idea of Swift type system ! → Optimizations magic "✨ SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  7. 7. Why SIL? → Better idea of Swift type system ! → Optimizations magic "✨ → Just for fun $ SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  8. 8. SIL   SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  9. 9. Swift Intermediate LanguageSIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  10. 10. SIL is a language specific Intermediate Representation SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  11. 11. Swift  SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  12. 12. Swift Compiler SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  13. 13. Swift Compiler SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  14. 14. Swift Compiler SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  15. 15. SIL SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  16. 16. raw SIL SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  17. 17. canonical SIL SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  18. 18. Objective-C  SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  19. 19. Clang    SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  20. 20. Clang SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  21. 21. SIL   SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  22. 22. Optimizations SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  23. 23. Optimization Passes → CapturePromotion → AllocBoxToStack → MandatoryInlining → DeadCodeElimination → Mem2Reg ... SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  24. 24. AllocBoxToStack SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  25. 25. Stack Promotion of Box Objects SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  26. 26. Stack vs Heap SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  27. 27. Stack SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  28. 28. Stack → Very fast SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  29. 29. Stack → Very fast → No explicit memory management SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  30. 30. Stack → Very fast → No explicit memory management → Size limits SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  31. 31. Heap SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  32. 32. Heap → Slow SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  33. 33. Heap → Slow → Explicit memory management SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  34. 34. Heap → Slow → Explicit memory management → No size limits SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  35. 35. Stack vs Heap Stack Heap Value types Reference types Pointers to reference type SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  36. 36. How AllocBoxToStack works? SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  37. 37. alloc_box ➡ alloc_stack SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  38. 38. stack.swift func number() -> Int { var x: Int x = 1 return x } SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  39. 39. raw SIL $swiftc -emit-silgen stack.swift > stack.sil SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  40. 40. stack.sil %0 = alloc_box ${ var Int }, var, name "x" %1 = mark_uninitialized [var] %0 : ${ var Int } %2 = project_box %1 : ${ var Int }, 0 ... %10 = begin_access [read] [unknown] %2 : $*Int %11 = load [trivial] %10 : $*Int end_access %10 : $*Int destroy_value %1 : ${ var Int } return %11 : $Int SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  41. 41. stack.sil %0 = alloc_box ${ var Int }, var, name "x" %1 = mark_uninitialized [var] %0 : ${ var Int } %2 = project_box %1 : ${ var Int }, 0 ... %10 = begin_access [read] [unknown] %2 : $*Int %11 = load [trivial] %10 : $*Int end_access %10 : $*Int destroy_value %1 : ${ var Int } return %11 : $Int SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  42. 42. canonical SIL $swiftc -emit-sil stack.swift > stack.sil SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  43. 43. stack.sil %0 = alloc_stack $Int, var, name "x" %1 = integer_literal $Builtin.Int64, 1 %2 = struct $Int (%1 : $Builtin.Int64) ... return %2 : $Int SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  44. 44. stack.sil %0 = alloc_stack $Int, var, name "x" %1 = integer_literal $Builtin.Int64, 1 %2 = struct $Int (%1 : $Builtin.Int64) ... return %2 : $Int SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  45. 45. alloc_box vs alloc_stack SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  46. 46. alloc_box alloc_box allocates a reference counted box on heap. SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  47. 47. alloc_stack alloc_stack allocates a value on stack. All allocations must be deallocated prior to returning from a function. SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  48. 48. Stack Promotion of Box Objects SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  49. 49. alloc_box ➡ alloc_stack SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  50. 50. alloc_box ➡ alloc_box SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  51. 51. box.swift func closure(_ completion: @escaping () -> Void) { completion() } func number() -> Int { var i: Int i = 0 closure { i = 10 } return i } SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  52. 52. box.swift func closure(_ completion: @escaping () -> Void) { completion() } func number() -> Int { var i: Int i = 0 closure { i = 10 } return i } SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  53. 53. box.swift func closure(_ completion: @escaping () -> Void) { completion() } func number() -> Int { var i: Int i = 0 closure { i = 10 } return i } SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  54. 54. raw SIL $swiftc -emit-silgen box.swift > box.sil SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  55. 55. box.sil %0 = alloc_box ${ var Int }, var, name "i" %1 = mark_uninitialized [var] %0 : ${ var Int } %2 = project_box %1 : ${ var Int }, 0 ... %16 = begin_access [read] [unknown] %2 : $*Int %17 = load [trivial] %16 : $*Int end_access %16 : $*Int destroy_value %1 : ${ var Int } return %17 : $Int SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  56. 56. box.sil %0 = alloc_box ${ var Int }, var, name "i" %1 = mark_uninitialized [var] %0 : ${ var Int } %2 = project_box %1 : ${ var Int }, 0 ... %16 = begin_access [read] [unknown] %2 : $*Int %17 = load [trivial] %16 : $*Int end_access %16 : $*Int destroy_value %1 : ${ var Int } return %17 : $Int SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  57. 57. canonical SIL $swiftc -emit-sil box.swift > box.sil SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  58. 58. box.sil %0 = alloc_box ${ var Int }, var, name "i" %1 = project_box %0 : ${ var Int }, 0 %2 = integer_literal $Builtin.Int64, 0 %3 = struct $Int (%2 : $Builtin.Int64) ... %12 = begin_access [read] [dynamic] %1 : $*Int %13 = load %12 : $*Int end_access %12 : $*Int strong_release %0 : ${ var Int } return %13 : $Int SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  59. 59. box.sil %0 = alloc_box ${ var Int }, var, name "i" %1 = project_box %0 : ${ var Int }, 0 %2 = integer_literal $Builtin.Int64, 0 %3 = struct $Int (%2 : $Builtin.Int64) ... %12 = begin_access [read] [dynamic] %1 : $*Int %13 = load %12 : $*Int end_access %12 : $*Int strong_release %0 : ${ var Int } return %13 : $Int SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  60. 60. How can promote alloc_box? SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  61. 61. class AllocBoxToStack : public SILFunctionTransform { void run() override { ... AllocBoxToStackState pass(this); for (auto &BB : *getFunction()) { for (auto &I : BB) if (auto *ABI = dyn_cast<AllocBoxInst>(&I)) if (canPromoteAllocBox(ABI, pass.PromotedOperands)) pass.Promotable.push_back(ABI); } if (!pass.Promotable.empty()) { auto Count = rewritePromotedBoxes(pass); ... } ... } }; SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  62. 62. class AllocBoxToStack : public SILFunctionTransform { void run() override { ... AllocBoxToStackState pass(this); for (auto &BB : *getFunction()) { for (auto &I : BB) if (auto *ABI = dyn_cast<AllocBoxInst>(&I)) if (canPromoteAllocBox(ABI, pass.PromotedOperands)) pass.Promotable.push_back(ABI); } if (!pass.Promotable.empty()) { auto Count = rewritePromotedBoxes(pass); ... } ... } }; SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  63. 63. class AllocBoxToStack : public SILFunctionTransform { void run() override { ... AllocBoxToStackState pass(this); for (auto &BB : *getFunction()) { for (auto &I : BB) if (auto *ABI = dyn_cast<AllocBoxInst>(&I)) if (canPromoteAllocBox(ABI, pass.PromotedOperands)) pass.Promotable.push_back(ABI); } if (!pass.Promotable.empty()) { auto Count = rewritePromotedBoxes(pass); ... } ... } }; SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  64. 64. class AllocBoxToStack : public SILFunctionTransform { void run() override { ... AllocBoxToStackState pass(this); for (auto &BB : *getFunction()) { for (auto &I : BB) if (auto *ABI = dyn_cast<AllocBoxInst>(&I)) if (canPromoteAllocBox(ABI, pass.PromotedOperands)) pass.Promotable.push_back(ABI); } if (!pass.Promotable.empty()) { auto Count = rewritePromotedBoxes(pass); ... } ... } }; SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  65. 65. static SILInstruction * findUnexpectedBoxUse(SILValue Box, bool examinePartialApply, bool inAppliedFunction, llvm::SmallVectorImpl<Operand *> &PromotedOperands) { llvm::SmallVector<Operand *, 4> LocalPromotedOperands; llvm::SmallVector<Operand *, 32> Worklist(Box->use_begin(), Box->use_end()); while (!Worklist.empty()) { auto *Op = Worklist.pop_back_val(); auto *User = Op->getUser(); if (isa<StrongRetainInst>(User) || isa<StrongReleaseInst>(User) || isa<ProjectBoxInst>(User) || isa<DestroyValueInst>(User) || (!inAppliedFunction && isa<DeallocBoxInst>(User))) continue; if (isa<MarkUninitializedInst>(User) || isa<CopyValueInst>(User)) { copy(cast<SingleValueInstruction>(User)->getUses(), std::back_inserter(Worklist)); continue; } if (auto *PAI = dyn_cast<PartialApplyInst>(User)) if (examinePartialApply && checkPartialApplyBody(Op) && !partialApplyEscapes(PAI, /* examineApply = */ true)) { LocalPromotedOperands.push_back(Op); continue; } return User; } ... } SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  66. 66. static SILInstruction * findUnexpectedBoxUse(SILValue Box, bool examinePartialApply, bool inAppliedFunction, llvm::SmallVectorImpl<Operand *> &PromotedOperands) { llvm::SmallVector<Operand *, 4> LocalPromotedOperands; llvm::SmallVector<Operand *, 32> Worklist(Box->use_begin(), Box->use_end()); while (!Worklist.empty()) { auto *Op = Worklist.pop_back_val(); auto *User = Op->getUser(); if (isa<StrongRetainInst>(User) || isa<StrongReleaseInst>(User) || isa<ProjectBoxInst>(User) || isa<DestroyValueInst>(User) || (!inAppliedFunction && isa<DeallocBoxInst>(User))) continue; if (isa<MarkUninitializedInst>(User) || isa<CopyValueInst>(User)) { copy(cast<SingleValueInstruction>(User)->getUses(), std::back_inserter(Worklist)); continue; } if (auto *PAI = dyn_cast<PartialApplyInst>(User)) if (examinePartialApply && checkPartialApplyBody(Op) && !partialApplyEscapes(PAI, /* examineApply = */ true)) { LocalPromotedOperands.push_back(Op); continue; } return User; } ... } SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  67. 67. static SILInstruction * findUnexpectedBoxUse(SILValue Box, bool examinePartialApply, bool inAppliedFunction, llvm::SmallVectorImpl<Operand *> &PromotedOperands) { llvm::SmallVector<Operand *, 4> LocalPromotedOperands; llvm::SmallVector<Operand *, 32> Worklist(Box->use_begin(), Box->use_end()); while (!Worklist.empty()) { auto *Op = Worklist.pop_back_val(); auto *User = Op->getUser(); if (isa<StrongRetainInst>(User) || isa<StrongReleaseInst>(User) || isa<ProjectBoxInst>(User) || isa<DestroyValueInst>(User) || (!inAppliedFunction && isa<DeallocBoxInst>(User))) continue; if (isa<MarkUninitializedInst>(User) || isa<CopyValueInst>(User)) { copy(cast<SingleValueInstruction>(User)->getUses(), std::back_inserter(Worklist)); continue; } if (auto *PAI = dyn_cast<PartialApplyInst>(User)) if (examinePartialApply && checkPartialApplyBody(Op) && !partialApplyEscapes(PAI, /* examineApply = */ true)) { LocalPromotedOperands.push_back(Op); continue; } return User; } ... } SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  68. 68. static SILInstruction * findUnexpectedBoxUse(SILValue Box, bool examinePartialApply, bool inAppliedFunction, llvm::SmallVectorImpl<Operand *> &PromotedOperands) { llvm::SmallVector<Operand *, 4> LocalPromotedOperands; llvm::SmallVector<Operand *, 32> Worklist(Box->use_begin(), Box->use_end()); while (!Worklist.empty()) { auto *Op = Worklist.pop_back_val(); auto *User = Op->getUser(); if (isa<StrongRetainInst>(User) || isa<StrongReleaseInst>(User) || isa<ProjectBoxInst>(User) || isa<DestroyValueInst>(User) || (!inAppliedFunction && isa<DeallocBoxInst>(User))) continue; if (isa<MarkUninitializedInst>(User) || isa<CopyValueInst>(User)) { copy(cast<SingleValueInstruction>(User)->getUses(), std::back_inserter(Worklist)); continue; } if (auto *PAI = dyn_cast<PartialApplyInst>(User)) if (examinePartialApply && checkPartialApplyBody(Op) && !partialApplyEscapes(PAI, /* examineApply = */ true)) { LocalPromotedOperands.push_back(Op); continue; } return User; } ... } SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  69. 69. static SILInstruction * findUnexpectedBoxUse(SILValue Box, bool examinePartialApply, bool inAppliedFunction, llvm::SmallVectorImpl<Operand *> &PromotedOperands) { llvm::SmallVector<Operand *, 4> LocalPromotedOperands; llvm::SmallVector<Operand *, 32> Worklist(Box->use_begin(), Box->use_end()); while (!Worklist.empty()) { auto *Op = Worklist.pop_back_val(); auto *User = Op->getUser(); if (isa<StrongRetainInst>(User) || isa<StrongReleaseInst>(User) || isa<ProjectBoxInst>(User) || isa<DestroyValueInst>(User) || (!inAppliedFunction && isa<DeallocBoxInst>(User))) continue; if (isa<MarkUninitializedInst>(User) || isa<CopyValueInst>(User)) { copy(cast<SingleValueInstruction>(User)->getUses(), std::back_inserter(Worklist)); continue; } if (auto *PAI = dyn_cast<PartialApplyInst>(User)) if (examinePartialApply && checkPartialApplyBody(Op) && !partialApplyEscapes(PAI, /* examineApply = */ true)) { LocalPromotedOperands.push_back(Op); continue; } return User; } ... } SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  70. 70. Recap → Promotes @noescape values to stack → @escaping values with a reference count SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  71. 71. Optimization Flags SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  72. 72. optimized.swift func closure(_ completion: @escaping () -> Void) { completion() } func number() -> Int { var i: Int i = 0 closure { i = 10 } return i } SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  73. 73. canonical SIL with -O $swiftc -emit-sil -O optimized.swift > optimized.sil SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  74. 74. optimized.sil %0 = integer_literal $Builtin.Int64, 10 %1 = struct $Int (%0 : $Builtin.Int64) return %1 : $Int SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  75. 75. No alloc_box or alloc_stack SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  76. 76. Mem2Reg SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  77. 77. Register Promotion of Stack Allocations SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  78. 78. How can promote stack allocation? SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  79. 79. class SILMem2Reg : public SILFunctionTransform { void run() override { SILFunction *F = getFunction(); DominanceAnalysis* DA = PM->getAnalysis<DominanceAnalysis>(); bool Changed = MemoryToRegisters(*F, DA->get(F)).run(); ... } }; SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  80. 80. class SILMem2Reg : public SILFunctionTransform { void run() override { SILFunction *F = getFunction(); DominanceAnalysis* DA = PM->getAnalysis<DominanceAnalysis>(); bool Changed = MemoryToRegisters(*F, DA->get(F)).run(); ... } }; SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  81. 81. class SILMem2Reg : public SILFunctionTransform { void run() override { SILFunction *F = getFunction(); DominanceAnalysis* DA = PM->getAnalysis<DominanceAnalysis>(); bool Changed = MemoryToRegisters(*F, DA->get(F)).run(); ... } }; SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  82. 82. class SILMem2Reg : public SILFunctionTransform { void run() override { SILFunction *F = getFunction(); DominanceAnalysis* DA = PM->getAnalysis<DominanceAnalysis>(); bool Changed = MemoryToRegisters(*F, DA->get(F)).run(); ... } }; SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  83. 83. bool MemoryToRegisters::promoteSingleAllocation(AllocStackInst *alloc, DomTreeLevelMap &DomTreeLevels){ NumAllocStackFound++; bool inSingleBlock = false; if (isCaptured(alloc, inSingleBlock)) { NumAllocStackCaptured++; return false; } if (isWriteOnlyAllocation(alloc)) { eraseUsesOfInstruction(alloc); return true; } if (inSingleBlock) { removeSingleBlockAllocation(alloc); if (!alloc->use_empty()) { B.setInsertionPoint(std::next(alloc->getIterator())); B.createDeallocStack(alloc->getLoc(), alloc); } return true; } StackAllocationPromoter(alloc, DT, DomTreeLevels, B).run(); eraseUsesOfInstruction(alloc); return true; } SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  84. 84. bool MemoryToRegisters::promoteSingleAllocation(AllocStackInst *alloc, DomTreeLevelMap &DomTreeLevels){ NumAllocStackFound++; bool inSingleBlock = false; if (isCaptured(alloc, inSingleBlock)) { NumAllocStackCaptured++; return false; } if (isWriteOnlyAllocation(alloc)) { eraseUsesOfInstruction(alloc); return true; } if (inSingleBlock) { removeSingleBlockAllocation(alloc); if (!alloc->use_empty()) { B.setInsertionPoint(std::next(alloc->getIterator())); B.createDeallocStack(alloc->getLoc(), alloc); } return true; } StackAllocationPromoter(alloc, DT, DomTreeLevels, B).run(); eraseUsesOfInstruction(alloc); return true; } SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  85. 85. bool MemoryToRegisters::promoteSingleAllocation(AllocStackInst *alloc, DomTreeLevelMap &DomTreeLevels){ NumAllocStackFound++; bool inSingleBlock = false; if (isCaptured(alloc, inSingleBlock)) { NumAllocStackCaptured++; return false; } if (isWriteOnlyAllocation(alloc)) { eraseUsesOfInstruction(alloc); return true; } if (inSingleBlock) { removeSingleBlockAllocation(alloc); if (!alloc->use_empty()) { B.setInsertionPoint(std::next(alloc->getIterator())); B.createDeallocStack(alloc->getLoc(), alloc); } return true; } StackAllocationPromoter(alloc, DT, DomTreeLevels, B).run(); eraseUsesOfInstruction(alloc); return true; } SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  86. 86. bool MemoryToRegisters::promoteSingleAllocation(AllocStackInst *alloc, DomTreeLevelMap &DomTreeLevels){ NumAllocStackFound++; bool inSingleBlock = false; if (isCaptured(alloc, inSingleBlock)) { NumAllocStackCaptured++; return false; } if (isWriteOnlyAllocation(alloc)) { eraseUsesOfInstruction(alloc); return true; } if (inSingleBlock) { removeSingleBlockAllocation(alloc); if (!alloc->use_empty()) { B.setInsertionPoint(std::next(alloc->getIterator())); B.createDeallocStack(alloc->getLoc(), alloc); } return true; } StackAllocationPromoter(alloc, DT, DomTreeLevels, B).run(); eraseUsesOfInstruction(alloc); return true; } SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  87. 87. bool MemoryToRegisters::promoteSingleAllocation(AllocStackInst *alloc, DomTreeLevelMap &DomTreeLevels){ NumAllocStackFound++; bool inSingleBlock = false; if (isCaptured(alloc, inSingleBlock)) { NumAllocStackCaptured++; return false; } if (isWriteOnlyAllocation(alloc)) { eraseUsesOfInstruction(alloc); return true; } if (inSingleBlock) { removeSingleBlockAllocation(alloc); if (!alloc->use_empty()) { B.setInsertionPoint(std::next(alloc->getIterator())); B.createDeallocStack(alloc->getLoc(), alloc); } return true; } StackAllocationPromoter(alloc, DT, DomTreeLevels, B).run(); eraseUsesOfInstruction(alloc); return true; } SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  88. 88. optimized.swift func closure(_ completion: @escaping () -> Void) { completion() } func number() -> Int { var i: Int i = 0 closure { i = 10 } return i } SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  89. 89. optimized.swift func number() -> Int { return 10 } SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  90. 90. Optimization Flags → -Onone → -O → -Ounchecked → -Osize SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  91. 91. Tips for Debug → -Xllvm -sil-print-all → -Xllvm -sil-print-only-functions → -Xllvm -sil-print-before/after/around SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  92. 92. Summary → Optimize, optimize and optimize ! → Better ideas of how Swift Compiler works " → Definitely worth learning # SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  93. 93. References → var vs let in SIL → swift/docs/SIL.rst → Debugging the Swift Compiler → Swift's High-Level IR: A Case Study of Complementing LLVM IR with Language-Specific Optimization SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018
  94. 94. Thank you! SIL Optimizations - AllocBoxToStack, Yusuke Kita (@kitasuke), iOSDC 2018

×