зеркало из https://github.com/dotnet/llilc.git
Merge pull request #316 from erozenfeld/StoreElem1
Implement storing of array elements.
This commit is contained in:
Коммит
f6100e53ba
|
@ -2220,9 +2220,11 @@ public:
|
|||
virtual void storeArg(uint32_t LocOrdinal, IRNode *Arg1,
|
||||
ReaderAlignType Alignment, bool IsVolatile) = 0;
|
||||
virtual void storeElem(ReaderBaseNS::StElemOpcode Opcode,
|
||||
CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Arg1,
|
||||
IRNode *Arg2, IRNode *Arg3) = 0;
|
||||
virtual void storeElemRefAny(IRNode *Value, IRNode *Index, IRNode *Obj);
|
||||
CORINFO_RESOLVED_TOKEN *ResolvedToken,
|
||||
IRNode *ValueToStore, IRNode *Index,
|
||||
IRNode *Array) = 0;
|
||||
virtual void storeElemRefAny(IRNode *ValueToStore, IRNode *Index,
|
||||
IRNode *Array);
|
||||
virtual void storeField(CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Arg1,
|
||||
IRNode *Arg2, ReaderAlignType Alignment,
|
||||
bool IsVolatile) = 0;
|
||||
|
|
|
@ -418,10 +418,8 @@ public:
|
|||
void storeArg(uint32_t ArgOrdinal, IRNode *Arg1, ReaderAlignType Alignment,
|
||||
bool IsVolatile) override;
|
||||
void storeElem(ReaderBaseNS::StElemOpcode Opcode,
|
||||
CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Arg1,
|
||||
IRNode *Arg2, IRNode *Arg3) override {
|
||||
throw NotYetImplementedException("storeElem");
|
||||
};
|
||||
CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *ValueToStore,
|
||||
IRNode *Index, IRNode *Array) override;
|
||||
|
||||
void storeField(CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Arg1,
|
||||
IRNode *Arg2, ReaderAlignType Alignment,
|
||||
|
@ -826,10 +824,10 @@ private:
|
|||
|
||||
/// Convert node to the desired type.
|
||||
/// May reinterpret, truncate, or extend as needed.
|
||||
/// \p Type - Desired type
|
||||
/// \p Node - Value to be converted
|
||||
/// \p IsSigned - Perform sign extension if necessary, otherwise
|
||||
/// integral values are zero extended
|
||||
/// \param Type Desired type
|
||||
/// \param Node Value to be converted
|
||||
/// \param IsSigned Perform sign extension if necessary, otherwise
|
||||
/// integral values are zero extended
|
||||
IRNode *convert(llvm::Type *Type, llvm::Value *Node, bool IsSigned);
|
||||
|
||||
llvm::Type *binaryOpType(llvm::Type *Type1, llvm::Type *Type2);
|
||||
|
@ -849,14 +847,14 @@ private:
|
|||
/// Generate instructions for loading value of the specified type at the
|
||||
/// specified address.
|
||||
///
|
||||
/// \p Address - Address to load from.
|
||||
/// \p Ty - llvm type of the value to load.
|
||||
/// \p CorType - CorInfoType of the value to load.
|
||||
/// \p ResolvedToken - Resolved token corresponding to the type of the value
|
||||
/// to load.
|
||||
/// \p AlignmentPrefix - Alignment of the value.
|
||||
/// \p IsVolatile - true if the load is volatile.
|
||||
/// \p AddressMayBeNull - true if the address may be null.
|
||||
/// \param Address Address to load from.
|
||||
/// \param Ty llvm type of the value to load.
|
||||
/// \param CorType CorInfoType of the value to load.
|
||||
/// \param ResolvedToken Resolved token corresponding to the type of the value
|
||||
/// to load.
|
||||
/// \param AlignmentPrefix Alignment of the value.
|
||||
/// \param IsVolatile true iff the load is volatile.
|
||||
/// \param AddressMayBeNull true iff the address may be null.
|
||||
/// \returns Value at the specified address.
|
||||
IRNode *loadAtAddress(IRNode *Address, llvm::Type *Ty, CorInfoType CorType,
|
||||
CORINFO_RESOLVED_TOKEN *ResolvedToken,
|
||||
|
@ -872,22 +870,49 @@ private:
|
|||
IsVolatile, false);
|
||||
}
|
||||
|
||||
/// Generate instructions for storing value of the specified type at the
|
||||
/// specified address.
|
||||
///
|
||||
/// \param Address Address to store to.
|
||||
/// \param ValueToStore Value to store.
|
||||
/// \param Ty llvm type of the value to store.
|
||||
/// \param ResolvedToken Resolved token corresponding to the type of the value
|
||||
/// to store.
|
||||
/// \param AlignmentPrefix Alignment of the value.
|
||||
/// \param IsVolatile true iff the store is volatile.
|
||||
/// \param IsField true iff this is a field address.
|
||||
/// \param AddressMayBeNull true iff the address may be null.
|
||||
void storeAtAddress(IRNode *Address, IRNode *ValueToStore, llvm::Type *Ty,
|
||||
CORINFO_RESOLVED_TOKEN *ResolvedToken,
|
||||
ReaderAlignType AlignmentPrefix, bool IsVolatile,
|
||||
bool IsField, bool AddressMayBeNull);
|
||||
|
||||
void storeAtAddressNonNull(IRNode *Address, IRNode *ValueToStore,
|
||||
llvm::Type *Ty,
|
||||
CORINFO_RESOLVED_TOKEN *ResolvedToken,
|
||||
ReaderAlignType AlignmentPrefix, bool IsVolatile,
|
||||
bool IsField) {
|
||||
return storeAtAddress(Address, ValueToStore, Ty, ResolvedToken,
|
||||
AlignmentPrefix, IsVolatile, IsField, false);
|
||||
|
||||
}
|
||||
|
||||
void classifyCmpType(llvm::Type *Ty, uint32_t &Size, bool &IsPointer,
|
||||
bool &IsFloat);
|
||||
|
||||
/// Generate a call to the throw helper if the condition is met.
|
||||
///
|
||||
/// \p Condition - Condition that will trigger the throw.
|
||||
/// \p HelperId - Id of the throw-helper.
|
||||
/// \p ThrowBlockName - Name of the basic block that will contain the throw.
|
||||
/// \param Condition Condition that will trigger the throw.
|
||||
/// \param HelperId Id of the throw-helper.
|
||||
/// \param ThrowBlockName Name of the basic block that will contain the throw.
|
||||
void genConditionalThrow(llvm::Value *Condition, CorInfoHelpFunc HelperId,
|
||||
const llvm::Twine &ThrowBlockName);
|
||||
|
||||
/// Generate array bounds check.
|
||||
///
|
||||
/// \p Array - Array to be accessed.
|
||||
/// \p Index - Index to be accessed.
|
||||
/// \returns - The input array.
|
||||
/// \param Array Array to be accessed.
|
||||
/// \param Index Index to be accessed.
|
||||
/// \returns The input array.
|
||||
IRNode *genBoundsCheck(IRNode *Array, IRNode *Index);
|
||||
|
||||
uint32_t size(CorInfoType CorType);
|
||||
|
@ -897,17 +922,17 @@ private:
|
|||
|
||||
/// Convert a result to a valid stack type,
|
||||
/// generally by either reinterpretation or extension.
|
||||
/// \p Node - Value to be converted
|
||||
/// \p CorType - additional information needed to determine if
|
||||
/// Node's type is signed or unsigned
|
||||
/// \param Node Value to be converted
|
||||
/// \param CorType additional information needed to determine if
|
||||
/// Node's type is signed or unsigned
|
||||
IRNode *convertToStackType(IRNode *Node, CorInfoType CorType);
|
||||
|
||||
/// Convert a result from a stack type to the desired type,
|
||||
/// generally by either reinterpretation or truncation.
|
||||
/// \p Node - Value to be converted
|
||||
/// \p CorType - additional information needed to determine if
|
||||
/// ResultTy is signed or unsigned
|
||||
/// \p ResultTy - Desired type
|
||||
/// \param Node Value to be converted
|
||||
/// \param CorType additional information needed to determine if
|
||||
/// ResultTy is signed or unsigned
|
||||
/// \param ResultTy - Desired type
|
||||
IRNode *convertFromStackType(IRNode *Node, CorInfoType CorType,
|
||||
llvm::Type *ResultTy);
|
||||
|
||||
|
@ -916,7 +941,7 @@ private:
|
|||
/// Create a new temporary variable that can be
|
||||
/// used anywhere within the method.
|
||||
///
|
||||
/// \p Ty - Type for the new variable.
|
||||
/// \param Ty Type for the new variable.
|
||||
/// \returns Instruction establishing the variable's location.
|
||||
llvm::Instruction *createTemporary(llvm::Type *Ty);
|
||||
|
||||
|
@ -948,13 +973,33 @@ private:
|
|||
|
||||
/// Get address of the array element.
|
||||
///
|
||||
/// \p Array - Array that the element belongs to.
|
||||
/// \p Index - Index of the element.
|
||||
/// \p ElementTy - Type of the element.
|
||||
/// \param Array Array that the element belongs to.
|
||||
/// \param Index Index of the element.
|
||||
/// \param ElementTy Type of the element.
|
||||
/// \returns Value representing the address of the element.
|
||||
llvm::Value *genArrayElemAddress(IRNode *Array, IRNode *Index,
|
||||
llvm::Type *ElementTy);
|
||||
|
||||
/// Convert ReaderAlignType to byte alighnment to byte alignment.
|
||||
///
|
||||
/// \param ReaderAlignment Reader alignment.
|
||||
/// \returns Alignment in bytes.
|
||||
uint32_t convertReaderAlignment(ReaderAlignType ReaderAlignment);
|
||||
|
||||
/// Get array element type.
|
||||
///
|
||||
/// \param Array Array node.
|
||||
/// \param ResolvedToken Resolved token from ldelem or stelem instruction.
|
||||
/// \param CorInfoType [IN/OUT] Type of the element (will be resolved for
|
||||
/// CORINFO_TYPE_UNDEF).
|
||||
/// \param Alignment - [IN/OUT] Alignment that will be updated for value
|
||||
/// classes.
|
||||
/// \returns Array element type.
|
||||
llvm::Type *getArrayElementType(IRNode *Array,
|
||||
CORINFO_RESOLVED_TOKEN *ResolvedToken,
|
||||
CorInfoType *CorType,
|
||||
ReaderAlignType *Alignment);
|
||||
|
||||
private:
|
||||
LLILCJitContext *JitContext;
|
||||
llvm::Function *Function;
|
||||
|
|
|
@ -553,6 +553,14 @@ IRNode *GenIR::instParam() {
|
|||
return (IRNode *)TypeParameter;
|
||||
}
|
||||
|
||||
// Convert ReaderAlignType to byte alighnment
|
||||
uint32_t GenIR::convertReaderAlignment(ReaderAlignType ReaderAlignment) {
|
||||
uint32_t Result = (ReaderAlignment == Reader_AlignNatural)
|
||||
? TargetPointerSizeInBits / 8
|
||||
: ReaderAlignment;
|
||||
return Result;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region DIAGNOSTICS
|
||||
|
@ -2547,9 +2555,7 @@ IRNode *GenIR::loadAtAddress(IRNode *Address, Type *Ty, CorInfoType CorType,
|
|||
AddressMayBeNull);
|
||||
} else {
|
||||
LoadInst *LoadInst = makeLoad(Address, IsVolatile, AddressMayBeNull);
|
||||
uint32_t Align = (AlignmentPrefix == Reader_AlignNatural)
|
||||
? TargetPointerSizeInBits / 8
|
||||
: AlignmentPrefix;
|
||||
uint32_t Align = convertReaderAlignment(AlignmentPrefix);
|
||||
LoadInst->setAlignment(Align);
|
||||
|
||||
IRNode *Result = convertToStackType((IRNode *)LoadInst, CorType);
|
||||
|
@ -2558,6 +2564,25 @@ IRNode *GenIR::loadAtAddress(IRNode *Address, Type *Ty, CorInfoType CorType,
|
|||
}
|
||||
}
|
||||
|
||||
// Generate instructions for storing value of the specified type at the
|
||||
// specified address.
|
||||
void GenIR::storeAtAddress(IRNode *Address, IRNode *ValueToStore, Type *Ty,
|
||||
CORINFO_RESOLVED_TOKEN *ResolvedToken,
|
||||
ReaderAlignType Alignment, bool IsVolatile,
|
||||
bool IsField, bool AddressMayBeNull) {
|
||||
// We do things differently based on whether the field is a value class.
|
||||
if (Ty->isStructTy()) {
|
||||
storeObj(ResolvedToken, ValueToStore, Address, Alignment, IsVolatile,
|
||||
IsField, AddressMayBeNull);
|
||||
}
|
||||
else {
|
||||
StoreInst *StoreInst = makeStore(ValueToStore, Address, IsVolatile,
|
||||
AddressMayBeNull);
|
||||
uint32_t Align = convertReaderAlignment(Alignment);
|
||||
StoreInst->setAlignment(Align);
|
||||
}
|
||||
}
|
||||
|
||||
void GenIR::storeField(CORINFO_RESOLVED_TOKEN *FieldToken, IRNode *ValueToStore,
|
||||
IRNode *Object, ReaderAlignType Alignment,
|
||||
bool IsVolatile) {
|
||||
|
@ -2620,21 +2645,9 @@ void GenIR::storeField(CORINFO_RESOLVED_TOKEN *FieldToken, IRNode *ValueToStore,
|
|||
return;
|
||||
}
|
||||
|
||||
// We do things differently based on whether the field is a value class.
|
||||
if (!IsStructTy) {
|
||||
makeStore(ValueToStore, Address, IsVolatile, !NullCheckBeforeStore);
|
||||
return;
|
||||
} else {
|
||||
// The WVM lowerer cannot handle multi-byte indirs whose base pointer
|
||||
// is the address of a field.
|
||||
if (FieldCorType == CORINFO_TYPE_VALUECLASS ||
|
||||
FieldCorType == CORINFO_TYPE_REFANY) {
|
||||
Alignment = getMinimumClassAlignment(FieldClassHandle, Alignment);
|
||||
}
|
||||
storeObj(FieldToken, ValueToStore, Address, Alignment, IsVolatile, true,
|
||||
!NullCheckBeforeStore);
|
||||
return;
|
||||
}
|
||||
bool IsField = true;
|
||||
return storeAtAddress(Address, ValueToStore, FieldTy, FieldToken, Alignment,
|
||||
IsVolatile, IsField, !NullCheckBeforeStore);
|
||||
}
|
||||
|
||||
void GenIR::storePrimitiveType(IRNode *Value, IRNode *Addr,
|
||||
|
@ -2807,32 +2820,15 @@ IRNode *GenIR::loadElem(ReaderBaseNS::LdElemOpcode Opcode,
|
|||
ASSERTNR(Opcode >= ReaderBaseNS::LdelemI1 &&
|
||||
Opcode < ReaderBaseNS::LastLdelemOpcode);
|
||||
|
||||
CORINFO_CLASS_HANDLE ClassHandle = nullptr;
|
||||
Type *ElementTy = nullptr;
|
||||
CorInfoType CorType = Map[Opcode];
|
||||
ReaderAlignType Alignment = Reader_AlignNatural;
|
||||
|
||||
if (CorType == CorInfoType::CORINFO_TYPE_CLASS) {
|
||||
PointerType *Ty = cast<PointerType>(Array->getType());
|
||||
StructType *ReferentTy = cast<StructType>(Ty->getPointerElementType());
|
||||
unsigned int NumElements = ReferentTy->getNumElements();
|
||||
ArrayType *ArrayTy =
|
||||
cast<ArrayType>(ReferentTy->getElementType(NumElements - 1));
|
||||
ElementTy = ArrayTy->getElementType();
|
||||
} else {
|
||||
// The type is either specified via token (for ldelem) or is primitive.
|
||||
if (Opcode == ReaderBaseNS::Ldelem) {
|
||||
ASSERTNR(ResolvedToken != nullptr);
|
||||
ClassHandle = ResolvedToken->hClass;
|
||||
|
||||
CorType = JitContext->JitInfo->asCorInfoType(ClassHandle);
|
||||
if (CorType == CorInfoType::CORINFO_TYPE_VALUECLASS) {
|
||||
Alignment = getMinimumClassAlignment(ClassHandle, Reader_AlignNatural);
|
||||
}
|
||||
}
|
||||
ASSERTNR(CorType != CorInfoType::CORINFO_TYPE_UNDEF);
|
||||
ElementTy = getType(CorType, ClassHandle);
|
||||
// ResolvedToken is only valid for ldelem.
|
||||
if (Opcode != ReaderBaseNS::Ldelem) {
|
||||
ResolvedToken = nullptr;
|
||||
}
|
||||
Type *ElementTy = getArrayElementType(Array, ResolvedToken, &CorType,
|
||||
&Alignment);
|
||||
|
||||
Value *ElementAddress = genArrayElemAddress(Array, Index, ElementTy);
|
||||
bool IsVolatile = false;
|
||||
|
@ -2861,6 +2857,95 @@ IRNode *GenIR::loadElemA(CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Index,
|
|||
return (IRNode *)genArrayElemAddress(Array, Index, ElementTy);
|
||||
}
|
||||
|
||||
void GenIR::storeElem(ReaderBaseNS::StElemOpcode Opcode,
|
||||
CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *ValueToStore, IRNode *Index,
|
||||
IRNode *Array) {
|
||||
static const CorInfoType Map[ReaderBaseNS::LastStelemOpcode] = {
|
||||
CorInfoType::CORINFO_TYPE_NATIVEINT, // STELEM_I
|
||||
CorInfoType::CORINFO_TYPE_BYTE, // STELEM_I1
|
||||
CorInfoType::CORINFO_TYPE_SHORT, // STELEM_I2
|
||||
CorInfoType::CORINFO_TYPE_INT, // STELEM_I4
|
||||
CorInfoType::CORINFO_TYPE_LONG, // STELEM_I8
|
||||
CorInfoType::CORINFO_TYPE_FLOAT, // STELEM_R4
|
||||
CorInfoType::CORINFO_TYPE_DOUBLE, // STELEM_R8
|
||||
CorInfoType::CORINFO_TYPE_CLASS, // STELEM_REF
|
||||
CorInfoType::CORINFO_TYPE_UNDEF // STELEM
|
||||
};
|
||||
|
||||
ASSERTNR(Opcode >= ReaderBaseNS::StelemI &&
|
||||
Opcode < ReaderBaseNS::LastStelemOpcode);
|
||||
|
||||
CorInfoType CorType = Map[Opcode];
|
||||
ReaderAlignType Alignment = Reader_AlignNatural;
|
||||
|
||||
// ResolvedToken is only valid for stelem.
|
||||
if (Opcode != ReaderBaseNS::Stelem) {
|
||||
ResolvedToken = nullptr;
|
||||
}
|
||||
|
||||
Type *ElementTy = getArrayElementType(Array, ResolvedToken, &CorType,
|
||||
&Alignment);
|
||||
|
||||
if (CorType == CorInfoType::CORINFO_TYPE_CLASS) {
|
||||
Constant *ConstantValue = dyn_cast<Constant>(ValueToStore);
|
||||
if (ConstantValue == nullptr || !ConstantValue->isNullValue()) {
|
||||
// This will call a helper that stores an element of object array with
|
||||
// type checking. It will also call a write barrier if necessary. Storing
|
||||
// null is always legal, doesn't need a write barrier, and thus does not
|
||||
// need a helper call.
|
||||
return storeElemRefAny(ValueToStore, Index, Array);
|
||||
}
|
||||
}
|
||||
|
||||
Value *ElementAddress = genArrayElemAddress(Array, Index, ElementTy);
|
||||
bool IsVolatile = false;
|
||||
bool IsField = false;
|
||||
ValueToStore = convertFromStackType(ValueToStore, CorType, ElementTy);
|
||||
if (ElementTy->isStructTy()) {
|
||||
bool IsNonValueClass = false;
|
||||
bool IsValueIsPointer = false;
|
||||
bool IsUnchecked = false;
|
||||
// Store with a write barrier if the struct has gc pointers.
|
||||
rdrCallWriteBarrierHelper(Array, ValueToStore, Alignment, IsVolatile,
|
||||
ResolvedToken, IsNonValueClass, IsValueIsPointer,
|
||||
IsField, IsUnchecked);
|
||||
}
|
||||
else {
|
||||
storeAtAddressNonNull((IRNode *)ElementAddress, ValueToStore,
|
||||
ElementTy, ResolvedToken, Alignment, IsVolatile,
|
||||
IsField);
|
||||
}
|
||||
}
|
||||
|
||||
// Get array element type.
|
||||
Type *GenIR::getArrayElementType(IRNode *Array,
|
||||
CORINFO_RESOLVED_TOKEN *ResolvedToken,
|
||||
CorInfoType *CorType,
|
||||
ReaderAlignType *Alignment) {
|
||||
ASSERTNR(Alignment != nullptr);
|
||||
ASSERTNR(CorType != nullptr);
|
||||
CORINFO_CLASS_HANDLE ClassHandle = nullptr;
|
||||
if (*CorType == CorInfoType::CORINFO_TYPE_CLASS) {
|
||||
PointerType *Ty = cast<PointerType>(Array->getType());
|
||||
StructType *ReferentTy = cast<StructType>(Ty->getPointerElementType());
|
||||
unsigned int NumElements = ReferentTy->getNumElements();
|
||||
ArrayType *ArrayTy =
|
||||
cast<ArrayType>(ReferentTy->getElementType(NumElements - 1));
|
||||
return ArrayTy->getElementType();
|
||||
}
|
||||
|
||||
if (ResolvedToken != nullptr) {
|
||||
ClassHandle = ResolvedToken->hClass;
|
||||
*CorType = JitContext->JitInfo->asCorInfoType(ClassHandle);
|
||||
if ((*CorType == CorInfoType::CORINFO_TYPE_VALUECLASS) ||
|
||||
(*CorType == CORINFO_TYPE_REFANY)) {
|
||||
*Alignment = getMinimumClassAlignment(ClassHandle, Reader_AlignNatural);
|
||||
}
|
||||
}
|
||||
ASSERTNR(*CorType != CorInfoType::CORINFO_TYPE_UNDEF);
|
||||
return getType(*CorType, ClassHandle);
|
||||
}
|
||||
|
||||
// Get address of the array element.
|
||||
Value *GenIR::genArrayElemAddress(IRNode *Array, IRNode *Index,
|
||||
Type *ElementTy) {
|
||||
|
@ -3963,8 +4048,7 @@ IRNode *GenIR::getPrimitiveAddress(IRNode *Addr, CorInfoType CorInfoType,
|
|||
}
|
||||
}
|
||||
|
||||
*Align = (Alignment == Reader_AlignNatural) ? TargetPointerSizeInBits / 8
|
||||
: Alignment;
|
||||
*Align = convertReaderAlignment(Alignment);
|
||||
return TypedAddr;
|
||||
}
|
||||
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче