void SwiftAggLowering::addLegalTypedData(llvm::Type *type, CharUnits begin, CharUnits end) { // Require the type to be naturally aligned. if (!begin.isZero() && !begin.isMultipleOf(getNaturalAlignment(CGM, type))) { // Try splitting vector types. if (auto vecTy = dyn_cast<llvm::VectorType>(type)) { auto split = splitLegalVectorType(CGM, end - begin, vecTy); auto eltTy = split.first; auto numElts = split.second; auto eltSize = (end - begin) / numElts; assert(eltSize == getTypeStoreSize(CGM, eltTy)); for (size_t i = 0, e = numElts; i != e; ++i) { addLegalTypedData(eltTy, begin, begin + eltSize); begin += eltSize; } assert(begin == end); return; } return addOpaqueData(begin, end); } addEntry(type, begin, end); }
void SwiftAggLowering::addEntry(llvm::Type *type, CharUnits begin, CharUnits end) { assert((!type || (!isa<llvm::StructType>(type) && !isa<llvm::ArrayType>(type))) && "cannot add aggregate-typed data"); assert(!type || begin.isMultipleOf(getNaturalAlignment(CGM, type))); // Fast path: we can just add entries to the end. if (Entries.empty() || Entries.back().End <= begin) { Entries.push_back({begin, end, type}); return; } // Find the first existing entry that ends after the start of the new data. // TODO: do a binary search if Entries is big enough for it to matter. size_t index = Entries.size() - 1; while (index != 0) { if (Entries[index - 1].End <= begin) break; --index; } // The entry ends after the start of the new data. // If the entry starts after the end of the new data, there's no conflict. if (Entries[index].Begin >= end) { // This insertion is potentially O(n), but the way we generally build // these layouts makes that unlikely to matter: we'd need a union of // several very large types. Entries.insert(Entries.begin() + index, {begin, end, type}); return; } // Otherwise, the ranges overlap. The new range might also overlap // with later ranges. restartAfterSplit: // Simplest case: an exact overlap. if (Entries[index].Begin == begin && Entries[index].End == end) { // If the types match exactly, great. if (Entries[index].Type == type) return; // If either type is opaque, make the entry opaque and return. if (Entries[index].Type == nullptr) { return; } else if (type == nullptr) { Entries[index].Type = nullptr; return; } // If they disagree in an ABI-agnostic way, just resolve the conflict // arbitrarily. if (auto entryType = getCommonType(Entries[index].Type, type)) { Entries[index].Type = entryType; return; } // Otherwise, make the entry opaque. Entries[index].Type = nullptr; return; } // Okay, we have an overlapping conflict of some sort. // If we have a vector type, split it. if (auto vecTy = dyn_cast_or_null<llvm::VectorType>(type)) { auto eltTy = vecTy->getElementType(); CharUnits eltSize = (end - begin) / vecTy->getNumElements(); assert(eltSize == getTypeStoreSize(CGM, eltTy)); for (unsigned i = 0, e = vecTy->getNumElements(); i != e; ++i) { addEntry(eltTy, begin, begin + eltSize); begin += eltSize; } assert(begin == end); return; } // If the entry is a vector type, split it and try again. if (Entries[index].Type && Entries[index].Type->isVectorTy()) { splitVectorEntry(index); goto restartAfterSplit; } // Okay, we have no choice but to make the existing entry opaque. Entries[index].Type = nullptr; // Stretch the start of the entry to the beginning of the range. if (begin < Entries[index].Begin) { Entries[index].Begin = begin; assert(index == 0 || begin >= Entries[index - 1].End); } // Stretch the end of the entry to the end of the range; but if we run // into the start of the next entry, just leave the range there and repeat. while (end > Entries[index].End) { assert(Entries[index].Type == nullptr); // If the range doesn't overlap the next entry, we're done. if (index == Entries.size() - 1 || end <= Entries[index + 1].Begin) { Entries[index].End = end; break; } // Otherwise, stretch to the start of the next entry. Entries[index].End = Entries[index + 1].Begin; // Continue with the next entry. index++; // This entry needs to be made opaque if it is not already. if (Entries[index].Type == nullptr) continue; // Split vector entries unless we completely subsume them. if (Entries[index].Type->isVectorTy() && end < Entries[index].End) { splitVectorEntry(index); } // Make the entry opaque. Entries[index].Type = nullptr; } }