/// Carry out the operations required for an indirect conditional cast /// using a scalar cast operation. void swift:: emitIndirectConditionalCastWithScalar(SILBuilder &B, Module *M, SILLocation loc, CastConsumptionKind consumption, SILValue src, CanType sourceType, SILValue dest, CanType targetType, SILBasicBlock *indirectSuccBB, SILBasicBlock *indirectFailBB) { assert(canUseScalarCheckedCastInstructions(B.getModule(), sourceType, targetType)); // We only need a different failure block if the cast consumption // requires us to destroy the source value. SILBasicBlock *scalarFailBB; if (!shouldDestroyOnFailure(consumption)) { scalarFailBB = indirectFailBB; } else { scalarFailBB = B.splitBlockForFallthrough(); } // We always need a different success block. SILBasicBlock *scalarSuccBB = B.splitBlockForFallthrough(); auto &srcTL = B.getModule().Types.getTypeLowering(src->getType()); // Always take; this works under an assumption that retaining the // result is equivalent to retaining the source. That means that // these casts would not be appropriate for bridging-like conversions. SILValue srcValue = srcTL.emitLoadOfCopy(B, loc, src, IsTake); SILType targetValueType = dest->getType().getObjectType(); B.createCheckedCastBranch(loc, /*exact*/ false, srcValue, targetValueType, scalarSuccBB, scalarFailBB); // Emit the success block. B.setInsertionPoint(scalarSuccBB); { auto &targetTL = B.getModule().Types.getTypeLowering(targetValueType); SILValue succValue = new (B.getModule()) SILArgument(scalarSuccBB, targetValueType); if (!shouldTakeOnSuccess(consumption)) targetTL.emitRetainValue(B, loc, succValue); targetTL.emitStoreOfCopy(B, loc, succValue, dest, IsInitialization); B.createBranch(loc, indirectSuccBB); } // Emit the failure block. if (shouldDestroyOnFailure(consumption)) { B.setInsertionPoint(scalarFailBB); srcTL.emitReleaseValue(B, loc, srcValue); B.createBranch(loc, indirectFailBB); } }
/// Given an aggregate value and an access path, extract the value indicated by /// the path. static SILValue ExtractSubElement(SILValue Val, unsigned SubElementNumber, SILBuilder &B, SILLocation Loc) { SILType ValTy = Val.getType(); // Extract tuple elements. if (auto TT = ValTy.getAs<TupleType>()) { for (unsigned EltNo : indices(TT.getElementTypes())) { // Keep track of what subelement is being referenced. SILType EltTy = ValTy.getTupleElementType(EltNo); unsigned NumSubElt = getNumSubElements(EltTy, B.getModule()); if (SubElementNumber < NumSubElt) { Val = B.emitTupleExtract(Loc, Val, EltNo, EltTy); return ExtractSubElement(Val, SubElementNumber, B, Loc); } SubElementNumber -= NumSubElt; } llvm_unreachable("Didn't find field"); } // Extract struct elements. if (auto *SD = getFullyReferenceableStruct(ValTy)) { for (auto *D : SD->getStoredProperties()) { auto fieldType = ValTy.getFieldType(D, B.getModule()); unsigned NumSubElt = getNumSubElements(fieldType, B.getModule()); if (SubElementNumber < NumSubElt) { Val = B.emitStructExtract(Loc, Val, D); return ExtractSubElement(Val, SubElementNumber, B, Loc); } SubElementNumber -= NumSubElt; } llvm_unreachable("Didn't find field"); } // Otherwise, we're down to a scalar. assert(SubElementNumber == 0 && "Miscalculation indexing subelements"); return Val; }
unsigned ArgumentDescriptor::updateOptimizedBBArgs(SILBuilder &Builder, SILBasicBlock *BB, unsigned ArgOffset) { // If this argument is completely dead, delete this argument and return // ArgOffset. if (IsDead) { // If we have a callee release and we are dead, set the callee release's // operand to undef. We do not need it to have the argument anymore, but we // do need the instruction to be non-null. // // TODO: This should not be necessary. for (auto &X : CalleeRelease) { SILType CalleeReleaseTy = X->getOperand(0)->getType(); X->setOperand( 0, SILUndef::get(CalleeReleaseTy, Builder.getModule())); } // We should be able to recursively delete all of the remaining // instructions. SILArgument *Arg = BB->getBBArg(ArgOffset); eraseUsesOfValue(Arg); BB->eraseBBArg(ArgOffset); return ArgOffset; } // If this argument is not dead and we did not perform SROA, increment the // offset and return. if (!shouldExplode()) { return ArgOffset + 1; } // Create values for the leaf types. llvm::SmallVector<SILValue, 8> LeafValues; // Create a reference to the old arg offset and increment arg offset so we can // create the new arguments. unsigned OldArgOffset = ArgOffset++; // We do this in the same order as leaf types since ProjTree expects that the // order of leaf values matches the order of leaf types. { llvm::SmallVector<SILType, 8> LeafTypes; ProjTree.getLeafTypes(LeafTypes); for (auto Ty : LeafTypes) { LeafValues.push_back(BB->insertBBArg( ArgOffset++, Ty, BB->getBBArg(OldArgOffset)->getDecl())); } } // Then go through the projection tree constructing aggregates and replacing // uses. // // TODO: What is the right location to use here? ProjTree.replaceValueUsesWithLeafUses(Builder, BB->getParent()->getLocation(), LeafValues); // We ignored debugvalue uses when we constructed the new arguments, in order // to preserve as much information as possible, we construct a new value for // OrigArg from the leaf values and use that in place of the OrigArg. SILValue NewOrigArgValue = ProjTree.computeExplodedArgumentValue(Builder, BB->getParent()->getLocation(), LeafValues); // Replace all uses of the original arg with the new value. SILArgument *OrigArg = BB->getBBArg(OldArgOffset); OrigArg->replaceAllUsesWith(NewOrigArgValue); // Now erase the old argument since it does not have any uses. We also // decrement ArgOffset since we have one less argument now. BB->eraseBBArg(OldArgOffset); --ArgOffset; return ArgOffset; }
unsigned ArgumentDescriptor::updateOptimizedBBArgs(SILBuilder &Builder, SILBasicBlock *BB, unsigned ArgOffset) { // If this argument is completely dead, delete this argument and return // ArgOffset. if (IsDead) { // If we have a callee release and we are dead, set the callee release's // operand to undef. We do not need it to have the argument anymore, but we // do need the instruction to be non-null. // // TODO: This should not be necessary. if (CalleeRelease) { SILType CalleeReleaseTy = CalleeRelease->getOperand(0).getType(); CalleeRelease->setOperand( 0, SILUndef::get(CalleeReleaseTy, Builder.getModule())); // TODO: Currently we cannot mark arguments as dead if they are released // in a throw block. But as soon as we can do this, we have to handle // CalleeReleaseInThrowBlock as well. assert(!CalleeReleaseInThrowBlock && "released arg in throw block cannot be dead"); } // We should be able to recursively delete all of the remaining // instructions. SILArgument *Arg = BB->getBBArg(ArgOffset); eraseUsesOfValue(Arg); BB->eraseBBArg(ArgOffset); return ArgOffset; } // If this argument is not dead and we did not perform SROA, increment the // offset and return. if (!shouldExplode()) { return ArgOffset + 1; } // Create values for the leaf types. llvm::SmallVector<SILValue, 8> LeafValues; // Create a reference to the old arg offset and increment arg offset so we can // create the new arguments. unsigned OldArgOffset = ArgOffset++; // We do this in the same order as leaf types since ProjTree expects that the // order of leaf values matches the order of leaf types. { llvm::SmallVector<SILType, 8> LeafTypes; ProjTree.getLeafTypes(LeafTypes); for (auto Ty : LeafTypes) { LeafValues.push_back(BB->insertBBArg( ArgOffset++, Ty, BB->getBBArg(OldArgOffset)->getDecl())); } } // Then go through the projection tree constructing aggregates and replacing // uses. // // TODO: What is the right location to use here? ProjTree.replaceValueUsesWithLeafUses(Builder, BB->getParent()->getLocation(), LeafValues); // Replace all uses of the original arg with undef so it does not have any // uses. SILValue OrigArg = SILValue(BB->getBBArg(OldArgOffset)); OrigArg.replaceAllUsesWith(SILUndef::get(OrigArg.getType(), BB->getModule())); // Now erase the old argument since it does not have any uses. We also // decrement ArgOffset since we have one less argument now. BB->eraseBBArg(OldArgOffset); --ArgOffset; return ArgOffset; }