|
35 | 35 | #include "swift/SILOptimizer/Analysis/ArraySemantic.h"
|
36 | 36 | #include "swift/SILOptimizer/Analysis/BasicCalleeAnalysis.h"
|
37 | 37 | #include "swift/SILOptimizer/Analysis/DominanceAnalysis.h"
|
| 38 | +#include "swift/SILOptimizer/Analysis/DestructorAnalysis.h" |
38 | 39 | #include "swift/SILOptimizer/OptimizerBridging.h"
|
39 | 40 | #include "swift/SILOptimizer/Utils/CFGOptUtils.h"
|
40 | 41 | #include "swift/SILOptimizer/Utils/DebugOptUtils.h"
|
@@ -2470,3 +2471,130 @@ SILValue swift::getInitOfTemporaryAllocStack(AllocStackInst *asi) {
|
2470 | 2471 | return findRootValueForTupleTempAllocation(asi, state);
|
2471 | 2472 | return findRootValueForNonTupleTempAllocation(asi, state);
|
2472 | 2473 | }
|
| 2474 | + |
| 2475 | +SILType getTypeOfLoadOfArrayOperandStorage(SILValue val) { |
| 2476 | + // The projection should look something like this: |
| 2477 | + // %29 = struct_element_addr %28 : $*Array<UInt8>, #Array._buffer |
| 2478 | + // %30 = struct_element_addr %29 : $*_ArrayBuffer<UInt8>, #_ArrayBuffer._storage |
| 2479 | + // %31 = struct_element_addr %30 : $*_BridgeStorage<__ContiguousArrayStorageBase>, #_BridgeStorage.rawValue |
| 2480 | + // %32 = load %31 : $*Builtin.BridgeObject |
| 2481 | + |
| 2482 | + // We can strip casts and init_existential_ref leading to a load. |
| 2483 | + if (auto initExistRef = dyn_cast<InitExistentialRefInst>(val)) |
| 2484 | + val = initExistRef->getOperand(); |
| 2485 | + auto ld = dyn_cast<LoadInst>(stripCasts(val)); |
| 2486 | + if (!ld) |
| 2487 | + return SILType(); |
| 2488 | + |
| 2489 | + auto opd = ld->getOperand(); |
| 2490 | + auto opdTy = opd->getType(); |
| 2491 | + if (opdTy.getObjectType() != |
| 2492 | + SILType::getBridgeObjectType(opdTy.getASTContext())) |
| 2493 | + return SILType(); |
| 2494 | + |
| 2495 | + auto bridgedStoragePrj = dyn_cast<StructElementAddrInst>(opd); |
| 2496 | + if (!bridgedStoragePrj) |
| 2497 | + return SILType(); |
| 2498 | + |
| 2499 | + auto arrayBufferStoragePrj = |
| 2500 | + dyn_cast<StructElementAddrInst>(bridgedStoragePrj->getOperand()); |
| 2501 | + if (!arrayBufferStoragePrj) |
| 2502 | + return SILType(); |
| 2503 | + |
| 2504 | + // If successfull return _ArrayBuffer<UInt8>. |
| 2505 | + return arrayBufferStoragePrj->getOperand()->getType().getObjectType(); |
| 2506 | +} |
| 2507 | + |
| 2508 | +static bool isBoxTypeWithoutSideEffectsOnRelease(SILFunction *f, |
| 2509 | + DestructorAnalysis *DA, |
| 2510 | + SILType ty) { |
| 2511 | + auto silBoxedTy = ty.getSILBoxFieldType(f); |
| 2512 | + if (silBoxedTy && !DA->mayStoreToMemoryOnDestruction(silBoxedTy)) |
| 2513 | + return true; |
| 2514 | + return false; |
| 2515 | +} |
| 2516 | + |
| 2517 | + |
| 2518 | +static bool isReleaseOfClosureWithoutSideffects(SILFunction *f, |
| 2519 | + DestructorAnalysis *DA, |
| 2520 | + SILValue opd) { |
| 2521 | + auto fnTy = dyn_cast<SILFunctionType>(opd->getType().getASTType()); |
| 2522 | + if (!fnTy) |
| 2523 | + return false; |
| 2524 | + |
| 2525 | + if (fnTy->isNoEscape() && |
| 2526 | + fnTy->getRepresentation() == SILFunctionType::Representation::Thick) |
| 2527 | + return true; |
| 2528 | + |
| 2529 | + auto pa = dyn_cast<PartialApplyInst>(lookThroughOwnershipInsts(opd)); |
| 2530 | + if (!pa) |
| 2531 | + return false; |
| 2532 | + |
| 2533 | + // Check that all captured argument types are "trivial". |
| 2534 | + for (auto &opd: pa->getArgumentOperands()) { |
| 2535 | + auto OpdTy = opd.get()->getType().getObjectType(); |
| 2536 | + if (!DA->mayStoreToMemoryOnDestruction(OpdTy)) |
| 2537 | + continue; |
| 2538 | + if (isBoxTypeWithoutSideEffectsOnRelease(f, DA, OpdTy)) |
| 2539 | + continue; |
| 2540 | + return false; |
| 2541 | + } |
| 2542 | + |
| 2543 | + return true; |
| 2544 | +} |
| 2545 | + |
| 2546 | +bool swift::isDestructorSideEffectFree(SILInstruction *mayRelease, |
| 2547 | + DestructorAnalysis *DA) { |
| 2548 | + switch (mayRelease->getKind()) { |
| 2549 | + case SILInstructionKind::DestroyValueInst: |
| 2550 | + case SILInstructionKind::StrongReleaseInst: |
| 2551 | + case SILInstructionKind::ReleaseValueInst: { |
| 2552 | + auto opd = mayRelease->getOperand(0); |
| 2553 | + auto opdTy = opd->getType(); |
| 2554 | + if (!DA->mayStoreToMemoryOnDestruction(opdTy)) |
| 2555 | + return true; |
| 2556 | + |
| 2557 | + auto arrayTy = getTypeOfLoadOfArrayOperandStorage(opd); |
| 2558 | + if (arrayTy && !DA->mayStoreToMemoryOnDestruction(arrayTy)) |
| 2559 | + return true; |
| 2560 | + |
| 2561 | + if (isReleaseOfClosureWithoutSideffects(mayRelease->getFunction(), DA, opd)) |
| 2562 | + return true; |
| 2563 | + |
| 2564 | + if (isBoxTypeWithoutSideEffectsOnRelease(mayRelease->getFunction(), DA, |
| 2565 | + opdTy)) |
| 2566 | + return true; |
| 2567 | + |
| 2568 | + return false; |
| 2569 | + } |
| 2570 | + case SILInstructionKind::BuiltinInst: { |
| 2571 | + auto *builtin = cast<BuiltinInst>(mayRelease); |
| 2572 | + switch (builtin->getBuiltinInfo().ID) { |
| 2573 | + case BuiltinValueKind::CopyArray: |
| 2574 | + case BuiltinValueKind::TakeArrayNoAlias: |
| 2575 | + case BuiltinValueKind::TakeArrayFrontToBack: |
| 2576 | + case BuiltinValueKind::TakeArrayBackToFront: |
| 2577 | + return true; // nothing is released, harmless regardless of type |
| 2578 | + case BuiltinValueKind::AssignCopyArrayNoAlias: |
| 2579 | + case BuiltinValueKind::AssignCopyArrayFrontToBack: |
| 2580 | + case BuiltinValueKind::AssignCopyArrayBackToFront: |
| 2581 | + case BuiltinValueKind::AssignTakeArray: |
| 2582 | + case BuiltinValueKind::DestroyArray: { |
| 2583 | + SubstitutionMap substitutions = builtin->getSubstitutions(); |
| 2584 | + auto eltTy = substitutions.getReplacementTypes()[0]; |
| 2585 | + return !DA->mayStoreToMemoryOnDestruction( |
| 2586 | + builtin->getFunction()->getLoweredType(eltTy)); |
| 2587 | + // Only harmless if the array element type destruction is harmless. |
| 2588 | + } |
| 2589 | + default: |
| 2590 | + break; |
| 2591 | + } |
| 2592 | + return false; |
| 2593 | + } |
| 2594 | + // Unhandled instruction. |
| 2595 | + default: |
| 2596 | + return false; |
| 2597 | + } |
| 2598 | + |
| 2599 | + return false; |
| 2600 | +} |
0 commit comments