зеркало из https://github.com/dotnet/llilc.git
Merge pull request #265 from erozenfeld/LoadElem1
Implement loading of array elements.
This commit is contained in:
Коммит
9e371b5838
|
@ -2014,10 +2014,10 @@ public:
|
|||
virtual IRNode *loadConstantR4(float Value) = 0;
|
||||
virtual IRNode *loadConstantR8(double Value) = 0;
|
||||
virtual IRNode *loadElem(ReaderBaseNS::LdElemOpcode Opcode,
|
||||
CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Arg1,
|
||||
IRNode *Arg2) = 0;
|
||||
virtual IRNode *loadElemA(CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Arg1,
|
||||
IRNode *Arg2, bool IsReadOnly) = 0;
|
||||
CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Index,
|
||||
IRNode *Array) = 0;
|
||||
virtual IRNode *loadElemA(CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Index,
|
||||
IRNode *Array, bool IsReadOnly) = 0;
|
||||
virtual IRNode *loadField(CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Arg1,
|
||||
ReaderAlignType Alignment, bool IsVolatile) = 0;
|
||||
virtual IRNode *loadIndir(ReaderBaseNS::LdIndirOpcode Opcode, IRNode *Address,
|
||||
|
|
|
@ -335,14 +335,10 @@ public:
|
|||
IRNode *loadConstantR4(float Value) override;
|
||||
IRNode *loadConstantR8(double Value) override;
|
||||
IRNode *loadElem(ReaderBaseNS::LdElemOpcode Opcode,
|
||||
CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Arg1,
|
||||
IRNode *Arg2) override {
|
||||
throw NotYetImplementedException("loadElem");
|
||||
};
|
||||
IRNode *loadElemA(CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Arg1,
|
||||
IRNode *Arg2, bool IsReadOnly) override {
|
||||
throw NotYetImplementedException("loadElemA");
|
||||
};
|
||||
CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Index,
|
||||
IRNode *Array) override;
|
||||
IRNode *loadElemA(CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Index,
|
||||
IRNode *Array, bool IsReadOnly) override;
|
||||
IRNode *loadField(CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Arg1,
|
||||
ReaderAlignType Alignment, bool IsVolatile) override;
|
||||
|
||||
|
@ -853,10 +849,50 @@ private:
|
|||
|
||||
IRNode *getPrimitiveAddress(IRNode *Addr, CorInfoType CorInfoType,
|
||||
ReaderAlignType Alignment, uint32_t *Align);
|
||||
/// 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.
|
||||
/// \returns Value at the specified address.
|
||||
IRNode *loadAtAddress(IRNode *Address, llvm::Type *Ty, CorInfoType CorType,
|
||||
CORINFO_RESOLVED_TOKEN *ResolvedToken,
|
||||
ReaderAlignType AlignmentPrefix, bool IsVolatile,
|
||||
bool AddressMayBeNull=true);
|
||||
|
||||
IRNode *loadAtAddressNonNull(IRNode *Address, llvm::Type *Ty,
|
||||
CorInfoType CorType,
|
||||
CORINFO_RESOLVED_TOKEN *ResolvedToken,
|
||||
ReaderAlignType AlignmentPrefix,
|
||||
bool IsVolatile) {
|
||||
return loadAtAddress(Address, Ty, CorType, ResolvedToken, AlignmentPrefix,
|
||||
IsVolatile, 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.
|
||||
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.
|
||||
IRNode *genBoundsCheck(IRNode *Array, IRNode *Index);
|
||||
|
||||
uint32_t size(CorInfoType CorType);
|
||||
uint32_t stackSize(CorInfoType CorType);
|
||||
static bool isSigned(CorInfoType CorType);
|
||||
|
@ -913,6 +949,15 @@ private:
|
|||
return makeLoad(Address, IsVolatile, false);
|
||||
}
|
||||
|
||||
/// 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.
|
||||
/// \returns Value representing the address of the element.
|
||||
llvm::Value *genArrayElemAddress(IRNode *Array, IRNode *Index,
|
||||
llvm::Type *ElementTy);
|
||||
|
||||
private:
|
||||
LLILCJitContext *JitContext;
|
||||
llvm::Function *Function;
|
||||
|
|
|
@ -4066,17 +4066,17 @@ IRNode *ReaderBase::loadIndir(ReaderBaseNS::LdIndirOpcode Opcode,
|
|||
bool IsVolatile, bool IsInterfReadOnly,
|
||||
bool AddressMayBeNull) {
|
||||
static const CorInfoType Map[ReaderBaseNS::LastLdindOpcode] = {
|
||||
CORINFO_TYPE_BYTE, // STIND_I1
|
||||
CORINFO_TYPE_UBYTE, // STIND_U1
|
||||
CORINFO_TYPE_SHORT, // STIND_I2
|
||||
CORINFO_TYPE_USHORT, // STIND_U2
|
||||
CORINFO_TYPE_INT, // STIND_I4
|
||||
CORINFO_TYPE_UINT, // STIND_U4
|
||||
CORINFO_TYPE_LONG, // STIND_I8
|
||||
CORINFO_TYPE_NATIVEINT, // STIND_I
|
||||
CORINFO_TYPE_FLOAT, // STIND_R4
|
||||
CORINFO_TYPE_DOUBLE, // STIND_R8
|
||||
CORINFO_TYPE_REFANY // STIND_REF
|
||||
CORINFO_TYPE_BYTE, // LDIND_I1
|
||||
CORINFO_TYPE_UBYTE, // LDIND_U1
|
||||
CORINFO_TYPE_SHORT, // LDIND_I2
|
||||
CORINFO_TYPE_USHORT, // LDIND_U2
|
||||
CORINFO_TYPE_INT, // LDIND_I4
|
||||
CORINFO_TYPE_UINT, // LDIND_U4
|
||||
CORINFO_TYPE_LONG, // LDIND_I8
|
||||
CORINFO_TYPE_NATIVEINT, // LDIND_I
|
||||
CORINFO_TYPE_FLOAT, // LDIND_R4
|
||||
CORINFO_TYPE_DOUBLE, // LDIND_R8
|
||||
CORINFO_TYPE_REFANY // LDIND_REF
|
||||
};
|
||||
|
||||
ASSERTNR(Opcode >= ReaderBaseNS::LdindI1 &&
|
||||
|
|
|
@ -1166,23 +1166,20 @@ Type *GenIR::getClassType(CORINFO_CLASS_HANDLE ClassHandle, bool IsRefClass,
|
|||
ByteOffset += DataLayout->getTypeSizeInBits(ArrayPadTy) / 8;
|
||||
}
|
||||
|
||||
// For arrays of ref classes there's an array element
|
||||
// type.
|
||||
CORINFO_CLASS_HANDLE ArrayElementHandle = nullptr;
|
||||
CorInfoType ArrayElementCorTy =
|
||||
getChildType(ClassHandle, &ArrayElementHandle);
|
||||
|
||||
if (ArrayElementCorTy == CORINFO_TYPE_CLASS) {
|
||||
Type *ArrayElementFieldTy =
|
||||
Type::getIntNPtrTy(LLVMContext, TargetPointerSizeInBits);
|
||||
Fields.push_back(ArrayElementFieldTy);
|
||||
ByteOffset += DataLayout->getTypeSizeInBits(ArrayElementFieldTy) / 8;
|
||||
}
|
||||
|
||||
Type *ElementTy = getType(ArrayElementCorTy, ArrayElementHandle);
|
||||
|
||||
// Next comes the array of elements. Nominally 0 size so no
|
||||
// ByteOffset update.
|
||||
//
|
||||
// Verify that the offset we calculated matches the expected offset
|
||||
// for arrays of objects.
|
||||
if (ArrayElementCorTy == CORINFO_TYPE_CLASS) {
|
||||
ASSERTNR(ByteOffset == JitContext->EEInfo.offsetOfObjArrayData);
|
||||
}
|
||||
|
||||
// TODO: There may be some inter-element padding here for arrays
|
||||
// of value classes.
|
||||
Type *ArrayOfElementTy = ArrayType::get(ElementTy, 0);
|
||||
|
@ -2405,7 +2402,7 @@ GenIR::loadManagedAddress(const std::vector<Value *> &UnmanagedAddresses,
|
|||
ManagedPointerType);
|
||||
}
|
||||
|
||||
// Load the address of the field described by pResolvedToken
|
||||
// Load the address of the field described by ResolvedToken
|
||||
// from the object Obj.
|
||||
IRNode *GenIR::loadFieldAddress(CORINFO_RESOLVED_TOKEN *ResolvedToken,
|
||||
IRNode *Obj) {
|
||||
|
@ -2424,7 +2421,7 @@ IRNode *GenIR::loadFieldAddress(CORINFO_RESOLVED_TOKEN *ResolvedToken,
|
|||
return Result;
|
||||
}
|
||||
|
||||
// Get the address of the field described by pResolvedToken
|
||||
// Get the address of the field described by ResolvedToken
|
||||
// from the object Obj. Optionally null check.
|
||||
IRNode *GenIR::getFieldAddress(CORINFO_RESOLVED_TOKEN *ResolvedToken,
|
||||
CORINFO_FIELD_INFO *FieldInfo, IRNode *Obj,
|
||||
|
@ -2524,17 +2521,29 @@ IRNode *GenIR::loadField(CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Obj,
|
|||
IRNode *Address =
|
||||
getFieldAddress(ResolvedToken, &FieldInfo, Obj, NullCheckBeforeLoad);
|
||||
|
||||
if (FieldTy->isStructTy()) {
|
||||
return loadAtAddress(Address, FieldTy, CorInfoType, ResolvedToken,
|
||||
AlignmentPrefix, IsVolatile, !NullCheckBeforeLoad);
|
||||
}
|
||||
|
||||
// Generate instructions for loading value of the specified type at the
|
||||
// specified address.
|
||||
IRNode *GenIR::loadAtAddress(IRNode *Address, Type *Ty, CorInfoType CorType,
|
||||
CORINFO_RESOLVED_TOKEN *ResolvedToken,
|
||||
ReaderAlignType AlignmentPrefix, bool IsVolatile,
|
||||
bool AddressMayBeNull)
|
||||
{
|
||||
if (Ty->isStructTy()) {
|
||||
return loadObj(ResolvedToken, Address, AlignmentPrefix, IsVolatile, true,
|
||||
!NullCheckBeforeLoad);
|
||||
} else {
|
||||
LoadInst *LoadInst = makeLoad(Address, IsVolatile, !NullCheckBeforeLoad);
|
||||
AddressMayBeNull);
|
||||
}
|
||||
else {
|
||||
LoadInst *LoadInst = makeLoad(Address, IsVolatile, AddressMayBeNull);
|
||||
uint32_t Align = (AlignmentPrefix == Reader_AlignNatural)
|
||||
? TargetPointerSizeInBits / 8
|
||||
: AlignmentPrefix;
|
||||
? TargetPointerSizeInBits / 8
|
||||
: AlignmentPrefix;
|
||||
LoadInst->setAlignment(Align);
|
||||
|
||||
IRNode *Result = convertToStackType((IRNode *)LoadInst, CorInfoType);
|
||||
IRNode *Result = convertToStackType((IRNode *)LoadInst, CorType);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
@ -2768,6 +2777,110 @@ IRNode *GenIR::addressOfLeaf(IRNode *Leaf) {
|
|||
throw NotYetImplementedException("AddressOfLeaf");
|
||||
}
|
||||
|
||||
IRNode *GenIR::loadElem(ReaderBaseNS::LdElemOpcode Opcode,
|
||||
CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Index,
|
||||
IRNode *Array)
|
||||
{
|
||||
static const CorInfoType Map[ReaderBaseNS::LastLdelemOpcode] = {
|
||||
CorInfoType::CORINFO_TYPE_BYTE, // LDELEM_I1
|
||||
CorInfoType::CORINFO_TYPE_UBYTE, // LDELEM_U1
|
||||
CorInfoType::CORINFO_TYPE_SHORT, // LDELEM_I2
|
||||
CorInfoType::CORINFO_TYPE_USHORT, // LDELEM_U2
|
||||
CorInfoType::CORINFO_TYPE_INT, // LDELEM_I4
|
||||
CorInfoType::CORINFO_TYPE_UINT, // LDELEM_U4
|
||||
CorInfoType::CORINFO_TYPE_LONG, // LDELEM_I8
|
||||
CorInfoType::CORINFO_TYPE_NATIVEINT, // LDELEM_I
|
||||
CorInfoType::CORINFO_TYPE_FLOAT, // LDELEM_R4
|
||||
CorInfoType::CORINFO_TYPE_DOUBLE, // LDELEM_R8
|
||||
CorInfoType::CORINFO_TYPE_CLASS, // LDELEM_REF
|
||||
CorInfoType::CORINFO_TYPE_UNDEF // LDELEM
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
Value *ElementAddress = genArrayElemAddress(Array, Index, ElementTy);
|
||||
bool IsVolatile = false;
|
||||
return loadAtAddressNonNull((IRNode *)ElementAddress, ElementTy, CorType,
|
||||
ResolvedToken, Alignment, IsVolatile);
|
||||
}
|
||||
|
||||
IRNode *GenIR::loadElemA(CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Index,
|
||||
IRNode *Array, bool IsReadOnly) {
|
||||
ASSERTNR(ResolvedToken != nullptr);
|
||||
CORINFO_CLASS_HANDLE ClassHandle = ResolvedToken->hClass;
|
||||
uint32_t ClassAttribs = getClassAttribs(ClassHandle);
|
||||
CorInfoType CorInfoType = JitContext->JitInfo->asCorInfoType(ClassHandle);
|
||||
Type *ElementTy = getType(CorInfoType, ClassHandle);
|
||||
|
||||
// Attempt to use a helper call.
|
||||
// We can only use the LDELEMA helper if the array elements
|
||||
// are not value classes and the access is not readonly.
|
||||
if (!IsReadOnly && ((ClassAttribs & CORINFO_FLG_VALUECLASS) == 0)) {
|
||||
IRNode *HandleNode = genericTokenToNode(ResolvedToken);
|
||||
PointerType *ElementAddressTy = getManagedPointerType(ElementTy);
|
||||
return callHelperImpl(CORINFO_HELP_LDELEMA_REF, ElementAddressTy,
|
||||
Array, Index, HandleNode);
|
||||
}
|
||||
|
||||
return (IRNode *)genArrayElemAddress(Array, Index, ElementTy);
|
||||
}
|
||||
|
||||
// Get address of the array element.
|
||||
Value *GenIR::genArrayElemAddress(IRNode *Array, IRNode *Index,
|
||||
Type *ElementTy) {
|
||||
// This call will load the array length which will ensure that the array is
|
||||
// not null.
|
||||
Array = genBoundsCheck(Array, Index);
|
||||
|
||||
PointerType *Ty = cast<PointerType>(Array->getType());
|
||||
StructType *ReferentTy = cast<StructType>(Ty->getPointerElementType());
|
||||
unsigned int RawArrayStructFieldIndex = ReferentTy->getNumElements() - 1;
|
||||
Type *ArrayTy = ReferentTy->getElementType(RawArrayStructFieldIndex);
|
||||
ASSERTNR(ArrayTy->isArrayTy());
|
||||
ASSERTNR(ArrayTy->getArrayElementType() == ElementTy);
|
||||
|
||||
LLVMContext &Context = *this->JitContext->LLVMContext;
|
||||
|
||||
// Build up gep indices:
|
||||
// the first index is for the struct representing the array;
|
||||
// the second index is for the raw array (last field of the struct):
|
||||
// the third index is for the array element.
|
||||
Value *Indices[] = { ConstantInt::get(Type::getInt32Ty(Context), 0),
|
||||
ConstantInt::get(Type::getInt32Ty(Context), RawArrayStructFieldIndex),
|
||||
Index };
|
||||
|
||||
return LLVMBuilder->CreateInBoundsGEP(Array, Indices);
|
||||
}
|
||||
|
||||
void GenIR::branch() {
|
||||
TerminatorInst *TermInst = LLVMBuilder->GetInsertBlock()->getTerminator();
|
||||
ASSERT(TermInst != nullptr);
|
||||
|
@ -3558,47 +3671,45 @@ void GenIR::throwOpcode(IRNode *Arg1) {
|
|||
ThrowCall->setDoesNotReturn();
|
||||
}
|
||||
|
||||
IRNode *GenIR::genNullCheck(IRNode *Node) {
|
||||
// Generate a call to the throw helper if the condition is met.
|
||||
void GenIR::genConditionalThrow(Value *Condition, CorInfoHelpFunc HelperId,
|
||||
const Twine &ThrowBlockName)
|
||||
{
|
||||
BasicBlock *CheckBlock = LLVMBuilder->GetInsertBlock();
|
||||
BasicBlock::iterator InsertPoint = LLVMBuilder->GetInsertPoint();
|
||||
Instruction *NextInstruction =
|
||||
(InsertPoint == CheckBlock->end() ? nullptr : (Instruction *)InsertPoint);
|
||||
(InsertPoint == CheckBlock->end() ? nullptr : (Instruction *)InsertPoint);
|
||||
|
||||
// Create the throw block so we can reference it later.
|
||||
// Note: we could generate much smaller IR by reusing the same throw block for
|
||||
// all null checks, but at the cost of not being able to tell in a debugger
|
||||
// what was null. The current strategy is to favor debuggability.
|
||||
// all throws of the same kind, but at the cost of not being able to tell in a
|
||||
// debugger which check caused the exception. The current strategy is to
|
||||
// favor debuggability.
|
||||
// TODO: Find a way to annotate the throw blocks as cold so they get laid out
|
||||
// out-of-line.
|
||||
BasicBlock *ThrowBlock =
|
||||
BasicBlock::Create(*JitContext->LLVMContext, "ThrowNullRef", Function);
|
||||
BasicBlock::Create(*JitContext->LLVMContext, ThrowBlockName, Function);
|
||||
|
||||
// Split the block. This creates a goto connecting the blocks that we'll
|
||||
// replace with the conditional branch.
|
||||
// Note that we split at offset NextInstrOffset rather than CurrInstrOffset.
|
||||
// We're already generating the IR for the instr at CurrInstrOffset, and using
|
||||
// NextInstrOffset here ensures that we won't redundantly try to add this
|
||||
// instruction again when processing moves to the new NonNullBlock.
|
||||
BasicBlock *NonNullBlock = ReaderBase::fgSplitBlock(
|
||||
(FlowGraphNode *)CheckBlock, NextInstrOffset, (IRNode *)NextInstruction);
|
||||
// instruction again when processing moves to the new ContinueBlock.
|
||||
BasicBlock *ContinueBlock = ReaderBase::fgSplitBlock(
|
||||
(FlowGraphNode *)CheckBlock, NextInstrOffset, (IRNode *)NextInstruction);
|
||||
TerminatorInst *Goto = CheckBlock->getTerminator();
|
||||
|
||||
// Insert the compare against null.
|
||||
LLVMBuilder->SetInsertPoint(Goto);
|
||||
Value *Compare = LLVMBuilder->CreateIsNotNull(Node, "NullCheck");
|
||||
|
||||
// Swap the conditional branch in place of the goto.
|
||||
LLVMBuilder->SetInsertPoint(Goto);
|
||||
BranchInst *Branch =
|
||||
LLVMBuilder->CreateCondBr(Compare, NonNullBlock, ThrowBlock);
|
||||
LLVMBuilder->CreateCondBr(Condition, ThrowBlock, ContinueBlock);
|
||||
Goto->eraseFromParent();
|
||||
|
||||
// FIll in the throw block.
|
||||
LLVMBuilder->SetInsertPoint(ThrowBlock);
|
||||
// TODO: Use throw_null_ref helper once that's available from CoreCLR. For
|
||||
// now, use throw_div_zero since it has the right signature and we don't
|
||||
// expect exceptions to work dynamically anyway.
|
||||
CallInst *ThrowCall =
|
||||
(CallInst *)callHelper(CORINFO_HELP_THROWDIVZERO, nullptr);
|
||||
(CallInst *)callHelper(HelperId, nullptr);
|
||||
ThrowCall->setDoesNotReturn();
|
||||
LLVMBuilder->CreateUnreachable();
|
||||
|
||||
|
@ -3612,14 +3723,52 @@ IRNode *GenIR::genNullCheck(IRNode *Node) {
|
|||
|
||||
// Move the insert point back to the first instruction in the non-null path.
|
||||
if (NextInstruction == nullptr) {
|
||||
LLVMBuilder->SetInsertPoint(NonNullBlock);
|
||||
} else {
|
||||
LLVMBuilder->SetInsertPoint(NonNullBlock->getFirstInsertionPt());
|
||||
LLVMBuilder->SetInsertPoint(ContinueBlock);
|
||||
}
|
||||
else {
|
||||
LLVMBuilder->SetInsertPoint(ContinueBlock->getFirstInsertionPt());
|
||||
}
|
||||
}
|
||||
|
||||
IRNode *GenIR::genNullCheck(IRNode *Node) {
|
||||
// Insert the compare against null.
|
||||
Value *Compare = LLVMBuilder->CreateIsNull(Node, "NullCheck");
|
||||
|
||||
// TODO: Use throw_null_ref helper once that's available from CoreCLR. For
|
||||
// now, use throw_div_zero since it has the right signature and we don't
|
||||
// expect exceptions to work dynamically anyway.
|
||||
CorInfoHelpFunc HelperId = CORINFO_HELP_THROWDIVZERO;
|
||||
genConditionalThrow(Compare, HelperId, "ThrowNullRef");
|
||||
|
||||
return Node;
|
||||
};
|
||||
|
||||
// Generate array bounds check.
|
||||
IRNode *GenIR::genBoundsCheck(IRNode *Array, IRNode *Index) {
|
||||
CorInfoHelpFunc HelperId = CORINFO_HELP_RNGCHKFAIL;
|
||||
|
||||
// This call will load the array length which will ensure that the array is
|
||||
// not null.
|
||||
IRNode *ArrayLength = loadLen(Array);
|
||||
|
||||
// Insert the bound compare.
|
||||
// The unsigned conversion allows us to also catch negative indices in the
|
||||
// compare.
|
||||
Type *ArrayLengthType = ArrayLength->getType();
|
||||
ASSERTNR(Index->getType()->getPrimitiveSizeInBits() <=
|
||||
ArrayLengthType->getPrimitiveSizeInBits());
|
||||
bool IsSigned = false;
|
||||
Value *ConvertedIndex = LLVMBuilder->CreateIntCast(Index,
|
||||
ArrayLengthType,
|
||||
IsSigned);
|
||||
Value *UpperBoundCompare = LLVMBuilder->CreateICmpUGE(ConvertedIndex,
|
||||
ArrayLength,
|
||||
"BoundsCheck");
|
||||
genConditionalThrow(UpperBoundCompare, HelperId, "ThrowIndexOutOfRange");
|
||||
|
||||
return Array;
|
||||
};
|
||||
|
||||
void GenIR::leave(uint32_t TargetOffset, bool IsNonLocal,
|
||||
bool EndsWithNonLocalGoto) {
|
||||
// TODO: handle exiting through nested finallies
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче