TupleIdSequence* TupleStorageSubBlock::getMatchesForPredicate(const Predicate *pred) const { TupleIdSequence *matches = new TupleIdSequence(); tuple_id max_tid = getMaxTupleID(); if (pred == NULL) { if (isPacked()) { for (tuple_id tid = 0; tid <= max_tid; ++tid) { matches->append(tid); } } else { for (tuple_id tid = 0; tid <= max_tid; ++tid) { if (hasTupleWithID(tid)) { matches->append(tid); } } } } else { if (isPacked()) { for (tuple_id tid = 0; tid <= max_tid; ++tid) { if (pred->matchesForSingleTuple(*this, tid)) { matches->append(tid); } } } else { for (tuple_id tid = 0; tid <= max_tid; ++tid) { if (hasTupleWithID(tid) && (pred->matchesForSingleTuple(*this, tid))) { matches->append(tid); } } } } return matches; }
llvm::Constant* IrAggr::createInitializerConstant( const VarInitMap& explicitInitializers, llvm::StructType* initializerType) { IF_LOG Logger::println("Creating initializer constant for %s", aggrdecl->toChars()); LOG_SCOPE; llvm::SmallVector<llvm::Constant*, 16> constants; unsigned offset = 0; if (type->ty == Tclass) { // add vtbl constants.push_back(getVtblSymbol()); // add monitor constants.push_back(getNullValue(DtoType(Type::tvoid->pointerTo()))); // we start right after the vtbl and monitor offset = Target::ptrsize * 2; } // Add the initializers for the member fields. While we are traversing the // class hierarchy, use the opportunity to populate interfacesWithVtbls if // we haven't done so previously (due to e.g. ClassReferenceExp, we can // have multiple initializer constants for a single class). addFieldInitializers(constants, explicitInitializers, aggrdecl, offset, interfacesWithVtbls.empty()); // tail padding? const size_t structsize = aggrdecl->size(Loc()); if (offset < structsize) { add_zeros(constants, offset, structsize); } // get initializer type if (!initializerType || initializerType->isOpaque()) { llvm::SmallVector<llvm::Constant*, 16>::iterator itr, end = constants.end(); llvm::SmallVector<llvm::Type*, 16> types; types.reserve(constants.size()); for (itr = constants.begin(); itr != end; ++itr) types.push_back((*itr)->getType()); if (!initializerType) initializerType = LLStructType::get(gIR->context(), types, isPacked()); else initializerType->setBody(types, isPacked()); } // build constant assert(!constants.empty()); llvm::Constant* c = LLConstantStruct::get(initializerType, constants); IF_LOG Logger::cout() << "final initializer: " << *c << std::endl; return c; }
SharedVariant::~SharedVariant() { switch (m_type) { case KindOfObject: if (getIsObj()) { delete m_data.obj; break; } // otherwise fall through case KindOfString: m_data.str->destruct(); break; case KindOfArray: { if (getSerializedArray()) { m_data.str->destruct(); break; } if (isPacked()) { delete m_data.packed; } else { ImmutableArray::Destroy(m_data.array); } } break; default: break; } }
int32_t SharedVariant::getSpaceUsage() const { int32_t size = sizeof(SharedVariant); if (!IS_REFCOUNTED_TYPE(m_type)) return size; switch (m_type) { case KindOfObject: if (getIsObj()) { return size + m_data.obj->getSpaceUsage(); } // fall through case KindOfString: size += sizeof(StringData) + m_data.str->size(); break; default: assert(is(KindOfArray)); if (getSerializedArray()) { size += sizeof(StringData) + m_data.str->size(); } else if (isPacked()) { auto size = m_data.packed->size(); size += sizeof(ImmutablePackedArray) + size * sizeof(SharedVariant*); for (size_t i = 0, n = m_data.packed->size(); i < n; i++) { size += m_data.packed->vals()[i]->getSpaceUsage(); } } else { auto array = m_data.array; size += array->getStructSize(); for (size_t i = 0, n = array->size(); i < n; i++) { size += array->getKeyIndex(i)->getSpaceUsage(); size += array->getValIndex(i)->getSpaceUsage(); } } break; } return size; }
void HLSLBlockEncoder::advanceOffset(GLenum typeIn, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride) { GLenum type = (mTransposeMatrices ? gl::TransposeMatrixType(typeIn) : typeIn); if (arraySize > 0) { mCurrentOffset += arrayStride * (arraySize - 1); } if (gl::IsMatrixType(type)) { ASSERT(matrixStride == ComponentsPerRegister); const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix); const int numComponents = gl::MatrixComponentCount(type, isRowMajorMatrix); mCurrentOffset += ComponentsPerRegister * (numRegisters - 1); mCurrentOffset += numComponents; } else if (isPacked()) { mCurrentOffset += gl::VariableComponentCount(type); } else { mCurrentOffset += ComponentsPerRegister; } }
llvm::Constant * IrAggr::createInitializerConstant(const VarInitMap &explicitInitializers) { IF_LOG Logger::println("Creating initializer constant for %s", aggrdecl->toChars()); LOG_SCOPE; llvm::SmallVector<llvm::Constant *, 16> constants; unsigned offset = 0; if (type->ty == Tclass) { // add vtbl constants.push_back(getVtblSymbol()); offset += Target::ptrsize; // add monitor (except for C++ classes) if (!aggrdecl->isClassDeclaration()->isCPPclass()) { constants.push_back(getNullValue(getVoidPtrType())); offset += Target::ptrsize; } } // Add the initializers for the member fields. While we are traversing the // class hierarchy, use the opportunity to populate interfacesWithVtbls if // we haven't done so previously (due to e.g. ClassReferenceExp, we can // have multiple initializer constants for a single class). addFieldInitializers(constants, explicitInitializers, aggrdecl, offset, interfacesWithVtbls.empty()); // tail padding? const size_t structsize = aggrdecl->size(Loc()); if (offset < structsize) add_zeros(constants, offset, structsize); assert(!constants.empty()); // get LL field types llvm::SmallVector<llvm::Type *, 16> types; types.reserve(constants.size()); for (auto c : constants) types.push_back(c->getType()); auto llStructType = getLLStructType(); bool isCompatible = (types.size() == llStructType->getNumElements()); if (isCompatible) { for (size_t i = 0; i < types.size(); i++) { if (types[i] != llStructType->getElementType(i)) { isCompatible = false; break; } } } // build constant LLStructType *llType = isCompatible ? llStructType : LLStructType::get(gIR->context(), types, isPacked()); llvm::Constant *c = LLConstantStruct::get(llType, constants); IF_LOG Logger::cout() << "final initializer: " << *c << std::endl; return c; }
void SharedVariant::getStats(SharedVariantStats *stats) const { stats->initStats(); stats->variantCount = 1; switch (m_type) { case KindOfUninit: case KindOfNull: case KindOfBoolean: case KindOfInt64: case KindOfDouble: case KindOfStaticString: stats->dataSize = sizeof(m_data.dbl); stats->dataTotalSize = sizeof(SharedVariant); break; case KindOfObject: if (getIsObj()) { SharedVariantStats childStats; m_data.obj->getSizeStats(&childStats); stats->addChildStats(&childStats); break; } // fall through case KindOfString: stats->dataSize = m_data.str->size(); stats->dataTotalSize = sizeof(SharedVariant) + sizeof(StringData) + stats->dataSize; break; default: assert(is(KindOfArray)); if (getSerializedArray()) { stats->dataSize = m_data.str->size(); stats->dataTotalSize = sizeof(SharedVariant) + sizeof(StringData) + stats->dataSize; break; } if (isPacked()) { stats->dataTotalSize = sizeof(SharedVariant) + sizeof(ImmutablePackedArray); auto size = m_data.packed->size(); stats->dataTotalSize += sizeof(SharedVariant*) * size; for (size_t i = 0; i < size; i++) { SharedVariant *v = m_data.packed->vals()[i]; SharedVariantStats childStats; v->getStats(&childStats); stats->addChildStats(&childStats); } } else { auto array = m_data.array; stats->dataTotalSize = sizeof(SharedVariant) + array->getStructSize(); for (size_t i = 0, n = array->size(); i < n; i++) { SharedVariantStats childStats; array->getKeyIndex(i)->getStats(&childStats); stats->addChildStats(&childStats); array->getValIndex(i)->getStats(&childStats); stats->addChildStats(&childStats); } } break; } }
Variant SharedVariant::getKey(ssize_t pos) const { assert(is(KindOfArray)); if (isPacked()) { assert(pos < (ssize_t) m_data.packed->size()); return pos; } return m_data.array->getKeyIndex(pos)->toLocal(); }
void HLSLBlockEncoder::getBlockLayoutInfo(GLenum typeIn, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut) { GLenum type = (mTransposeMatrices ? gl::TransposeMatrixType(typeIn) : typeIn); // We assume we are only dealing with 4 byte components (no doubles or half-words currently) ASSERT(gl::VariableComponentSize(gl::VariableComponentType(type)) == BytesPerComponent); int matrixStride = 0; int arrayStride = 0; // if variables are not to be packed, or we're about to // pack a matrix or array, skip to the start of the next // register if (!isPacked() || gl::IsMatrixType(type) || arraySize > 0) { nextRegister(); } if (gl::IsMatrixType(type)) { matrixStride = ComponentsPerRegister; if (arraySize > 0) { const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix); arrayStride = ComponentsPerRegister * numRegisters; } } else if (arraySize > 0) { arrayStride = ComponentsPerRegister; } else if (isPacked()) { int numComponents = gl::VariableComponentCount(type); if ((numComponents + (mCurrentOffset % ComponentsPerRegister)) > ComponentsPerRegister) { nextRegister(); } } *matrixStrideOut = matrixStride; *arrayStrideOut = arrayStride; }
int SharedVariant::getIndex(int64_t key) { assert(is(KindOfArray)); if (isPacked()) { if (key < 0 || (size_t) key >= m_data.packed->size()) return -1; return key; } return m_data.array->indexOf(key); }
std::string getObjectConnectionName( ObjectData* obj, const void* target ) { Class* cls = obj->getVMClass(); FTRACE(5, "HG: Getting connection name for type {} at {}\n", obj->getClassName().data(), obj ); if (!supportsToArray(obj)) { return ""; } auto arr = obj->toArray(); bool is_packed = arr->isPacked(); for (ArrayIter iter(arr); iter; ++iter) { auto first = iter.first(); auto key = first.toString(); auto key_tv = first.asTypedValue(); auto val_tv = iter.secondRef().asTypedValue(); if (key_tv->m_type == HPHP::KindOfString) { // If the key begins with a NUL, it's a private or protected property. // Read the class name from between the two NUL bytes. // // Note: Copied from object-data.cpp if (!key.empty() && key[0] == '\0') { int subLen = key.find('\0', 1) + 1; key = key.substr(subLen); } } FTRACE(5, "HG: ...Iterating over object key-val {}=>{}\n", key, tname(val_tv->m_type) ); // We're only interested in the porperty name that points to our target if ((void*)val_tv->m_data.pobj != target) { continue; } bool is_declared = key_tv->m_type == HPHP::KindOfString && cls->lookupDeclProp(key.get()) != kInvalidSlot; if (!is_declared && !is_packed) { return std::string("Key:" + key); } else if (is_packed) { return std::string("PropertyIndex"); } else { return std::string("Property:" + key); } } return ""; }
HOT_FUNC SharedVariant* SharedVariant::getValue(ssize_t pos) const { assert(is(KindOfArray)); if (isPacked()) { assert(pos < (ssize_t) m_data.packed->size()); return m_data.packed->vals()[pos]; } return m_data.array->getValIndex(pos); }
HphpArray::SortFlavor HphpArray::preSort(const AccessorT& acc, bool checkTypes) { assert(m_size > 0); if (isPacked()) { // todo t2607563: this is pessimistic. packedToMixed(); } if (!checkTypes && m_size == m_used) { // No need to loop over the elements, we're done return GenericSort; } Elm* start = data(); Elm* end = data() + m_used; bool allInts UNUSED = true; bool allStrs UNUSED = true; for (;;) { if (checkTypes) { while (!isTombstone(start->data.m_type)) { allInts = (allInts && acc.isInt(*start)); allStrs = (allStrs && acc.isStr(*start)); ++start; if (start == end) { goto done; } } } else { while (!isTombstone(start->data.m_type)) { ++start; if (start == end) { goto done; } } } --end; if (start == end) { goto done; } while (isTombstone(end->data.m_type)) { --end; if (start == end) { goto done; } } memcpy(start, end, sizeof(Elm)); } done: m_used = start - data(); assert(m_size == m_used); if (checkTypes) { return allStrs ? StringSort : allInts ? IntegerSort : GenericSort; } else { return GenericSort; } }
APCArray::~APCArray() { if (isPacked()) { APCHandle** v = vals(); for (size_t i = 0, n = m_size; i < n; i++) { v[i]->unreference(); } } else { Bucket* bks = buckets(); for (int i = 0; i < m.m_num; i++) { bks[i].key->unreference(); bks[i].val->unreference(); } } }
int SharedVariant::countReachable() const { int count = 1; if (getType() == KindOfArray) { int size = arrSize(); if (!isPacked()) { count += size; // for keys } for (int i = 0; i < size; i++) { SharedVariant* p = getValue(i); count += p->countReachable(); // for values } } return count; }
TupleIdSequence* TupleStorageSubBlock::getExistenceMap() const { const tuple_id max_tid = getMaxTupleID(); TupleIdSequence *existing_tuples = new TupleIdSequence(max_tid + 1); if (isPacked()) { existing_tuples->setRange(0, max_tid + 1, true); } else { for (tuple_id tid = 0; tid <= max_tid; ++tid) { if (hasTupleWithID(tid)) { existing_tuples->set(tid, true); } } } return existing_tuples; }
APCArray::~APCArray() { // This array is refcounted, but keys/values might be uncounted strings, so // we must use unreferenceRoot here (corresponding to Create calls above). if (isPacked()) { APCHandle** v = vals(); for (size_t i = 0, n = m_size; i < n; i++) { v[i]->unreferenceRoot(); } } else { Bucket* bks = buckets(); for (int i = 0; i < m.m_num; i++) { bks[i].key->unreferenceRoot(); bks[i].val->unreferenceRoot(); } } }
tuple_id TupleStorageSubBlock::numTuples() const { if (isEmpty()) { return 0; } else if (isPacked()) { return getMaxTupleID() + 1; } else { // WARNING: This branch is O(N). Subclasses should override wherever possible. tuple_id count = 0; for (tuple_id tid = 0; tid <= getMaxTupleID(); ++tid) { if (hasTupleWithID(tid)) { ++count; } } // Should have at least one tuple, otherwise isEmpty() would have been true. DEBUG_ASSERT(count > 0); return count; } }
OrderedTupleIdSequence* TupleStorageSubBlock::getExistenceList() const { const tuple_id max_tid = getMaxTupleID(); OrderedTupleIdSequence *existence_list = new OrderedTupleIdSequence(); existence_list->reserve(numTuples()); if (isPacked()) { for (tuple_id tid = 0; tid <= max_tid; ++tid) { existence_list->emplace_back(tid); } } else { for (tuple_id tid = 0; tid <= max_tid; ++tid) { if (hasTupleWithID(tid)) { existence_list->emplace_back(tid); } } } return existence_list; }
IrTypeStruct *IrTypeStruct::get(StructDeclaration *sd) { auto t = new IrTypeStruct(sd); sd->type->ctype = t; IF_LOG Logger::println("Building struct type %s @ %s", sd->toPrettyChars(), sd->loc.toChars()); LOG_SCOPE; // if it's a forward declaration, all bets are off, stick with the opaque if (sd->sizeok != SIZEOKdone) { return t; } t->packed = isPacked(sd); // For ldc.dcomptetypes.Pointer!(uint n,T), // emit { T addrspace(gIR->dcomputetarget->mapping[n])* } llvm::Optional<DcomputePointer> p; if (gIR->dcomputetarget && (p = toDcomputePointer(sd))) { // Translate the virtual dcompute address space into the real one for // the target int realAS = gIR->dcomputetarget->mapping[p->addrspace]; llvm::SmallVector<LLType *, 1> body; body.push_back(DtoMemType(p->type)->getPointerTo(realAS)); isaStruct(t->type)->setBody(body, t->packed); VarGEPIndices v; v[sd->fields[0]] = 0; t->varGEPIndices = v; } else { AggrTypeBuilder builder(t->packed); builder.addAggregate(sd); builder.addTailPadding(sd->structsize); isaStruct(t->type)->setBody(builder.defaultTypes(), t->packed); t->varGEPIndices = builder.varGEPIndices(); } IF_LOG Logger::cout() << "final struct type: " << *t->type << std::endl; return t; }
ArrayData* SharedVariant::loadElems(const SharedArray &array) { assert(is(KindOfArray)); auto count = arrSize(); ArrayData* elems; if (isPacked()) { PackedArrayInit ai(count); for (uint i = 0; i < count; i++) { ai.append(array.getValueRef(i)); } elems = ai.create(); } else { ArrayInit ai(count); for (uint i = 0; i < count; i++) { ai.add(m_data.array->getKeyIndex(i)->toLocal(), array.getValueRef(i), true); } elems = ai.create(); } if (elems->isStatic()) elems = elems->copy(); return elems; }
// --------------------------------------------------------------------- // Driver for Unpacking // // In a nutshell, unpacking consists of the following major steps: // // 1. fix the endianness of the version header (members of this class) // 2. fix up the virtual table function pointer for the object // 3. migrate an object of a previous version to the current version // 4. fix the endianness of all other members in the subclasses // 5. convert pointers in this object from offsets back to addresses // 5. initiate unpacking for other objects referenced by this object // 6. initialize new members added in the new version // // Parameters: // base is the base address (added to offset to get pointer) // vtblPtr (first form) is the pointer to the virtual function table // of the class // ptrToAnchorClass (second form, see below) is a pointer to an object // that has the desired virtual function pointer // --------------------------------------------------------------------- NA_EIDPROC NAVersionedObject *NAVersionedObject::driveUnpack( void *base, char *vtblPtr, void * reallocator) { // ----------------------------------------------------------------- // Make sure we are really dealing with a NAVersionedObject by // examining its eyeCatcher_. // ----------------------------------------------------------------- if (str_cmp(eyeCatcher_,VOBJ_EYE_CATCHER,VOBJ_EYE_CATCHER_SIZE)) return NULL; // ----------------------------------------------------------------- // If object has already been unpacked, just return either its own // address or the reallocated address if the object was reallocated // to somewhere else. // ----------------------------------------------------------------- if (!isPacked()) { if (reallocatedAddress_.isNull()) return this; else return reallocatedAddress_.getPointer(); } #ifdef NA_64BIT // dg64 - the 32-bit module files have junk in them, so let's try zero // at least in the high-order 32-bits else reallocatedAddress_ = (NAVersionedObjectPtr) NULL ; #endif // ----------------------------------------------------------------- // Fix the Version Header to the endianness of the local platform // if necessary. Correct classID_ field is necessary to determine // the right subclass the object belongs. // // *** DON'T DO THIS JUST YET: PLAN IS TO SUPPORT THIS ONLY FROM // *** SECOND RELEASE. // ----------------------------------------------------------------- #ifndef NA_LITTLE_ENDIAN // toggleEndiannessOfVersionHeader(); #endif // ----------------------------------------------------------------- // The method findVTblPtr() was called on an object of the Anthor // Class T to find out what subclass of the Anchor Class this object // belongs based on its classID_. Now, the virtual function table // pointer is used to fix up this object. // ----------------------------------------------------------------- if (vtblPtr == NULL) return NULL; // unknown class ID // else setVTblPtr(vtblPtr); // ----------------------------------------------------------------- // Call the virtual method migrateToNewVersion() so that older // objects can be migrated to fit in the new class template. // ----------------------------------------------------------------- NAVersionedObject *objPtr = NULL; // ----------------------------------------------------------------- // migrateToNewVersion() should either set objPtr to this or to an // reallocated image. // ----------------------------------------------------------------- if (migrateToNewVersion(objPtr)) return NULL; // version not supported // // ----------------------------------------------------------------- // Convert members of this object from reference platform to local // platform. // // *** DON'T DO THIS JUST YET: PLAN IS TO SUPPORT THIS ONLY FROM // *** SECOND RELEASE. // ----------------------------------------------------------------- // objPtr->convertToLocalPlatform(); // ----------------------------------------------------------------- // Mark object as not packed, despite it is not completely unpacked // yet. This is needed because the call that follows to the virtual // method unpack() drives the unpacking of all objects referenced by // this object. If this object is subsequently referenced by another // object down the row, driveUnpack() will be called on this object // again. At that point of time, we should see the packed flag set // to "not packed" so that "double-unpacking" can be avoided. // ----------------------------------------------------------------- markAsNotPacked(); objPtr->markAsNotPacked(); // ----------------------------------------------------------------- // After migration, the object might have been reallocated. In that // case objPtr will be changed to point to the reallocated object. // The following calls are then made on the reallocated object // instead of this. // ----------------------------------------------------------------- if(objPtr->unpack(base, reallocator)) return NULL; // Should this ever happen? Internal Error. objPtr->initNewMembers(); return objPtr; }
// --------------------------------------------------------------------- // Driver for Packing // // Should return a 64 bit integer on a 64 bit platform. Could be fixed // later when 64-bit platforms are really available since it doesn't // affect object layout. // --------------------------------------------------------------------- NA_EIDPROC Long NAVersionedObject::drivePack(void *space, short isSpacePtr) { // ----------------------------------------------------------------- // If the object has already been packed, just convert the pointer // of the object to an offset and return its value. That value will // be used by the caller to replace the pointer stored there. // ----------------------------------------------------------------- if (isPacked()) { if (isSpacePtr) return ((Space *)space)->convertToOffset((char *)this); else return ((char *)space - (char *)this); } // ----------------------------------------------------------------- // Make sure the image size and the version ID are set properly // before proceeding on to pack the object. // ----------------------------------------------------------------- Int16 classSize = getClassSize(); if ((classSize % 8) != 0) assert((classSize % 8) == 0); setImageSize(classSize); populateImageVersionIDArray(); // ----------------------------------------------------------------- // Toggle the Endianness of the Version Header if it's not stored // in little-endian form. // // *** DON'T DO THIS JUST YET: PLAN IS TO SUPPORT THIS ONLY FROM // *** SECOND RELEASE. // ----------------------------------------------------------------- #ifndef NA_LITTLE_ENDIAN // toggleEndiannessOfVersionHeader(); #endif // ----------------------------------------------------------------- // Convert members of this object from local platform to reference // platform. // // *** DON'T DO THIS JUST YET: PLAN IS TO SUPPORT THIS ONLY FROM // *** SECOND RELEASE. // ----------------------------------------------------------------- // convertToReferencePlatform(); // ----------------------------------------------------------------- // Mark object as packed, despite it is not completely packed yet. // It is needed because the call that follows to the virtual method // pack() drives the packing of all objects referenced by this // object. If this object is subsequently referenced by another // object down the row, drivePack() will be called on this object // again. At that point of time, we should see the packed flag set // so that "double-packing" can be avoided. // ----------------------------------------------------------------- markAsPacked(); // ----------------------------------------------------------------- // pack() is a virtual method the subclass should redefine to drive // the packing of all objects it references by pointers and convert // those pointers to offsets. It should also convert the endianness // of its members to the reference if necessary. // ----------------------------------------------------------------- setIsSpacePtr( isSpacePtr !=0 ); Long offset = pack(space); // long offset = (isSpacePtr ? pack(space) : pack(space,0)); // ----------------------------------------------------------------- // Make sure the eyeCatcher_ field of the object is proper. Also // clean up the virtual table function pointer, so that the image // look identical each time. // ----------------------------------------------------------------- str_cpy_all(eyeCatcher_,VOBJ_EYE_CATCHER,VOBJ_EYE_CATCHER_SIZE); setVTblPtr(NULL); return offset; }
void IrAggr::addFieldInitializers( llvm::SmallVectorImpl<llvm::Constant*>& constants, const VarInitMap& explicitInitializers, AggregateDeclaration* decl, unsigned& offset, bool populateInterfacesWithVtbls ) { if (ClassDeclaration* cd = decl->isClassDeclaration()) { if (cd->baseClass) { addFieldInitializers(constants, explicitInitializers, cd->baseClass, offset, populateInterfacesWithVtbls); } } // Build up vector with one-to-one mapping to field indices. const size_t n = decl->fields.dim; llvm::SmallVector<VarInitConst, 16> data(n); // Fill in explicit initializers. for (size_t i = 0; i < n; ++i) { VarDeclaration* vd = decl->fields[i]; VarInitMap::const_iterator expl = explicitInitializers.find(vd); if (expl != explicitInitializers.end()) data[i] = *expl; } // Fill in implicit initializers for (size_t i = 0; i < n; i++) { if (data[i].first) continue; VarDeclaration* vd = decl->fields[i]; /* Skip void initializers for unions. DMD bug 3991: union X { int a = void; dchar b = 'a'; } */ if (decl->isUnionDeclaration() && vd->init && vd->init->isVoidInitializer()) continue; unsigned vd_begin = vd->offset; unsigned vd_end = vd_begin + vd->type->size(); /* Skip zero size fields like zero-length static arrays, LDC issue 812: class B { ubyte[0] test; } */ if (vd_begin == vd_end) continue; // make sure it doesn't overlap any explicit initializers. bool overlaps = false; if (type->ty == Tstruct) { // Only structs and unions can have overlapping fields. for (size_t j = 0; j < n; ++j) { if (i == j || !data[j].first) continue; VarDeclaration* it = decl->fields[j]; unsigned f_begin = it->offset; unsigned f_end = f_begin + it->type->size(); if (vd_begin >= f_end || vd_end <= f_begin) continue; overlaps = true; break; } } // add if no overlap found if (!overlaps) { IF_LOG Logger::println("Implicit initializer: %s @+%u", vd->toChars(), vd->offset); LOG_SCOPE; data[i].first = vd; data[i].second = get_default_initializer(vd, NULL); } } // Sort data array by offset. // TODO: Figure out whether this is really necessary, fields should already // be in offset order. Not having do do this would mean we could use a plain // llvm::Constant* vector for initializers and avoid all the VarInitConst business. std::sort(data.begin(), data.end(), struct_init_data_sort); // build array of constants and make sure explicit zero padding is inserted when necessary. for (size_t i = 0; i < n; i++) { VarDeclaration* vd = data[i].first; if (vd == NULL) continue; // get next aligned offset for this field size_t alignedoffset = offset; if (!isPacked()) { alignedoffset = realignOffset(alignedoffset, vd->type); } // insert explicit padding? if (alignedoffset < vd->offset) { add_zeros(constants, alignedoffset, vd->offset); } IF_LOG Logger::println("adding field %s", vd->toChars()); constants.push_back(FillSArrayDims(vd->type, data[i].second)); offset = vd->offset + vd->type->size(); } if (ClassDeclaration* cd = decl->isClassDeclaration()) { // has interface vtbls? if (cd->vtblInterfaces && cd->vtblInterfaces->dim > 0) { // false when it's not okay to use functions from super classes bool newinsts = (cd == aggrdecl->isClassDeclaration()); size_t inter_idx = interfacesWithVtbls.size(); offset = (offset + Target::ptrsize - 1) & ~(Target::ptrsize - 1); for (BaseClasses::iterator I = cd->vtblInterfaces->begin(), E = cd->vtblInterfaces->end(); I != E; ++I) { constants.push_back(getInterfaceVtbl(*I, newinsts, inter_idx)); offset += Target::ptrsize; inter_idx++; if (populateInterfacesWithVtbls) interfacesWithVtbls.push_back(*I); } } } }
HOT_FUNC int SharedVariant::getIndex(const StringData* key) { assert(is(KindOfArray)); if (isPacked()) return -1; return m_data.array->indexOf(key); }
void AstArrayDType::dump(ostream& str) { this->AstNodeDType::dump(str); if (isPacked()) str<<" [PACKED]"; }
IrTypeClass *IrTypeClass::get(ClassDeclaration *cd) { const auto t = new IrTypeClass(cd); cd->type->ctype = t; IF_LOG Logger::println("Building class type %s @ %s", cd->toPrettyChars(), cd->loc.toChars()); LOG_SCOPE; IF_LOG Logger::println("Instance size: %u", cd->structsize); // This class may contain an align declaration. See GitHub #726. t->packed = false; for (auto base = cd; base != nullptr && !t->packed; base = base->baseClass) { t->packed = isPacked(base); } AggrTypeBuilder builder(t->packed); // add vtbl builder.addType(llvm::PointerType::get(t->vtbl_type, 0), Target::ptrsize); if (cd->isInterfaceDeclaration()) { // interfaces are just a vtable t->num_interface_vtbls = cd->vtblInterfaces ? cd->vtblInterfaces->dim : 0; } else { // classes have monitor and fields if (!cd->isCPPclass() && !cd->isCPPinterface()) { // add monitor builder.addType( llvm::PointerType::get(llvm::Type::getInt8Ty(gIR->context()), 0), Target::ptrsize); } // add data members recursively t->addClassData(builder, cd); // add tail padding builder.addTailPadding(cd->structsize); } if (global.errors) { fatal(); } // set struct body and copy GEP indices isaStruct(t->type)->setBody(builder.defaultTypes(), t->packed); t->varGEPIndices = builder.varGEPIndices(); // set vtbl type body FuncDeclarations vtbl; vtbl.reserve(cd->vtbl.dim); if (!cd->isCPPclass()) vtbl.push(nullptr); for (size_t i = cd->vtblOffset(); i < cd->vtbl.dim; ++i) { FuncDeclaration *fd = cd->vtbl[i]->isFuncDeclaration(); assert(fd); vtbl.push(fd); } Type* first = cd->isCPPclass() ? nullptr : Type::typeinfoclass->type; t->vtbl_type->setBody(t->buildVtblType(first, &vtbl)); IF_LOG Logger::cout() << "class type: " << *t->type << std::endl; return t; }
static int swscale(SwsContext *c, const uint8_t *src[], int srcStride[], int srcSliceY, int srcSliceH, uint8_t *dst[], int dstStride[]) { /* load a few things into local vars to make the code more readable? * and faster */ #ifndef NEW_FILTER const int srcW = c->srcW; #endif const int dstW = c->dstW; const int dstH = c->dstH; #ifndef NEW_FILTER const int chrDstW = c->chrDstW; const int chrSrcW = c->chrSrcW; const int lumXInc = c->lumXInc; const int chrXInc = c->chrXInc; #endif const enum AVPixelFormat dstFormat = c->dstFormat; const int flags = c->flags; int32_t *vLumFilterPos = c->vLumFilterPos; int32_t *vChrFilterPos = c->vChrFilterPos; #ifndef NEW_FILTER int32_t *hLumFilterPos = c->hLumFilterPos; int32_t *hChrFilterPos = c->hChrFilterPos; int16_t *hLumFilter = c->hLumFilter; int16_t *hChrFilter = c->hChrFilter; int32_t *lumMmxFilter = c->lumMmxFilter; int32_t *chrMmxFilter = c->chrMmxFilter; #endif const int vLumFilterSize = c->vLumFilterSize; const int vChrFilterSize = c->vChrFilterSize; #ifndef NEW_FILTER const int hLumFilterSize = c->hLumFilterSize; const int hChrFilterSize = c->hChrFilterSize; int16_t **lumPixBuf = c->lumPixBuf; int16_t **chrUPixBuf = c->chrUPixBuf; int16_t **chrVPixBuf = c->chrVPixBuf; #endif int16_t **alpPixBuf = c->alpPixBuf; const int vLumBufSize = c->vLumBufSize; const int vChrBufSize = c->vChrBufSize; #ifndef NEW_FILTER uint8_t *formatConvBuffer = c->formatConvBuffer; uint32_t *pal = c->pal_yuv; #endif yuv2planar1_fn yuv2plane1 = c->yuv2plane1; yuv2planarX_fn yuv2planeX = c->yuv2planeX; yuv2interleavedX_fn yuv2nv12cX = c->yuv2nv12cX; yuv2packed1_fn yuv2packed1 = c->yuv2packed1; yuv2packed2_fn yuv2packed2 = c->yuv2packed2; yuv2packedX_fn yuv2packedX = c->yuv2packedX; yuv2anyX_fn yuv2anyX = c->yuv2anyX; const int chrSrcSliceY = srcSliceY >> c->chrSrcVSubSample; const int chrSrcSliceH = FF_CEIL_RSHIFT(srcSliceH, c->chrSrcVSubSample); int should_dither = is9_OR_10BPS(c->srcFormat) || is16BPS(c->srcFormat); int lastDstY; /* vars which will change and which we need to store back in the context */ int dstY = c->dstY; int lumBufIndex = c->lumBufIndex; int chrBufIndex = c->chrBufIndex; int lastInLumBuf = c->lastInLumBuf; int lastInChrBuf = c->lastInChrBuf; int perform_gamma = c->is_internal_gamma; #ifdef NEW_FILTER int lumStart = 0; int lumEnd = c->descIndex[0]; int chrStart = lumEnd; int chrEnd = c->descIndex[1]; int vStart = chrEnd; int vEnd = c->numDesc; SwsSlice *src_slice = &c->slice[lumStart]; SwsSlice *hout_slice = &c->slice[c->numSlice-2]; SwsSlice *vout_slice = &c->slice[c->numSlice-1]; SwsFilterDescriptor *desc = c->desc; int hasLumHoles = 1; int hasChrHoles = 1; #endif #ifndef NEW_FILTER if (!usePal(c->srcFormat)) { pal = c->input_rgb2yuv_table; } #endif if (isPacked(c->srcFormat)) { src[0] = src[1] = src[2] = src[3] = src[0]; srcStride[0] = srcStride[1] = srcStride[2] = srcStride[3] = srcStride[0]; } srcStride[1] <<= c->vChrDrop; srcStride[2] <<= c->vChrDrop; DEBUG_BUFFERS("swscale() %p[%d] %p[%d] %p[%d] %p[%d] -> %p[%d] %p[%d] %p[%d] %p[%d]\n", src[0], srcStride[0], src[1], srcStride[1], src[2], srcStride[2], src[3], srcStride[3], dst[0], dstStride[0], dst[1], dstStride[1], dst[2], dstStride[2], dst[3], dstStride[3]); DEBUG_BUFFERS("srcSliceY: %d srcSliceH: %d dstY: %d dstH: %d\n", srcSliceY, srcSliceH, dstY, dstH); DEBUG_BUFFERS("vLumFilterSize: %d vLumBufSize: %d vChrFilterSize: %d vChrBufSize: %d\n", vLumFilterSize, vLumBufSize, vChrFilterSize, vChrBufSize); if (dstStride[0]&15 || dstStride[1]&15 || dstStride[2]&15 || dstStride[3]&15) { static int warnedAlready = 0; // FIXME maybe move this into the context if (flags & SWS_PRINT_INFO && !warnedAlready) { av_log(c, AV_LOG_WARNING, "Warning: dstStride is not aligned!\n" " ->cannot do aligned memory accesses anymore\n"); warnedAlready = 1; } } if ( (uintptr_t)dst[0]&15 || (uintptr_t)dst[1]&15 || (uintptr_t)dst[2]&15 || (uintptr_t)src[0]&15 || (uintptr_t)src[1]&15 || (uintptr_t)src[2]&15 || dstStride[0]&15 || dstStride[1]&15 || dstStride[2]&15 || dstStride[3]&15 || srcStride[0]&15 || srcStride[1]&15 || srcStride[2]&15 || srcStride[3]&15 ) { static int warnedAlready=0; int cpu_flags = av_get_cpu_flags(); if (HAVE_MMXEXT && (cpu_flags & AV_CPU_FLAG_SSE2) && !warnedAlready){ av_log(c, AV_LOG_WARNING, "Warning: data is not aligned! This can lead to a speedloss\n"); warnedAlready=1; } } /* Note the user might start scaling the picture in the middle so this * will not get executed. This is not really intended but works * currently, so people might do it. */ if (srcSliceY == 0) { lumBufIndex = -1; chrBufIndex = -1; dstY = 0; lastInLumBuf = -1; lastInChrBuf = -1; } if (!should_dither) { c->chrDither8 = c->lumDither8 = sws_pb_64; } lastDstY = dstY; #ifdef NEW_FILTER ff_init_vscale_pfn(c, yuv2plane1, yuv2planeX, yuv2nv12cX, yuv2packed1, yuv2packed2, yuv2packedX, yuv2anyX, c->use_mmx_vfilter); ff_init_slice_from_src(src_slice, (uint8_t**)src, srcStride, c->srcW, srcSliceY, srcSliceH, chrSrcSliceY, chrSrcSliceH); ff_init_slice_from_src(vout_slice, (uint8_t**)dst, dstStride, c->dstW, dstY, dstH, dstY >> c->chrDstVSubSample, FF_CEIL_RSHIFT(dstH, c->chrDstVSubSample)); hout_slice->plane[0].sliceY = lastInLumBuf + 1; hout_slice->plane[1].sliceY = lastInChrBuf + 1; hout_slice->plane[2].sliceY = lastInChrBuf + 1; hout_slice->plane[3].sliceY = lastInLumBuf + 1; hout_slice->plane[0].sliceH = hout_slice->plane[1].sliceH = hout_slice->plane[2].sliceH = hout_slice->plane[3].sliceH = 0; hout_slice->width = dstW; #endif for (; dstY < dstH; dstY++) { const int chrDstY = dstY >> c->chrDstVSubSample; #ifndef NEW_FILTER uint8_t *dest[4] = { dst[0] + dstStride[0] * dstY, dst[1] + dstStride[1] * chrDstY, dst[2] + dstStride[2] * chrDstY, (CONFIG_SWSCALE_ALPHA && alpPixBuf) ? dst[3] + dstStride[3] * dstY : NULL, }; #endif int use_mmx_vfilter= c->use_mmx_vfilter; // First line needed as input const int firstLumSrcY = FFMAX(1 - vLumFilterSize, vLumFilterPos[dstY]); const int firstLumSrcY2 = FFMAX(1 - vLumFilterSize, vLumFilterPos[FFMIN(dstY | ((1 << c->chrDstVSubSample) - 1), dstH - 1)]); // First line needed as input const int firstChrSrcY = FFMAX(1 - vChrFilterSize, vChrFilterPos[chrDstY]); // Last line needed as input int lastLumSrcY = FFMIN(c->srcH, firstLumSrcY + vLumFilterSize) - 1; int lastLumSrcY2 = FFMIN(c->srcH, firstLumSrcY2 + vLumFilterSize) - 1; int lastChrSrcY = FFMIN(c->chrSrcH, firstChrSrcY + vChrFilterSize) - 1; int enough_lines; #ifdef NEW_FILTER int i; int posY, cPosY, firstPosY, lastPosY, firstCPosY, lastCPosY; #endif // handle holes (FAST_BILINEAR & weird filters) if (firstLumSrcY > lastInLumBuf) { #ifdef NEW_FILTER hasLumHoles = lastInLumBuf != firstLumSrcY - 1; if (hasLumHoles) { hout_slice->plane[0].sliceY = lastInLumBuf + 1; hout_slice->plane[3].sliceY = lastInLumBuf + 1; hout_slice->plane[0].sliceH = hout_slice->plane[3].sliceH = 0; } #endif lastInLumBuf = firstLumSrcY - 1; } if (firstChrSrcY > lastInChrBuf) { #ifdef NEW_FILTER hasChrHoles = lastInChrBuf != firstChrSrcY - 1; if (hasChrHoles) { hout_slice->plane[1].sliceY = lastInChrBuf + 1; hout_slice->plane[2].sliceY = lastInChrBuf + 1; hout_slice->plane[1].sliceH = hout_slice->plane[2].sliceH = 0; } #endif lastInChrBuf = firstChrSrcY - 1; } av_assert0(firstLumSrcY >= lastInLumBuf - vLumBufSize + 1); av_assert0(firstChrSrcY >= lastInChrBuf - vChrBufSize + 1); DEBUG_BUFFERS("dstY: %d\n", dstY); DEBUG_BUFFERS("\tfirstLumSrcY: %d lastLumSrcY: %d lastInLumBuf: %d\n", firstLumSrcY, lastLumSrcY, lastInLumBuf); DEBUG_BUFFERS("\tfirstChrSrcY: %d lastChrSrcY: %d lastInChrBuf: %d\n", firstChrSrcY, lastChrSrcY, lastInChrBuf); // Do we have enough lines in this slice to output the dstY line enough_lines = lastLumSrcY2 < srcSliceY + srcSliceH && lastChrSrcY < FF_CEIL_RSHIFT(srcSliceY + srcSliceH, c->chrSrcVSubSample); if (!enough_lines) { lastLumSrcY = srcSliceY + srcSliceH - 1; lastChrSrcY = chrSrcSliceY + chrSrcSliceH - 1; DEBUG_BUFFERS("buffering slice: lastLumSrcY %d lastChrSrcY %d\n", lastLumSrcY, lastChrSrcY); } #ifdef NEW_FILTER posY = hout_slice->plane[0].sliceY + hout_slice->plane[0].sliceH; if (posY <= lastLumSrcY && !hasLumHoles) { firstPosY = FFMAX(firstLumSrcY, posY); lastPosY = FFMIN(lastLumSrcY + MAX_LINES_AHEAD, srcSliceY + srcSliceH - 1); } else { firstPosY = lastInLumBuf + 1; lastPosY = lastLumSrcY; } cPosY = hout_slice->plane[1].sliceY + hout_slice->plane[1].sliceH; if (cPosY <= lastChrSrcY && !hasChrHoles) { firstCPosY = FFMAX(firstChrSrcY, cPosY); lastCPosY = FFMIN(lastChrSrcY + MAX_LINES_AHEAD, FF_CEIL_RSHIFT(srcSliceY + srcSliceH, c->chrSrcVSubSample) - 1); } else { firstCPosY = lastInChrBuf + 1; lastCPosY = lastChrSrcY; } ff_rotate_slice(hout_slice, lastPosY, lastCPosY); if (posY < lastLumSrcY + 1) { for (i = lumStart; i < lumEnd; ++i) desc[i].process(c, &desc[i], firstPosY, lastPosY - firstPosY + 1); } lumBufIndex += lastLumSrcY - lastInLumBuf; lastInLumBuf = lastLumSrcY; if (cPosY < lastChrSrcY + 1) { for (i = chrStart; i < chrEnd; ++i) desc[i].process(c, &desc[i], firstCPosY, lastCPosY - firstCPosY + 1); } chrBufIndex += lastChrSrcY - lastInChrBuf; lastInChrBuf = lastChrSrcY; #else // Do horizontal scaling while (lastInLumBuf < lastLumSrcY) { const uint8_t *src1[4] = { src[0] + (lastInLumBuf + 1 - srcSliceY) * srcStride[0], src[1] + (lastInLumBuf + 1 - srcSliceY) * srcStride[1], src[2] + (lastInLumBuf + 1 - srcSliceY) * srcStride[2], src[3] + (lastInLumBuf + 1 - srcSliceY) * srcStride[3], }; lumBufIndex++; av_assert0(lumBufIndex < 2 * vLumBufSize); av_assert0(lastInLumBuf + 1 - srcSliceY < srcSliceH); av_assert0(lastInLumBuf + 1 - srcSliceY >= 0); if (perform_gamma) gamma_convert((uint8_t **)src1, srcW, c->inv_gamma); hyscale(c, lumPixBuf[lumBufIndex], dstW, src1, srcW, lumXInc, hLumFilter, hLumFilterPos, hLumFilterSize, formatConvBuffer, pal, 0); if (CONFIG_SWSCALE_ALPHA && alpPixBuf) hyscale(c, alpPixBuf[lumBufIndex], dstW, src1, srcW, lumXInc, hLumFilter, hLumFilterPos, hLumFilterSize, formatConvBuffer, pal, 1); lastInLumBuf++; DEBUG_BUFFERS("\t\tlumBufIndex %d: lastInLumBuf: %d\n", lumBufIndex, lastInLumBuf); } while (lastInChrBuf < lastChrSrcY) { const uint8_t *src1[4] = { src[0] + (lastInChrBuf + 1 - chrSrcSliceY) * srcStride[0], src[1] + (lastInChrBuf + 1 - chrSrcSliceY) * srcStride[1], src[2] + (lastInChrBuf + 1 - chrSrcSliceY) * srcStride[2], src[3] + (lastInChrBuf + 1 - chrSrcSliceY) * srcStride[3], }; chrBufIndex++; av_assert0(chrBufIndex < 2 * vChrBufSize); av_assert0(lastInChrBuf + 1 - chrSrcSliceY < (chrSrcSliceH)); av_assert0(lastInChrBuf + 1 - chrSrcSliceY >= 0); // FIXME replace parameters through context struct (some at least) if (c->needs_hcscale) hcscale(c, chrUPixBuf[chrBufIndex], chrVPixBuf[chrBufIndex], chrDstW, src1, chrSrcW, chrXInc, hChrFilter, hChrFilterPos, hChrFilterSize, formatConvBuffer, pal); lastInChrBuf++; DEBUG_BUFFERS("\t\tchrBufIndex %d: lastInChrBuf: %d\n", chrBufIndex, lastInChrBuf); } #endif // wrap buf index around to stay inside the ring buffer if (lumBufIndex >= vLumBufSize) lumBufIndex -= vLumBufSize; if (chrBufIndex >= vChrBufSize) chrBufIndex -= vChrBufSize; if (!enough_lines) break; // we can't output a dstY line so let's try with the next slice #if HAVE_MMX_INLINE ff_updateMMXDitherTables(c, dstY, lumBufIndex, chrBufIndex, lastInLumBuf, lastInChrBuf); #endif if (should_dither) { c->chrDither8 = ff_dither_8x8_128[chrDstY & 7]; c->lumDither8 = ff_dither_8x8_128[dstY & 7]; } if (dstY >= dstH - 2) { /* hmm looks like we can't use MMX here without overwriting * this array's tail */ ff_sws_init_output_funcs(c, &yuv2plane1, &yuv2planeX, &yuv2nv12cX, &yuv2packed1, &yuv2packed2, &yuv2packedX, &yuv2anyX); use_mmx_vfilter= 0; ff_init_vscale_pfn(c, yuv2plane1, yuv2planeX, yuv2nv12cX, yuv2packed1, yuv2packed2, yuv2packedX, yuv2anyX, use_mmx_vfilter); } { #ifdef NEW_FILTER for (i = vStart; i < vEnd; ++i) desc[i].process(c, &desc[i], dstY, 1); #else const int16_t **lumSrcPtr = (const int16_t **)(void*) lumPixBuf + lumBufIndex + firstLumSrcY - lastInLumBuf + vLumBufSize; const int16_t **chrUSrcPtr = (const int16_t **)(void*) chrUPixBuf + chrBufIndex + firstChrSrcY - lastInChrBuf + vChrBufSize; const int16_t **chrVSrcPtr = (const int16_t **)(void*) chrVPixBuf + chrBufIndex + firstChrSrcY - lastInChrBuf + vChrBufSize; const int16_t **alpSrcPtr = (CONFIG_SWSCALE_ALPHA && alpPixBuf) ? (const int16_t **)(void*) alpPixBuf + lumBufIndex + firstLumSrcY - lastInLumBuf + vLumBufSize : NULL; int16_t *vLumFilter = c->vLumFilter; int16_t *vChrFilter = c->vChrFilter; if (isPlanarYUV(dstFormat) || (isGray(dstFormat) && !isALPHA(dstFormat))) { // YV12 like const int chrSkipMask = (1 << c->chrDstVSubSample) - 1; vLumFilter += dstY * vLumFilterSize; vChrFilter += chrDstY * vChrFilterSize; // av_assert0(use_mmx_vfilter != ( // yuv2planeX == yuv2planeX_10BE_c // || yuv2planeX == yuv2planeX_10LE_c // || yuv2planeX == yuv2planeX_9BE_c // || yuv2planeX == yuv2planeX_9LE_c // || yuv2planeX == yuv2planeX_16BE_c // || yuv2planeX == yuv2planeX_16LE_c // || yuv2planeX == yuv2planeX_8_c) || !ARCH_X86); if(use_mmx_vfilter){ vLumFilter= (int16_t *)c->lumMmxFilter; vChrFilter= (int16_t *)c->chrMmxFilter; } if (vLumFilterSize == 1) { yuv2plane1(lumSrcPtr[0], dest[0], dstW, c->lumDither8, 0); } else { yuv2planeX(vLumFilter, vLumFilterSize, lumSrcPtr, dest[0], dstW, c->lumDither8, 0); } if (!((dstY & chrSkipMask) || isGray(dstFormat))) { if (yuv2nv12cX) { yuv2nv12cX(c, vChrFilter, vChrFilterSize, chrUSrcPtr, chrVSrcPtr, dest[1], chrDstW); } else if (vChrFilterSize == 1) { yuv2plane1(chrUSrcPtr[0], dest[1], chrDstW, c->chrDither8, 0); yuv2plane1(chrVSrcPtr[0], dest[2], chrDstW, c->chrDither8, 3); } else { yuv2planeX(vChrFilter, vChrFilterSize, chrUSrcPtr, dest[1], chrDstW, c->chrDither8, 0); yuv2planeX(vChrFilter, vChrFilterSize, chrVSrcPtr, dest[2], chrDstW, c->chrDither8, use_mmx_vfilter ? (c->uv_offx2 >> 1) : 3); } } if (CONFIG_SWSCALE_ALPHA && alpPixBuf) { if(use_mmx_vfilter){ vLumFilter= (int16_t *)c->alpMmxFilter; } if (vLumFilterSize == 1) { yuv2plane1(alpSrcPtr[0], dest[3], dstW, c->lumDither8, 0); } else { yuv2planeX(vLumFilter, vLumFilterSize, alpSrcPtr, dest[3], dstW, c->lumDither8, 0); } } } else if (yuv2packedX) { av_assert1(lumSrcPtr + vLumFilterSize - 1 < (const int16_t **)lumPixBuf + vLumBufSize * 2); av_assert1(chrUSrcPtr + vChrFilterSize - 1 < (const int16_t **)chrUPixBuf + vChrBufSize * 2); if (c->yuv2packed1 && vLumFilterSize == 1 && vChrFilterSize <= 2) { // unscaled RGB int chrAlpha = vChrFilterSize == 1 ? 0 : vChrFilter[2 * dstY + 1]; yuv2packed1(c, *lumSrcPtr, chrUSrcPtr, chrVSrcPtr, alpPixBuf ? *alpSrcPtr : NULL, dest[0], dstW, chrAlpha, dstY); } else if (c->yuv2packed2 && vLumFilterSize == 2 && vChrFilterSize == 2) { // bilinear upscale RGB int lumAlpha = vLumFilter[2 * dstY + 1]; int chrAlpha = vChrFilter[2 * dstY + 1]; lumMmxFilter[2] = lumMmxFilter[3] = vLumFilter[2 * dstY] * 0x10001; chrMmxFilter[2] = chrMmxFilter[3] = vChrFilter[2 * chrDstY] * 0x10001; yuv2packed2(c, lumSrcPtr, chrUSrcPtr, chrVSrcPtr, alpPixBuf ? alpSrcPtr : NULL, dest[0], dstW, lumAlpha, chrAlpha, dstY); } else { // general RGB yuv2packedX(c, vLumFilter + dstY * vLumFilterSize, lumSrcPtr, vLumFilterSize, vChrFilter + dstY * vChrFilterSize, chrUSrcPtr, chrVSrcPtr, vChrFilterSize, alpSrcPtr, dest[0], dstW, dstY); } } else { av_assert1(!yuv2packed1 && !yuv2packed2); yuv2anyX(c, vLumFilter + dstY * vLumFilterSize, lumSrcPtr, vLumFilterSize, vChrFilter + dstY * vChrFilterSize, chrUSrcPtr, chrVSrcPtr, vChrFilterSize, alpSrcPtr, dest, dstW, dstY); } if (perform_gamma) gamma_convert(dest, dstW, c->gamma); #endif } }