static InitializationPtr prepareIndirectResultInit(SILGenFunction &gen, CanType resultType, ArrayRef<SILResultInfo> &allResults, MutableArrayRef<SILValue> &directResults, ArrayRef<SILArgument*> &indirectResultAddrs, SmallVectorImpl<CleanupHandle> &cleanups) { // Recursively decompose tuple types. if (auto resultTupleType = dyn_cast<TupleType>(resultType)) { auto tupleInit = new TupleInitialization(); tupleInit->SubInitializations.reserve(resultTupleType->getNumElements()); for (auto resultEltType : resultTupleType.getElementTypes()) { auto eltInit = prepareIndirectResultInit(gen, resultEltType, allResults, directResults, indirectResultAddrs, cleanups); tupleInit->SubInitializations.push_back(std::move(eltInit)); } return InitializationPtr(tupleInit); } // Okay, pull the next result off the list of results. auto result = allResults[0]; allResults = allResults.slice(1); // If it's indirect, we should be emitting into an argument. if (result.isIndirect()) { // Pull off the next indirect result argument. SILValue addr = indirectResultAddrs.front(); indirectResultAddrs = indirectResultAddrs.slice(1); // Create an initialization which will initialize it. auto &resultTL = gen.getTypeLowering(addr->getType()); auto temporary = gen.useBufferAsTemporary(addr, resultTL); // Remember the cleanup that will be activated. auto cleanup = temporary->getInitializedCleanup(); if (cleanup.isValid()) cleanups.push_back(cleanup); return InitializationPtr(temporary.release()); } // Otherwise, make an Initialization that stores the value in the // next element of the directResults array. auto init = new StoreResultInitialization(directResults[0], cleanups); directResults = directResults.slice(1); return InitializationPtr(init); }
static void withValueInPayload(IRGenFunction &IGF, const EnumPayload &payload, llvm::Type *valueType, int numBitsUsedInValue, unsigned payloadOffset, Fn &&f) { auto &DataLayout = IGF.IGM.DataLayout; int valueTypeBitWidth = DataLayout.getTypeSizeInBits(valueType); int valueBitWidth = numBitsUsedInValue < 0 ? valueTypeBitWidth : numBitsUsedInValue; assert(numBitsUsedInValue <= valueTypeBitWidth); // Find the elements we need to touch. // TODO: Linear search through the payload elements is lame. MutableArrayRef<EnumPayload::LazyValue> payloads = payload.PayloadValues; llvm::Type *payloadType; int payloadBitWidth; int valueOffset = 0, payloadValueOffset = payloadOffset; for (;;) { payloadType = getPayloadType(payloads.front()); payloadBitWidth = IGF.IGM.DataLayout.getTypeSizeInBits(payloadType); // Does this element overlap the area we need to touch? if (payloadValueOffset < payloadBitWidth) { // See how much of the value we can fit here. int valueChunkWidth = payloadBitWidth - payloadValueOffset; valueChunkWidth = std::min(valueChunkWidth, valueBitWidth - valueOffset); f(payloads.front(), payloadBitWidth, payloadValueOffset, valueTypeBitWidth, valueOffset); // If we used the entire value, we're done. valueOffset += valueChunkWidth; if (valueOffset >= valueBitWidth) return; } payloadValueOffset = std::max(payloadValueOffset - payloadBitWidth, 0); payloads = payloads.slice(1); } }
static void emitSubSwitch(IRGenFunction &IGF, MutableArrayRef<EnumPayload::LazyValue> values, APInt mask, MutableArrayRef<std::pair<APInt, llvm::BasicBlock *>> cases, SwitchDefaultDest dflt) { recur: assert(!values.empty() && "didn't exit out when exhausting all values?!"); assert(!cases.empty() && "switching with no cases?!"); auto &DL = IGF.IGM.DataLayout; auto &pv = values.front(); values = values.slice(1); auto payloadTy = getPayloadType(pv); unsigned size = DL.getTypeSizeInBits(payloadTy); // Grab a chunk of the mask. auto maskPiece = mask.zextOrTrunc(size); mask = mask.lshr(size); // If the piece is zero, this doesn't affect the switch. We can just move // forward and recur. if (maskPiece == 0) { for (auto &casePair : cases) casePair.first = casePair.first.lshr(size); goto recur; } // Force the value we will test. auto v = forcePayloadValue(pv); auto payloadIntTy = llvm::IntegerType::get(IGF.IGM.getLLVMContext(), size); // Need to coerce to integer for 'icmp eq' if it's not already an integer // or pointer. (Switching or masking will also require a cast to integer.) if (!isa<llvm::IntegerType>(v->getType()) && !isa<llvm::PointerType>(v->getType())) v = IGF.Builder.CreateBitOrPointerCast(v, payloadIntTy); // Apply the mask if it's interesting. if (!maskPiece.isAllOnesValue()) { v = IGF.Builder.CreateBitOrPointerCast(v, payloadIntTy); auto maskConstant = llvm::ConstantInt::get(payloadIntTy, maskPiece); v = IGF.Builder.CreateAnd(v, maskConstant); } // Gather the values we will switch over for this payload chunk. // FIXME: std::map is lame. Should hash APInts. std::map<APInt, SmallVector<std::pair<APInt, llvm::BasicBlock*>, 2>, ult> subCases; for (auto casePair : cases) { // Grab a chunk of the value. auto valuePiece = casePair.first.zextOrTrunc(size); // Index the case according to this chunk. subCases[valuePiece].push_back({std::move(casePair.first).lshr(size), casePair.second}); } bool needsAdditionalCases = !values.empty() && mask != 0; SmallVector<std::pair<llvm::BasicBlock *, decltype(cases)>, 2> recursiveCases; auto blockForCases = [&](MutableArrayRef<std::pair<APInt, llvm::BasicBlock*>> cases) -> llvm::BasicBlock * { // If we need to recur, emit a new block. if (needsAdditionalCases) { auto newBB = IGF.createBasicBlock(""); recursiveCases.push_back({newBB, cases}); return newBB; } // Otherwise, we can jump directly to the ultimate destination. assert(cases.size() == 1 && "more than one case for final destination?!"); return cases.front().second; }; // If there's only one case, do a cond_br. if (subCases.size() == 1) { auto &subCase = *subCases.begin(); llvm::BasicBlock *block = blockForCases(subCase.second); // If the default case is unreachable, we don't need to conditionally // branch. if (dflt.getInt()) { IGF.Builder.CreateBr(block); goto next; } auto &valuePiece = subCase.first; llvm::Value *valueConstant = llvm::ConstantInt::get(payloadIntTy, valuePiece); valueConstant = IGF.Builder.CreateBitOrPointerCast(valueConstant, v->getType()); auto cmp = IGF.Builder.CreateICmpEQ(v, valueConstant); IGF.Builder.CreateCondBr(cmp, block, dflt.getPointer()); goto next; } // Otherwise, do a switch. { v = IGF.Builder.CreateBitOrPointerCast(v, payloadIntTy); auto swi = IGF.Builder.CreateSwitch(v, dflt.getPointer(), subCases.size()); for (auto &subCase : subCases) { auto &valuePiece = subCase.first; auto valueConstant = llvm::ConstantInt::get(IGF.IGM.getLLVMContext(), valuePiece); swi->addCase(valueConstant, blockForCases(subCase.second)); } } next: // Emit the recursive cases. for (auto &recursive : recursiveCases) { IGF.Builder.emitBlock(recursive.first); emitSubSwitch(IGF, values, mask, recursive.second, dflt); } }