static void mapOperands(SILInstruction *I, const llvm::DenseMap<ValueBase *, SILValue> &ValueMap) { for (auto &Opd : I->getAllOperands()) { SILValue OrigVal = Opd.get(); ValueBase *OrigDef = OrigVal.getDef(); auto Found = ValueMap.find(OrigDef); if (Found != ValueMap.end()) { SILValue MappedVal = Found->second; unsigned ResultIdx = OrigVal.getResultNumber(); // All mapped instructions have their result number set to zero. Except // for arguments that we followed along one edge to their incoming value // on that edge. if (isa<SILArgument>(OrigDef)) ResultIdx = MappedVal.getResultNumber(); Opd.set(SILValue(MappedVal.getDef(), ResultIdx)); } } }
/// \brief Removes instructions that create the callee value if they are no /// longer necessary after inlining. static void cleanupCalleeValue(SILValue CalleeValue, ArrayRef<SILValue> CaptureArgs, ArrayRef<SILValue> FullArgs) { SmallVector<SILInstruction*, 16> InstsToDelete; for (SILValue V : FullArgs) { if (SILInstruction *I = dyn_cast<SILInstruction>(V)) if (I != CalleeValue.getDef() && isInstructionTriviallyDead(I)) InstsToDelete.push_back(I); } recursivelyDeleteTriviallyDeadInstructions(InstsToDelete, true); // Handle the case where the callee of the apply is a load instruction. if (LoadInst *LI = dyn_cast<LoadInst>(CalleeValue)) { assert(CalleeValue.getResultNumber() == 0); SILInstruction *ABI = dyn_cast<AllocBoxInst>(LI->getOperand()); assert(ABI && LI->getOperand().getResultNumber() == 1); // The load instruction must have no more uses left to erase it. if (!LI->use_empty()) return; LI->eraseFromParent(); // Look through uses of the alloc box the load is loading from to find up to // one store and up to one strong release. StoreInst *SI = nullptr; StrongReleaseInst *SRI = nullptr; for (auto UI = ABI->use_begin(), UE = ABI->use_end(); UI != UE; ++UI) { if (SI == nullptr && isa<StoreInst>(UI.getUser())) { SI = cast<StoreInst>(UI.getUser()); assert(SI->getDest() == SILValue(ABI, 1)); } else if (SRI == nullptr && isa<StrongReleaseInst>(UI.getUser())) { SRI = cast<StrongReleaseInst>(UI.getUser()); assert(SRI->getOperand() == SILValue(ABI, 0)); } else return; } // If we found a store, record its source and erase it. if (SI) { CalleeValue = SI->getSrc(); SI->eraseFromParent(); } else { CalleeValue = SILValue(); } // If we found a strong release, replace it with a strong release of the // source of the store and erase it. if (SRI) { if (CalleeValue.isValid()) SILBuilderWithScope(SRI) .emitStrongReleaseAndFold(SRI->getLoc(), CalleeValue); SRI->eraseFromParent(); } assert(ABI->use_empty()); ABI->eraseFromParent(); if (!CalleeValue.isValid()) return; } if (auto *PAI = dyn_cast<PartialApplyInst>(CalleeValue)) { assert(CalleeValue.getResultNumber() == 0); SILValue Callee = PAI->getCallee(); if (!tryDeleteDeadClosure(PAI)) return; CalleeValue = Callee; } if (auto *TTTFI = dyn_cast<ThinToThickFunctionInst>(CalleeValue)) { assert(CalleeValue.getResultNumber() == 0); SILValue Callee = TTTFI->getCallee(); if (!tryDeleteDeadClosure(TTTFI)) return; CalleeValue = Callee; } if (FunctionRefInst *FRI = dyn_cast<FunctionRefInst>(CalleeValue)) { assert(CalleeValue.getResultNumber() == 0); if (!FRI->use_empty()) return; FRI->eraseFromParent(); } }
/// \brief Returns the callee SILFunction called at a call site, in the case /// that the call is transparent (as in, both that the call is marked /// with the transparent flag and that callee function is actually transparently /// determinable from the SIL) or nullptr otherwise. This assumes that the SIL /// is already in SSA form. /// /// In the case that a non-null value is returned, FullArgs contains effective /// argument operands for the callee function. static SILFunction * getCalleeFunction(FullApplySite AI, bool &IsThick, SmallVectorImpl<SILValue>& CaptureArgs, SmallVectorImpl<SILValue>& FullArgs, PartialApplyInst *&PartialApply, SILModule::LinkingMode Mode) { IsThick = false; PartialApply = nullptr; CaptureArgs.clear(); FullArgs.clear(); for (const auto &Arg : AI.getArguments()) FullArgs.push_back(Arg); SILValue CalleeValue = AI.getCallee(); if (LoadInst *LI = dyn_cast<LoadInst>(CalleeValue)) { assert(CalleeValue.getResultNumber() == 0); // Conservatively only see through alloc_box; we assume this pass is run // immediately after SILGen SILInstruction *ABI = dyn_cast<AllocBoxInst>(LI->getOperand()); if (!ABI) return nullptr; assert(LI->getOperand().getResultNumber() == 1); // Scan forward from the alloc box to find the first store, which // (conservatively) must be in the same basic block as the alloc box StoreInst *SI = nullptr; for (auto I = SILBasicBlock::iterator(ABI), E = I->getParent()->end(); I != E; ++I) { // If we find the load instruction first, then the load is loading from // a non-initialized alloc; this shouldn't really happen but I'm not // making any assumptions if (static_cast<SILInstruction*>(I) == LI) return nullptr; if ((SI = dyn_cast<StoreInst>(I)) && SI->getDest().getDef() == ABI) { // We found a store that we know dominates the load; now ensure there // are no other uses of the alloc other than loads, retains, releases // and dealloc stacks for (auto UI = ABI->use_begin(), UE = ABI->use_end(); UI != UE; ++UI) if (UI.getUser() != SI && !isa<LoadInst>(UI.getUser()) && !isa<StrongRetainInst>(UI.getUser()) && !isa<StrongReleaseInst>(UI.getUser())) return nullptr; // We can conservatively see through the store break; } } if (!SI) return nullptr; CalleeValue = SI->getSrc(); } // We are allowed to see through exactly one "partial apply" instruction or // one "thin to thick function" instructions, since those are the patterns // generated when using auto closures. if (PartialApplyInst *PAI = dyn_cast<PartialApplyInst>(CalleeValue)) { assert(CalleeValue.getResultNumber() == 0); for (const auto &Arg : PAI->getArguments()) { CaptureArgs.push_back(Arg); FullArgs.push_back(Arg); } CalleeValue = PAI->getCallee(); IsThick = true; PartialApply = PAI; } else if (ThinToThickFunctionInst *TTTFI = dyn_cast<ThinToThickFunctionInst>(CalleeValue)) { assert(CalleeValue.getResultNumber() == 0); CalleeValue = TTTFI->getOperand(); IsThick = true; } FunctionRefInst *FRI = dyn_cast<FunctionRefInst>(CalleeValue); if (!FRI) return nullptr; SILFunction *CalleeFunction = FRI->getReferencedFunction(); switch (CalleeFunction->getRepresentation()) { case SILFunctionTypeRepresentation::Thick: case SILFunctionTypeRepresentation::Thin: case SILFunctionTypeRepresentation::Method: case SILFunctionTypeRepresentation::WitnessMethod: break; case SILFunctionTypeRepresentation::CFunctionPointer: case SILFunctionTypeRepresentation::ObjCMethod: case SILFunctionTypeRepresentation::Block: return nullptr; } // If CalleeFunction is a declaration, see if we can load it. If we fail to // load it, bail. if (CalleeFunction->empty() && !AI.getModule().linkFunction(CalleeFunction, Mode)) return nullptr; return CalleeFunction; }
/// Optimize builtins which receive the same value in their first and second /// operand. static SILInstruction *optimizeBuiltinWithSameOperands(SILBuilder &Builder, BuiltinInst *I, SILCombiner *C) { // Handle all builtins which can be optimized. // We have to take special care about floating point operations because of // potential NaN values. E.g. ordered equal FCMP_OEQ(Nan, Nan) is not true. switch (I->getBuiltinInfo().ID) { // Replace the uses with one of the (identical) operands. case BuiltinValueKind::And: case BuiltinValueKind::Or: { // We cannot just _return_ the operand because it is not necessarily an // instruction. It can be an argument. SILValue Op = I->getOperand(0); C->replaceInstUsesWith(*I, Op.getDef(), 0, Op.getResultNumber()); break; } // Return 0 or false. case BuiltinValueKind::Sub: case BuiltinValueKind::SRem: case BuiltinValueKind::URem: case BuiltinValueKind::Xor: case BuiltinValueKind::ICMP_NE: case BuiltinValueKind::ICMP_SLT: case BuiltinValueKind::ICMP_SGT: case BuiltinValueKind::ICMP_ULT: case BuiltinValueKind::ICMP_UGT: case BuiltinValueKind::FCMP_ONE: if (auto Ty = I->getType().getAs<BuiltinIntegerType>()) { // FIXME: Should also use SILBuilderWithScope? return Builder.createIntegerLiteral(I->getLoc(), I->getType(), APInt(Ty->getGreatestWidth(), 0)); } break; // Return 1 or true. case BuiltinValueKind::ICMP_EQ: case BuiltinValueKind::ICMP_SLE: case BuiltinValueKind::ICMP_SGE: case BuiltinValueKind::ICMP_ULE: case BuiltinValueKind::ICMP_UGE: case BuiltinValueKind::FCMP_UEQ: case BuiltinValueKind::FCMP_UGE: case BuiltinValueKind::FCMP_ULE: case BuiltinValueKind::SDiv: case BuiltinValueKind::UDiv: if (auto Ty = I->getType().getAs<BuiltinIntegerType>()) { // FIXME: Should also use SILBuilderWithScope? return Builder.createIntegerLiteral(I->getLoc(), I->getType(), APInt(Ty->getGreatestWidth(), 1)); } break; // Return 0 in a tuple. case BuiltinValueKind::SSubOver: case BuiltinValueKind::USubOver: { SILType Ty = I->getType(); SILType IntTy = Ty.getTupleElementType(0); SILType BoolTy = Ty.getTupleElementType(1); SILBuilderWithScope B(I); SILValue Elements[] = { B.createIntegerLiteral(I->getLoc(), IntTy, /* Result */ 0), B.createIntegerLiteral(I->getLoc(), BoolTy, /* Overflow */ 0) }; return B.createTuple(I->getLoc(), Ty, Elements); } default: break; } return nullptr; }