/// Track uses of the arguments, recording in the summary any accesses /// started by a begin_access and any flows of the arguments to other /// functions. void AccessSummaryAnalysis::processArgument(FunctionInfo *info, SILFunctionArgument *argument, ArgumentSummary &summary, FunctionOrder &order) { unsigned argumentIndex = argument->getIndex(); // Use a worklist to track argument uses to be processed. llvm::SmallVector<Operand *, 32> worklist; // Start by adding the immediate uses of the argument to the worklist. worklist.append(argument->use_begin(), argument->use_end()); // Iterate to follow uses of the arguments. while (!worklist.empty()) { Operand *operand = worklist.pop_back_val(); SILInstruction *user = operand->getUser(); switch (user->getKind()) { case ValueKind::BeginAccessInst: { auto *BAI = cast<BeginAccessInst>(user); summary.mergeWith(BAI->getAccessKind(), BAI->getLoc()); // We don't add the users of the begin_access to the worklist because // even if these users eventually begin an access to the address // or a projection from it, that access can't begin more exclusive // access than this access -- otherwise it will be diagnosed // elsewhere. break; } case ValueKind::EndUnpairedAccessInst: // Don't diagnose unpaired access statically. assert(cast<EndUnpairedAccessInst>(user)->getEnforcement() == SILAccessEnforcement::Dynamic); break; case ValueKind::StructElementAddrInst: case ValueKind::TupleElementAddrInst: // Eventually we'll summarize individual struct elements separately. // For now an access to a part of the struct is treated as an access // to the whole struct. worklist.append(user->use_begin(), user->use_end()); break; case ValueKind::DebugValueAddrInst: case ValueKind::AddressToPointerInst: // Ignore these uses, they don't affect formal accesses. break; case ValueKind::PartialApplyInst: processPartialApply(info, argumentIndex, cast<PartialApplyInst>(user), operand, order); break; case ValueKind::ApplyInst: processFullApply(info, argumentIndex, cast<ApplyInst>(user), operand, order); break; case ValueKind::TryApplyInst: processFullApply(info, argumentIndex, cast<TryApplyInst>(user), operand, order); break; case ValueKind::CopyAddrInst: case ValueKind::ExistentialMetatypeInst: case ValueKind::ValueMetatypeInst: case ValueKind::LoadInst: case ValueKind::LoadBorrowInst: case ValueKind::EndBorrowInst: case ValueKind::OpenExistentialAddrInst: case ValueKind::ProjectBlockStorageInst: // These likely represent scenarios in which we're not generating // begin access markers. Ignore these for now. But we really should // add SIL verification to ensure all loads and stores have associated // access markers. break; default: // TODO: These requirements should be checked for in the SIL verifier. // This is an assertion rather than llvm_unreachable() because // it is likely the whitelist above for scenarios in which we'ren // not generating access markers is not comprehensive. assert(false && "Unrecognized argument use"); break; } } }
/// Track uses of the arguments, recording in the summary any accesses /// started by a begin_access and any flows of the arguments to other /// functions. void AccessSummaryAnalysis::processArgument(FunctionInfo *info, SILFunctionArgument *argument, ArgumentSummary &summary, FunctionOrder &order) { unsigned argumentIndex = argument->getIndex(); // Use a worklist to track argument uses to be processed. llvm::SmallVector<Operand *, 32> worklist; // Start by adding the immediate uses of the argument to the worklist. worklist.append(argument->use_begin(), argument->use_end()); // Iterate to follow uses of the arguments. while (!worklist.empty()) { Operand *operand = worklist.pop_back_val(); SILInstruction *user = operand->getUser(); switch (user->getKind()) { case SILInstructionKind::BeginAccessInst: { auto *BAI = cast<BeginAccessInst>(user); const IndexTrieNode *subPath = findSubPathAccessed(BAI); summary.mergeWith(BAI->getAccessKind(), BAI->getLoc(), subPath); // We don't add the users of the begin_access to the worklist because // even if these users eventually begin an access to the address // or a projection from it, that access can't begin more exclusive // access than this access -- otherwise it will be diagnosed // elsewhere. break; } case SILInstructionKind::EndUnpairedAccessInst: // Don't diagnose unpaired access statically. assert(cast<EndUnpairedAccessInst>(user)->getEnforcement() == SILAccessEnforcement::Dynamic); break; case SILInstructionKind::StructElementAddrInst: case SILInstructionKind::TupleElementAddrInst: { // Eventually we'll summarize individual struct elements separately. // For now an access to a part of the struct is treated as an access // to the whole struct. auto inst = cast<SingleValueInstruction>(user); worklist.append(inst->use_begin(), inst->use_end()); break; } case SILInstructionKind::DebugValueAddrInst: case SILInstructionKind::AddressToPointerInst: // Ignore these uses, they don't affect formal accesses. break; case SILInstructionKind::PartialApplyInst: processPartialApply(info, argumentIndex, cast<PartialApplyInst>(user), operand, order); break; case SILInstructionKind::ApplyInst: processFullApply(info, argumentIndex, cast<ApplyInst>(user), operand, order); break; case SILInstructionKind::TryApplyInst: processFullApply(info, argumentIndex, cast<TryApplyInst>(user), operand, order); break; default: // FIXME: These likely represent scenarios in which we're not generating // begin access markers. Ignore these for now. But we really should // add SIL verification to ensure all loads and stores have associated // access markers. Once SIL verification is implemented, enable the // following assert to verify that the cases handled above are // comprehensive, which guarantees that exclusivity enforcement is // complete. // assert(false && "Unrecognized argument use"); break; } } }