Refactor call canonicalization.

- Move newobj canonicalization out of GenIR and into ReaderBase.
- Refactor rdrCall such that canonicalization occurs before genCall runs.
- Add ReaderCallSignature to encapsulate runtime call signatures.

Taken together, these changes allow ReaderBase to generate accurate
function types for call targets in rdrCall, thus enabling the removal of
a number of post-processing steps in genCall that impede value-type
returns and parameters.

There is also a small bugfix for createTemporary, which was attempting to
set the insertion point to an invalid location in the cast that the entry
block was entirely empty.
This commit is contained in:
Pat Gavlin 2015-03-27 23:30:04 -07:00
Родитель 129bd3f2a6
Коммит babd621eca
4 изменённых файлов: 519 добавлений и 394 удалений

Просмотреть файл

@ -204,6 +204,7 @@ struct EHRegion;
class VerifyWorkList;
class VerificationState;
class FlowGraphNodeOffsetList;
class ReaderCallTargetData;
/// \brief Exception information for the Jit's exception filter
///
@ -235,16 +236,15 @@ struct GCLayout {
uint8_t GCPointers[0]; ///< Array indicating location of the gc pointers
};
/// \brief Structure used to pass argument information from rdrCall to GenCall.
/// \brief Structure that encapsulates type information for the values passed to
/// and returned from calls.
///
/// ReaderBase (which implements \p rdrCall) doesn't know how the derived
/// Reader (which implements \p GenCall) will represent type information, so it
/// uses \p ArgType and \p ArgClass to describe the type of the argument, and
/// \p ArgNode to describe its value.
struct CallArgTriple {
IRNode *ArgNode; ///< Opaque pointer to IR for argument value
CorInfoType ArgType; ///< Low-level type of the argument
CORINFO_CLASS_HANDLE ArgClass; ///< Extra type info for pointers and similar
/// ReaderBase doesn't know how the derived Reader will represent type
/// information, so it uses \p CorType and \p Class to describe the type of
/// the argument.
struct CallArgType {
CorInfoType CorType;
CORINFO_CLASS_HANDLE Class;
};
/// Structure representing a linked list of flow graph nodes
@ -396,6 +396,43 @@ public:
#pragma endregion
/// \brief Information about a runtime call signature.
///
/// Code generation for calls must take into account the parameters that a
/// particular call target expects at runtime, as opposed to the parameters
/// exposed by the target in metadata. This class encapsulates this information
/// s.t. subclasses of ReaderBase need not compute this data ad-hoc.
class ReaderCallSignature {
friend class ReaderBase;
friend class ReaderCallTargetData;
private:
CorInfoCallConv CallingConvention; ///< The calling convention for this
///< target.
CallArgType ResultType; ///< The type of the value returned by
///< this target.
std::vector<CallArgType> ArgumentTypes; ///< The list of types for the formal
///< arguments to this target.
public:
/// \brief Get the calling convention used for this target.
/// \returns The calling convention.
CorInfoCallConv getCallingConvention() const { return CallingConvention; }
/// \brief Get the type information for this target's return value.
/// \returns The type information.
const CallArgType &getResultType() const { return ResultType; }
/// \brief Get the type information for the formal arguments to this target.
/// \returns A vector containing the type information for each formal
/// argument.
const std::vector<CallArgType> &getArgumentTypes() const {
return ArgumentTypes;
}
};
/// \brief Information about a specific call site.
///
/// Code generation for calls must take into account many different factors.
@ -457,6 +494,8 @@ private:
///< secret parameter.
IRNode *CallTargetNode; ///< Client IR for the call
///< target.
ReaderCallSignature CallTargetSignature; ///< Signature information for
///< the call target.
#if defined(_DEBUG)
char TargetName[MAX_CLASSNAME_LENGTH]; ///< Name of the call target.
#endif
@ -778,6 +817,16 @@ public:
///
/// \param NewTargetMethodHandle Method handle for the optimized ctor.
void setOptimizedDelegateCtor(CORINFO_METHOD_HANDLE NewTargetMethodHandle);
/// \brief Return the runtime signature of the call target.
///
/// The runtime signature may differ from the metadata signature for a variety
/// of reasons.
///
/// \returns The runtime signature of the call target.
const ReaderCallSignature &getCallTargetSignature() const {
return CallTargetSignature;
}
};
// Interface to GenIR defined EHRegion structure
@ -1966,6 +2015,28 @@ public:
// at the end of this file.
// ///////////////////////////////////////////////////////////////////////////
/// \brief Generate the \p this argument for \p newobj.
///
/// \param CallTargetData Information about the call site.
/// \param CorType The \p CorInfoType of the \p this parameter.
/// \param Class The class handle of the \p this parameter.
///
/// \returns An \p IRNode that represents the \p this argument.
IRNode *rdrMakeNewObjThisArg(ReaderCallTargetData *CallTargetData,
CorInfoType CorType, CORINFO_CLASS_HANDLE Class);
/// \brief Generate the return node for \p newobj.
///
/// \param CallTargetData Information about the call site.
/// \param ThisArg The argument passed as the \p this parameter for
/// the call. This is exactly the node returned by a
/// previous call to \p genNewObjThisArg, if any.
/// \param CallReturnNode The return node for the corresponding call, if any.
///
/// \returns An \p IRNode that represents the result of the call.
IRNode *rdrMakeNewObjReturnNode(ReaderCallTargetData *CallTargetData,
IRNode *ThisArg, IRNode *CallReturnNode);
IRNode *rdrCall(ReaderCallTargetData *CallTargetData,
ReaderBaseNS::CallOpcode Opcode, IRNode **CallNode);
@ -2748,10 +2819,47 @@ public:
virtual IRNode *addressOfLeaf(IRNode *Leaf) = 0;
virtual IRNode *addressOfValue(IRNode *Leaf) = 0;
/// \brief Delegate to GenIR to generate code to instantiate a new MDArray.
///
/// Creating MDArrays requires calling a runtime helper. This helper is
/// unique in that it is the only variadic helper. Rather than complicate the
/// general case (i.e. genCall and its inputs) in order to handle this,
/// simply special-case the helper call generation.
///
/// \param CallTargetData Information about the call site.
/// \param Args The actual arguments to the call.
/// \param CallNode [out] The \p IRNode corresponding to the call.
///
/// \returns An \p IRNode that represents the result of the call, if any.
virtual IRNode *genNewMDArrayCall(ReaderCallTargetData *CallTargetData,
std::vector<IRNode *> Args,
IRNode **CallNode) = 0;
/// \brief Delegate to GenIR to generate the \p this argument for \p newobj.
///
/// \param CallTargetData Information about the call site.
/// \param CorType The \p CorInfoType of the \p this parameter.
/// \param Class The class handle of the \p this parameter.
///
/// \returns An \p IRNode that represents the \p this argument.
virtual IRNode *genNewObjThisArg(ReaderCallTargetData *CallTargetData,
CorInfoType CorType,
CORINFO_CLASS_HANDLE Class) = 0;
/// \brief Delegate to GenIR to generate the return node for \p newobj.
///
/// \param CallTargetData Information about the call site.
/// \param ThisArg The argument passed as the \p this parameter for
/// the call. This is exactly the node returned by a
/// previous call to \p genNewObjThisArg, if any.
///
/// \returns An \p IRNode that represents the result of the call.
virtual IRNode *genNewObjReturnNode(ReaderCallTargetData *CallTargetData,
IRNode *ThisArg) = 0;
// Helper callback used by rdrCall to emit call code.
virtual IRNode *genCall(ReaderCallTargetData *CallTargetDaTA,
CallArgTriple *Args, uint32_t NumArgs,
IRNode **CallNode) = 0;
virtual IRNode *genCall(ReaderCallTargetData *CallTargetData,
std::vector<IRNode *> Args, IRNode **CallNode) = 0;
virtual bool canMakeDirectCall(ReaderCallTargetData *CallTargetData) = 0;
@ -2813,12 +2921,19 @@ public:
virtual IRNode *makePtrDstGCOperand(bool IsInteriorGC) = 0;
virtual IRNode *makePtrNode(ReaderPtrType PointerType = Reader_PtrNotGc) = 0;
virtual IRNode *makeStackTypeNode(IRNode *Node) = 0;
virtual IRNode *makeCallReturnNode(CORINFO_SIG_INFO *Sig,
uint32_t *HiddenMBParamSize,
GCLayout **GCInfo) = 0;
virtual IRNode *makeDirectCallTargetNode(CORINFO_METHOD_HANDLE Method,
void *CodeAddress) = 0;
virtual IRNode *makeDirectCallTargetNode(void *CodeAddress) = 0;
/// \brief Create a function pointer with the given signature from the given
/// target address.
///
/// \param Signature The runtime signature of the function located at the
/// target address.
/// \param SourceNode The \p IRNode corresponding to the target address.
///
/// \returns An \p IRNode that representing the function pointer.
virtual IRNode *makeFunctionPointer(const ReaderCallSignature &Signature,
IRNode *SourceNode) = 0;
// Called once region tree has been built.
virtual void setEHInfo(EHRegion *EhRegionTree,

Просмотреть файл

@ -703,9 +703,20 @@ public:
IRNode *addressOfLeaf(IRNode *Leaf) override;
IRNode *addressOfValue(IRNode *Leaf) override;
IRNode *genNewMDArrayCall(ReaderCallTargetData *CallTargetData,
std::vector<IRNode *> Args,
IRNode **CallNode) override;
IRNode *genNewObjThisArg(ReaderCallTargetData *CallTargetData,
CorInfoType COrType,
CORINFO_CLASS_HANDLE Class) override;
IRNode *genNewObjReturnNode(ReaderCallTargetData *CalLTargetData,
IRNode *ThisArg) override;
// Helper callback used by rdrCall to emit call code.
IRNode *genCall(ReaderCallTargetData *CallTargetInfo, CallArgTriple *ArgArray,
uint32_t NumArgs, IRNode **CallNode) override;
IRNode *genCall(ReaderCallTargetData *CallTargetInfo,
std::vector<IRNode *> Args, IRNode **CallNode) override;
bool canMakeDirectCall(ReaderCallTargetData *CallTargetData) override;
@ -773,11 +784,10 @@ public:
throw NotYetImplementedException("makeStackTypeNode");
};
IRNode *makeCallReturnNode(CORINFO_SIG_INFO *Sig, unsigned *HiddenMBParamSize,
GCLayout **GcInfo) override;
IRNode *makeDirectCallTargetNode(void *CodeAddr) override;
IRNode *makeDirectCallTargetNode(CORINFO_METHOD_HANDLE Method,
void *CodeAddr) override;
IRNode *makeFunctionPointer(const ReaderCallSignature &Signature,
IRNode *SourceNode) override;
// Called once region tree has been built.
void setEHInfo(EHRegion *EhRegionTree, EHRegionList *EhRegionList) override;
@ -793,18 +803,11 @@ public:
//
// vararg
bool callIsCorVarArgs(IRNode *CallNode);
void canonVarargsCall(IRNode *CallNode,
ReaderCallTargetData *CallTargetInfo) {
throw NotYetImplementedException("canonVarargsCall");
};
// newobj
bool canonNewObjCall(IRNode *CallNode, ReaderCallTargetData *CallTargetData,
IRNode **OutResult);
IRNode *canonNewArrayCall(IRNode *CallNode,
ReaderCallTargetData *CallTargetData);
// stubs
IRNode *canonStubCall(IRNode *CallNode, ReaderCallTargetData *CallTargetData);
#endif
@ -845,6 +848,7 @@ private:
llvm::FunctionType *getFunctionType(CORINFO_SIG_INFO &Sig,
CORINFO_CLASS_HANDLE ThisClass,
bool HasSecretParameter = false);
llvm::FunctionType *getFunctionType(const ReaderCallSignature &Signature);
llvm::Type *getClassType(CORINFO_CLASS_HANDLE ClassHandle, bool IsRefClass,
bool GetRefClassFields);

Просмотреть файл

@ -4636,7 +4636,7 @@ IRNode *ReaderBase::rdrGetFieldAddress(CORINFO_RESOLVED_TOKEN *ResolvedToken,
}
IRNode *ReaderBase::loadToken(CORINFO_RESOLVED_TOKEN *ResolvedToken) {
CORINFO_GENERIC_HANDLE CompileTimeHandleValue = 0;
CORINFO_GENERIC_HANDLE CompileTimeHandleValue = nullptr;
bool RequiresRuntimeLookup = true;
IRNode *GetTokenNumericNode =
genericTokenToNode(ResolvedToken, false, true, &CompileTimeHandleValue,
@ -4726,6 +4726,41 @@ void ReaderBase::getCallSiteSignature(CORINFO_METHOD_HANDLE Method,
#endif // CC_PEVERIFY
}
IRNode *ReaderBase::rdrMakeNewObjThisArg(ReaderCallTargetData *CallTargetData,
CorInfoType CorType,
CORINFO_CLASS_HANDLE Class) {
uint32_t ClassAttribs = CallTargetData->getClassAttribs();
bool IsMDArray = ((ClassAttribs & CORINFO_FLG_ARRAY) != 0);
if (IsMDArray) {
// Storage for MDArrays is allocated by the callee; these do not take a this
// argument.
return nullptr;
}
return genNewObjThisArg(CallTargetData, CorType, Class);
}
IRNode *
ReaderBase::rdrMakeNewObjReturnNode(ReaderCallTargetData *CallTargetData,
IRNode *ThisArg, IRNode *CallReturnNode) {
uint32_t ClassAttribs = CallTargetData->getClassAttribs();
bool IsMDArray = ((ClassAttribs & CORINFO_FLG_ARRAY) != 0);
bool IsVarObjSize = ((ClassAttribs & CORINFO_FLG_VAROBJSIZE) != 0);
// MDArrays should already have been taken care of.
ASSERT(!IsMDArray);
if (IsVarObjSize) {
// Storage for variably-sized objects is allocated by the callee; the result
// of the call is already correct.
return CallReturnNode;
}
return genNewObjReturnNode(CallTargetData, ThisArg);
}
// Constraint calls in generic code. Constraint calls are operations on generic
// type variables,
// e.g. "x.Incr()" where "x" has type "T" in generic code and where "T" supports
@ -4771,7 +4806,6 @@ IRNode *
ReaderBase::rdrCall(ReaderCallTargetData *Data, ReaderBaseNS::CallOpcode Opcode,
IRNode **CallNode) { // out param is defined by GenCall
IRNode *ReturnNode;
CallArgTriple *ArgArray;
uint32_t NumArgs;
int32_t FirstArgNum;
int32_t TypeArgNum;
@ -5101,6 +5135,9 @@ ReaderBase::rdrCall(ReaderCallTargetData *Data, ReaderBaseNS::CallOpcode Opcode,
CORINFO_SIG_INFO *SigInfo = Data->getSigInfo();
// Set the calling convention.
Data->CallTargetSignature.CallingConvention = SigInfo->getCallConv();
// Get the number of arguments to this method.
NumArgs = (uint32_t)SigInfo->numArgs;
HasThis = Data->hasThis();
@ -5127,12 +5164,11 @@ ReaderBase::rdrCall(ReaderCallTargetData *Data, ReaderBaseNS::CallOpcode Opcode,
TotalArgs =
(HasThis ? 1 : 0) + (IsVarArg ? 1 : 0) + (HasTypeArg ? 1 : 0) + NumArgs;
// Special case for newobj, currently the first
// argument is handled/appended in CanonNewObj.
// For this reason we don't need to record any
// information about that argument.
FirstArgNum = 0;
if (Opcode == ReaderBaseNS::NewObj) {
// Special case for newobj: the first argument is not on the stack.
IRNode *NewObjThisArg = nullptr;
if (Data->isNewObj()) {
ASSERTNR(HasThis); // new obj better have "this"
FirstArgNum = 1;
}
@ -5140,38 +5176,37 @@ ReaderBase::rdrCall(ReaderCallTargetData *Data, ReaderBaseNS::CallOpcode Opcode,
VarArgNum = IsVarArg ? (HasThis ? 1 : 0) : -1;
TypeArgNum = HasTypeArg ? ((HasThis ? 1 : 0) + (IsVarArg ? 1 : 0)) : -1;
// Create return info.
Data->CallTargetSignature.ResultType = {SigInfo->retType,
SigInfo->retTypeClass};
// Create arg array and populate with stack arguments.
// - struct return pointer does not live on arg array,
// it is passed to GenIR as destination.
// - this pointer is also not present in array.
//
// Note that array is populated with two loops: the first traverses the EE's
// argument list, the second pops arguments from the stack. Two loops are
// clearer because the data is stored with opposite orderings.
// Note that array is populated with two loops, the first
// traverses the ee's argument list, the second pops
// arguments from the stack. Two loops are needed because
// the Data is stored with opposite orderings.
// First populate ArgType, argClass fields.
ArgArray = nullptr;
std::vector<CallArgType> &ArgumentTypes =
Data->CallTargetSignature.ArgumentTypes;
new (&ArgumentTypes) std::vector<CallArgType>(TotalArgs);
std::vector<IRNode *> Arguments(TotalArgs);
// First populate argument type information.
if (TotalArgs > 0) {
CORINFO_ARG_LIST_HANDLE Args;
CorInfoType CorType;
CORINFO_CLASS_HANDLE ArgType, Class;
ArgArray = (CallArgTriple *)_alloca(sizeof(CallArgTriple) * TotalArgs);
#if !defined(NODEBUG)
memset(ArgArray, 0, sizeof(CallArgTriple) * TotalArgs);
#endif
Args = SigInfo->args;
Index = 0;
// If this call passes a this ptr, then it is first in array.
if (HasThis) {
ArgArray[Index].ArgType = CORINFO_TYPE_BYREF;
ArgArray[Index].ArgClass = Data->getClassHandle();
ArgumentTypes[Index].CorType = CORINFO_TYPE_BYREF;
ArgumentTypes[Index].Class = Data->getClassHandle();
if (Data->getMethodHandle() != nullptr) {
if ((Data->getClassAttribs() & CORINFO_FLG_VALUECLASS) == 0) {
ArgArray[Index].ArgType = CORINFO_TYPE_CLASS;
ArgumentTypes[Index].CorType = CORINFO_TYPE_CLASS;
}
}
Index++;
@ -5184,8 +5219,8 @@ ReaderBase::rdrCall(ReaderCallTargetData *Data, ReaderBaseNS::CallOpcode Opcode,
// If this call has a type arg, then it's right before fixed params.
if (HasTypeArg) {
ArgArray[Index].ArgType = CORINFO_TYPE_NATIVEINT;
ArgArray[Index].ArgClass = 0;
ArgumentTypes[Index].CorType = CORINFO_TYPE_NATIVEINT;
ArgumentTypes[Index].Class = nullptr;
Index++;
}
@ -5217,8 +5252,8 @@ ReaderBase::rdrCall(ReaderCallTargetData *Data, ReaderBaseNS::CallOpcode Opcode,
}
#endif // CC_PEVERIFY
ArgArray[Index].ArgType = CorType;
ArgArray[Index].ArgClass = Class;
ArgumentTypes[Index].CorType = CorType;
ArgumentTypes[Index].Class = Class;
Args = JitInfo->getArgNext(Args);
}
@ -5232,22 +5267,23 @@ ReaderBase::rdrCall(ReaderCallTargetData *Data, ReaderBaseNS::CallOpcode Opcode,
continue;
}
if (Index == TypeArgNum) {
ArgArray[Index].ArgNode = Data->getTypeContextNode();
ASSERTNR(ArgArray[Index].ArgNode != NULL);
Arguments[Index] = Data->getTypeContextNode();
ASSERTNR(Arguments[Index] != nullptr);
ASSERTMNR(!Data->isCallI(), "CALLI on parameterized type");
continue;
}
ArgArray[Index].ArgNode = (IRNode *)ReaderOperandStack->pop();
Arguments[Index] = (IRNode *)ReaderOperandStack->pop();
}
// this-pointer specific stuff
if (HasThis) {
if (Opcode == ReaderBaseNS::NewObj) {
// First argument to newobj has complete type info, but no argument
// node.
ArgArray[0].ArgNode = nullptr;
if (Data->isNewObj()) {
// Create the this argument for newobj now.
NewObjThisArg = rdrMakeNewObjThisArg(Data, ArgumentTypes[0].CorType,
ArgumentTypes[0].Class);
Arguments[0] = NewObjThisArg;
} else {
ArgArray[0].ArgNode = Data->applyThisTransform(ArgArray[0].ArgNode);
Arguments[0] = Data->applyThisTransform(Arguments[0]);
}
}
}
@ -5265,14 +5301,43 @@ ReaderBase::rdrCall(ReaderCallTargetData *Data, ReaderBaseNS::CallOpcode Opcode,
removeStackInterference();
}
// Get the call target
if (ReaderBaseNS::Calli != Opcode) {
rdrMakeCallTargetNode(Data,
ArgArray != nullptr ? &ArgArray[0].ArgNode : nullptr);
// Perform any post-processing necessary for newobj.
if (Data->isNewObj()) {
uint32_t ClassAttribs = Data->getClassAttribs();
bool IsMDArray = ((ClassAttribs & CORINFO_FLG_ARRAY) != 0);
if (IsMDArray) {
return genNewMDArrayCall(Data, Arguments, CallNode);
}
bool IsVarObjSize = ((ClassAttribs & CORINFO_FLG_VAROBJSIZE) != 0);
if (IsVarObjSize) {
// We are allocating an object whose size depends on constructor args
// (e.g., string). In this case the call to the constructor will allocate
// the object.
Data->CallTargetSignature.ResultType = {ArgumentTypes[0].CorType,
ArgumentTypes[0].Class};
}
}
// Get the call target
if (Data->isCallI()) {
Data->CallTargetNode =
makeFunctionPointer(Data->CallTargetSignature, Data->CallTargetNode);
} else {
rdrMakeCallTargetNode(Data,
Arguments.size() == 0 ? nullptr : &Arguments[0]);
ASSERT(!Data->isNewObj() || Arguments[0] == NewObjThisArg);
}
// Ask GenIR to emit call, optionally returns a ReturnNode.
ReturnNode = genCall(Data, Arguments, CallNode);
if (Data->isNewObj()) {
ReturnNode = rdrMakeNewObjReturnNode(Data, NewObjThisArg, ReturnNode);
}
// Ask GenIR to emit call, returns a ReturnNode.
ReturnNode = genCall(Data, ArgArray, TotalArgs, CallNode);
return ReturnNode;
}
@ -5298,54 +5363,54 @@ void ReaderBase::rdrMakeCallTargetNode(ReaderCallTargetData *CallTargetData,
// Check for Delegate Invoke optimization
if (rdrCallIsDelegateInvoke(CallTargetData)) {
CallTargetData->CallTargetNode =
rdrGetDelegateInvokeTarget(CallTargetData, ThisPtr);
return;
Target = rdrGetDelegateInvokeTarget(CallTargetData, ThisPtr);
} else {
// Insert the code sequence to load a pointer to the target function.
// If that sequence involves dereferencing the current method's instance
// parameter (e.g. to find dynamic type parameter information for shared
// generic code) or the target method's instance argument (e.g. to look up
// its VTable), the sequence generated here will include that dereference
// and any null checks necessary for it.
// Additionally, the NeedsNullCheck flag will be set if the ensuing call
// sequence needs to explicitly null-check the target method's instance
// argument (e.g. because the callvirt opcode was used to call a non-virtual
// method). The NeedsNullCheck flag will not be set if the sequence
// generated here already dereferences (and therefore null-checks) the
// target
// method's instance argument (e.g. if callvirt was used but the method is
// virtual and lookup is performed via the target's VTable).
switch (CallInfo->kind) {
case CORINFO_CALL:
// Direct Call
CallTargetData->NeedsNullCheck = CallInfo->nullInstanceCheck == TRUE;
Target = rdrGetDirectCallTarget(CallTargetData);
break;
case CORINFO_CALL_CODE_POINTER:
// Runtime lookup required (code sharing w/o using inst param)
CallTargetData->NeedsNullCheck = CallInfo->nullInstanceCheck == TRUE;
Target = rdrGetCodePointerLookupCallTarget(CallTargetData);
break;
case CORINFO_VIRTUALCALL_STUB:
// Virtual Call via virtual dispatch stub
CallTargetData->NeedsNullCheck = true;
Target = rdrGetVirtualStubCallTarget(CallTargetData);
break;
case CORINFO_VIRTUALCALL_LDVIRTFTN:
// Virtual Call via indirect virtual call
Target = rdrGetIndirectVirtualCallTarget(CallTargetData, ThisPtr);
break;
case CORINFO_VIRTUALCALL_VTABLE:
// Virtual call via table lookup (vtable)
Target = rdrGetVirtualTableCallTarget(CallTargetData, ThisPtr);
break;
default:
ASSERTMNR(UNREACHED, "Unexpected call kind");
Target = nullptr;
}
}
// Insert the code sequence to load a pointer to the target function.
// If that sequence involves dereferencing the current method's instance
// parameter (e.g. to find dynamic type parameter information for shared
// generic code) or the target method's instance argument (e.g. to look up
// its VTable), the sequence generated here will include that dereference
// and any null checks necessary for it.
// Additionally, the NeedsNullCheck flag will be set if the ensuing call
// sequence needs to explicitly null-check the target method's instance
// argument (e.g. because the callvirt opcode was used to call a non-virtual
// method). The NeedsNullCheck flag will not be set if the sequence
// generated here already dereferences (and therefore null-checks) the target
// method's instance argument (e.g. if callvirt was used but the method is
// virtual and lookup is performed via the target's VTable).
switch (CallInfo->kind) {
case CORINFO_CALL:
// Direct Call
CallTargetData->NeedsNullCheck = CallInfo->nullInstanceCheck == TRUE;
Target = rdrGetDirectCallTarget(CallTargetData);
break;
case CORINFO_CALL_CODE_POINTER:
// Runtime lookup required (code sharing w/o using inst param)
CallTargetData->NeedsNullCheck = CallInfo->nullInstanceCheck == TRUE;
Target = rdrGetCodePointerLookupCallTarget(CallTargetData);
break;
case CORINFO_VIRTUALCALL_STUB:
// Virtual Call via virtual dispatch stub
CallTargetData->NeedsNullCheck = true;
Target = rdrGetVirtualStubCallTarget(CallTargetData);
break;
case CORINFO_VIRTUALCALL_LDVIRTFTN:
// Virtual Call via indirect virtual call
Target = rdrGetIndirectVirtualCallTarget(CallTargetData, ThisPtr);
break;
case CORINFO_VIRTUALCALL_VTABLE:
// Virtual call via table lookup (vtable)
Target = rdrGetVirtualTableCallTarget(CallTargetData, ThisPtr);
break;
default:
ASSERTMNR(UNREACHED, "Unexpected call kind");
Target = nullptr;
}
CallTargetData->CallTargetNode = Target;
CallTargetData->CallTargetNode =
makeFunctionPointer(CallTargetData->CallTargetSignature, Target);
}
IRNode *
@ -5389,7 +5454,7 @@ IRNode *ReaderBase::rdrGetDirectCallTarget(CORINFO_METHOD_HANDLE Method,
IRNode *TargetNode;
if ((AddressInfo.accessType == IAT_VALUE) && CanMakeDirectCall) {
TargetNode = makeDirectCallTargetNode(Method, AddressInfo.addr);
TargetNode = makeDirectCallTargetNode(AddressInfo.addr);
} else {
bool IsIndirect = AddressInfo.accessType != IAT_VALUE;
TargetNode = handleToIRNode(MethodToken, AddressInfo.addr, 0, IsIndirect,
@ -5750,7 +5815,7 @@ void ReaderBase::buildUpParams(uint32_t NumParams, bool HasSecretParameter) {
// comes instParam (typeArg cookie)
if (HasTypeArg) {
// this is not a real arg. we do not record it for verification
CORINFO_CLASS_HANDLE Class = 0;
const CORINFO_CLASS_HANDLE Class = nullptr;
createSym(ParamIndex, false, CORINFO_TYPE_NATIVEINT, Class, false,
ReaderSpecialSymbolType::Reader_InstParam);
ParamIndex++;
@ -5775,7 +5840,7 @@ void ReaderBase::buildUpParams(uint32_t NumParams, bool HasSecretParameter) {
if (HasSecretParameter) {
ASSERT(ParamIndex == NumParams - 1);
CORINFO_CLASS_HANDLE Class = 0;
const CORINFO_CLASS_HANDLE Class = nullptr;
createSym(ParamIndex, false, CORINFO_TYPE_NATIVEINT, Class, false,
ReaderSpecialSymbolType::Reader_SecretParam);
}

Просмотреть файл

@ -547,7 +547,12 @@ Instruction *GenIR::createTemporary(Type *Ty, const Twine &Name) {
if (TempInsertionPoint == nullptr) {
// There are no local, param or temp allocas in the entry block, so set
// the insertion point to the first point in the block.
LLVMBuilder->SetInsertPoint(EntryBlock->getFirstInsertionPt());
auto FirstIP = EntryBlock->getFirstInsertionPt();
if (FirstIP == EntryBlock->end()) {
LLVMBuilder->SetInsertPoint(EntryBlock);
} else {
LLVMBuilder->SetInsertPoint(FirstIP);
}
} else {
// There are local, param or temp allocas. TempInsertionPoint refers to
// the last of them. Set the insertion point to the next instruction since
@ -1478,6 +1483,22 @@ FunctionType *GenIR::getFunctionType(CORINFO_SIG_INFO &Sig,
return FunctionType;
}
FunctionType *GenIR::getFunctionType(const ReaderCallSignature &Signature) {
CallArgType ResultType = Signature.getResultType();
Type *LLVMResultType = this->getType(ResultType.CorType, ResultType.Class);
const std::vector<CallArgType> &ArgumentTypes = Signature.getArgumentTypes();
const uint32_t NumArguments = ArgumentTypes.size();
SmallVector<Type *, 16> LLVMArgumentTypes(NumArguments);
for (uint32_t I = 0; I < NumArguments; I++) {
const CallArgType &Arg = ArgumentTypes[I];
LLVMArgumentTypes[I] = this->getType(Arg.CorType, Arg.Class);
}
const bool IsVarArg = false;
return FunctionType::get(LLVMResultType, LLVMArgumentTypes, IsVarArg);
}
// Verify that this value's type is a valid type
// for an operand on the evaluation stack.
bool GenIR::isValidStackType(IRNode *Node) {
@ -3377,34 +3398,187 @@ bool GenIR::canMakeDirectCall(ReaderCallTargetData *CallTargetData) {
return !CallTargetData->isJmp();
}
IRNode *GenIR::makeDirectCallTargetNode(CORINFO_METHOD_HANDLE Method,
void *CodeAddr) {
IRNode *GenIR::makeDirectCallTargetNode(void *CodeAddr) {
uint32_t NumBits = TargetPointerSizeInBits;
bool IsSigned = false;
ConstantInt *CodeAddrValue = ConstantInt::get(
*JitContext->LLVMContext, APInt(NumBits, (uint64_t)CodeAddr, IsSigned));
FunctionType *FunctionType = getFunctionType(Method);
return (IRNode *)CodeAddrValue;
}
return (IRNode *)LLVMBuilder->CreateIntToPtr(
CodeAddrValue, getUnmanagedPointerType(FunctionType));
IRNode *GenIR::makeFunctionPointer(const ReaderCallSignature &Signature,
IRNode *Source) {
Value *SourceValue = (Value *)Source;
assert(SourceValue->getType()->isIntegerTy(TargetPointerSizeInBits));
Type *FunctionTy = getFunctionType(Signature);
Type *FunctionPtrTy = getUnmanagedPointerType(FunctionTy);
return (IRNode *)LLVMBuilder->CreateIntToPtr(SourceValue, FunctionPtrTy);
}
// Helper callback used by rdrCall to emit a call to allocate a new MDArray.
IRNode *GenIR::genNewMDArrayCall(ReaderCallTargetData *CallTargetData,
std::vector<IRNode *> Args,
IRNode **CallNode) {
// To construct the array we need to call a helper passing it the class handle
// for the constructor method, the number of arguments to the constructor and
// the arguments to the constructor.
const ReaderCallSignature &Signature =
CallTargetData->getCallTargetSignature();
const std::vector<CallArgType> SigArgumentTypes =
Signature.getArgumentTypes();
const uint32_t ArgCount = Args.size();
// Construct the new function type.
Type *ReturnType =
getType(SigArgumentTypes[0].CorType, SigArgumentTypes[0].Class);
SmallVector<Type *, 16> ArgumentTypes(ArgCount + 2);
SmallVector<Value *, 16> Arguments(ArgCount + 2);
uint32_t Index = 0;
// The first argument is the class handle.
IRNode *ClassHandle = CallTargetData->getClassHandleNode();
ASSERTNR(ClassHandle);
ArgumentTypes[Index] = ClassHandle->getType();
Arguments[Index++] = ClassHandle;
// The second argument is the number of arguments to follow.
const uint32_t NumBits = 32;
const bool IsSigned = true;
Value *NumArgs = ConstantInt::get(
*JitContext->LLVMContext,
APInt(NumBits, CallTargetData->getSigInfo()->numArgs, IsSigned));
ASSERTNR(NumArgs);
ArgumentTypes[Index] = NumArgs->getType();
Arguments[Index++] = NumArgs;
// The rest of the arguments are the same as in the original newobj call.
// It's a vararg call so add arguments but not argument types.
for (unsigned I = 1; I < ArgCount; ++I) {
IRNode *ArgNode = Args[I];
CorInfoType CorType = SigArgumentTypes[I].CorType;
CORINFO_CLASS_HANDLE Class = SigArgumentTypes[I].Class;
Type *ArgType = this->getType(CorType, Class);
if (ArgType->isStructTy()) {
throw NotYetImplementedException("Call has value type args");
}
IRNode *Arg = convertFromStackType(ArgNode, CorType, ArgType);
Arguments[Index++] = Arg;
}
const bool IsVarArg = true;
FunctionType *FunctionType =
FunctionType::get(ReturnType, ArgumentTypes, IsVarArg);
// Create a call target with the right type.
// Get the address of the Helper descr.
Value *Callee = getHelperCallAddress(CORINFO_HELP_NEW_MDARR);
Callee = LLVMBuilder->CreateIntToPtr(Callee,
getUnmanagedPointerType(FunctionType));
// Replace the old call instruction with the new one.
*CallNode = (IRNode *)LLVMBuilder->CreateCall(Callee, Arguments);
return *CallNode;
}
IRNode *GenIR::genNewObjThisArg(ReaderCallTargetData *CallTargetData,
CorInfoType CorType,
CORINFO_CLASS_HANDLE Class) {
Type *ThisType = this->getType(CorType, Class);
uint32_t ClassAttribs = CallTargetData->getClassAttribs();
bool IsVarObjSize = ((ClassAttribs & CORINFO_FLG_VAROBJSIZE) != 0);
if (IsVarObjSize) {
// Storage for variably-sized objects is allocated by the callee; simply
// pass a null pointer.
return (IRNode *)Constant::getNullValue(ThisType);
}
bool IsValueClass = ((ClassAttribs & CORINFO_FLG_VALUECLASS) != 0);
if (IsValueClass) {
CorInfoType StructCorType;
uint32_t MbSize;
ReaderBase::getClassType(Class, ClassAttribs, &StructCorType, &MbSize);
Type *StructType = this->getType(StructCorType, Class);
// We are allocating an instance of a value class on the stack.
Instruction *AllocaInst = createTemporary(StructType);
// Initialize the struct to zero.
LLVMContext &LLVMContext = *this->JitContext->LLVMContext;
Value *ZeroByte = Constant::getNullValue(Type::getInt8Ty(LLVMContext));
uint32_t Align = 0;
LLVMBuilder->CreateMemSet(AllocaInst, ZeroByte, MbSize, Align);
// Create a managed pointer to the struct instance and pass it as the 'this'
// argument to the constructor call.
Type *ManagedPointerType = getManagedPointerType(StructType);
Value *ManagedPointerToStruct =
LLVMBuilder->CreateAddrSpaceCast(AllocaInst, ManagedPointerType);
ManagedPointerToStruct =
LLVMBuilder->CreatePointerCast(ManagedPointerToStruct, ThisType);
return (IRNode *)ManagedPointerToStruct;
}
// We are allocating a fixed-size class on the heap.
// Create a call to the newobj helper specific to this class,
// and use its return value as the
// 'this' pointer to be passed as the first argument to the constructor.
// Create the address operand for the newobj helper.
CorInfoHelpFunc HelperId = getNewHelper(CallTargetData->getResolvedToken());
Value *ThisPointer =
callHelperImpl(HelperId, ThisType, CallTargetData->getClassHandleNode());
return (IRNode *)ThisPointer;
}
IRNode *GenIR::genNewObjReturnNode(ReaderCallTargetData *CallTargetData,
IRNode *ThisArg) {
uint32_t ClassAttribs = CallTargetData->getClassAttribs();
bool IsValueClass = ((ClassAttribs & CORINFO_FLG_VALUECLASS) != 0);
if (IsValueClass) {
// Dig through the 'this' arg to find the temporary created earlier
// and dereference it.
Value *Alloca = nullptr;
CastInst *PointerCast = cast<CastInst>(ThisArg);
AddrSpaceCastInst *AddrSpaceCast =
dyn_cast<AddrSpaceCastInst>(PointerCast->getOperand(0));
if (AddrSpaceCast == nullptr) {
Alloca = PointerCast->getOperand(0);
} else {
Alloca = AddrSpaceCast->getOperand(0);
}
AllocaInst *Temp = cast<AllocaInst>(Alloca);
// The temp we passed as the this arg needs to be dereferenced.
return (IRNode *)makeLoadNonNull((Value *)Temp, false);
}
// Otherwise, we already have a good value.
return ThisArg;
}
IRNode *GenIR::genCall(ReaderCallTargetData *CallTargetInfo,
CallArgTriple *ArgArray, uint32_t NumArgs,
IRNode **CallNode) {
std::vector<IRNode *> Args, IRNode **CallNode) {
IRNode *Call = nullptr, *ReturnNode = nullptr;
IRNode *TargetNode = CallTargetInfo->getCallTargetNode();
CORINFO_SIG_INFO *SigInfo = CallTargetInfo->getSigInfo();
CORINFO_CALL_INFO *CallInfo = CallTargetInfo->getCallInfo();
const ReaderCallSignature &Signature =
CallTargetInfo->getCallTargetSignature();
bool IsStubCall =
(CallInfo != nullptr) && (CallInfo->kind == CORINFO_VIRTUALCALL_STUB);
unsigned HiddenMBParamSize = 0;
GCLayout *GCInfo = nullptr;
if (CallTargetInfo->isTailCall()) {
// If there's no explicit tail prefix, we can generate
// a normal call and all will be well.
@ -3413,27 +3587,30 @@ IRNode *GenIR::genCall(ReaderCallTargetData *CallTargetInfo,
}
}
CorInfoCallConv CC = Signature.getCallingConvention();
if (CallTargetInfo->isIndirect()) {
CorInfoCallConv Conv = SigInfo->getCallConv();
if (Conv == CORINFO_CALLCONV_STDCALL || Conv == CORINFO_CALLCONV_C ||
Conv == CORINFO_CALLCONV_THISCALL ||
Conv == CORINFO_CALLCONV_FASTCALL ||
Conv == CORINFO_CALLCONV_NATIVEVARARG) {
if (CC == CORINFO_CALLCONV_STDCALL || CC == CORINFO_CALLCONV_C ||
CC == CORINFO_CALLCONV_THISCALL || CC == CORINFO_CALLCONV_FASTCALL ||
CC == CORINFO_CALLCONV_NATIVEVARARG) {
throw NotYetImplementedException("PInvoke call");
}
}
// Ask GenIR to create return value.
if (!CallTargetInfo->isNewObj()) {
ReturnNode = makeCallReturnNode(SigInfo, &HiddenMBParamSize, &GCInfo);
CallArgType ResultType = Signature.getResultType();
if ((ResultType.CorType == CORINFO_TYPE_REFANY) ||
(ResultType.CorType == CORINFO_TYPE_VALUECLASS)) {
throw NotYetImplementedException("Return refany or value class");
}
std::vector<Value *> Arguments;
const std::vector<CallArgType> &ArgumentTypes = Signature.getArgumentTypes();
const uint32_t NumArgs = Args.size();
assert(NumArgs == ArgumentTypes.size());
SmallVector<Value *, 16> Arguments(NumArgs);
for (uint32_t I = 0; I < NumArgs; I++) {
IRNode *ArgNode = ArgArray[I].ArgNode;
CorInfoType CorType = ArgArray[I].ArgType;
CORINFO_CLASS_HANDLE Class = ArgArray[I].ArgClass;
IRNode *ArgNode = Args[I];
CorInfoType CorType = ArgumentTypes[I].CorType;
CORINFO_CLASS_HANDLE Class = ArgumentTypes[I].Class;
Type *ArgType = this->getType(CorType, Class);
if (ArgType->isStructTy()) {
@ -3441,50 +3618,16 @@ IRNode *GenIR::genCall(ReaderCallTargetData *CallTargetInfo,
}
if (I == 0) {
if (CallTargetInfo->isNewObj()) {
// Memory and a representative node for the 'this' pointer for newobj
// has not been created yet. Pass a null value of the right type for
// now;
// it will be replaced by the real value in canonNewObjCall.
ASSERT(ArgNode == nullptr);
ArgNode = (IRNode *)Constant::getNullValue(ArgType);
} else if (CallTargetInfo->needsNullCheck()) {
if (!CallTargetInfo->isNewObj() && CallTargetInfo->needsNullCheck()) {
// Insert this Ptr null check if required
ASSERT(SigInfo->hasThis());
ASSERT(CallTargetInfo->hasThis());
ArgNode = genNullCheck(ArgNode);
}
}
IRNode *Arg = convertFromStackType(ArgNode, CorType, ArgType);
Arguments.push_back(Arg);
Arguments[I] = Arg;
}
// We may need to fix the type on the TargetNode.
const bool FixFunctionType = CallTargetInfo->isCallVirt() ||
CallTargetInfo->isCallI() ||
CallTargetInfo->isOptimizedDelegateCtor();
if (FixFunctionType) {
CORINFO_CLASS_HANDLE ThisClass = nullptr;
if (SigInfo->hasThis()) {
ThisClass = ArgArray[0].ArgClass;
}
Type *FunctionTy =
getUnmanagedPointerType(getFunctionType(*SigInfo, ThisClass));
if (TargetNode->getType()->isPointerTy()) {
TargetNode =
(IRNode *)LLVMBuilder->CreatePointerCast(TargetNode, FunctionTy);
} else {
ASSERT(TargetNode->getType()->isIntegerTy());
TargetNode =
(IRNode *)LLVMBuilder->CreateIntToPtr(TargetNode, FunctionTy);
}
} else {
// We should have a usable type already.
ASSERT(TargetNode->getType()->isPointerTy());
ASSERT(TargetNode->getType()->getPointerElementType()->isFunctionTy());
}
CallInst *CallInst = LLVMBuilder->CreateCall(TargetNode, Arguments);
CorInfoIntrinsics IntrinsicID = CallTargetInfo->getCorInstrinsic();
if ((0 <= IntrinsicID) && (IntrinsicID < CORINFO_INTRINSIC_Count)) {
switch (IntrinsicID) {
@ -3504,208 +3647,26 @@ IRNode *GenIR::genCall(ReaderCallTargetData *CallTargetInfo,
}
}
Call = (IRNode *)CallInst;
Call = (IRNode *)LLVMBuilder->CreateCall(TargetNode, Arguments);
*CallNode = Call;
bool Done = false;
// Process newobj. This may involve changing the call target.
if (CallTargetInfo->isNewObj()) {
Done = canonNewObjCall(Call, CallTargetInfo, &ReturnNode);
}
if (!Done) {
// Add VarArgs cookie to outgoing param list
if (callIsCorVarArgs(Call)) {
canonVarargsCall(Call, CallTargetInfo);
}
// Add VarArgs cookie to outgoing param list
if (CC == CORINFO_CALLCONV_VARARG) {
canonVarargsCall(Call, CallTargetInfo);
}
if (IsStubCall) {
Call = canonStubCall(Call, CallTargetInfo);
}
if (ReturnNode != nullptr) {
return ReturnNode;
}
if (SigInfo->retType != CORINFO_TYPE_VOID) {
IRNode *Result = convertToStackType((IRNode *)Call, SigInfo->retType);
return Result;
*CallNode = Call;
if (ResultType.CorType != CORINFO_TYPE_VOID) {
return convertToStackType((IRNode *)Call, ResultType.CorType);
} else {
return nullptr;
}
}
// Canonicalizes a newobj call.
// Returns true if the call is done being processed.
// Outparam is the value to be pushed on the stack (this pointer of new object).
bool GenIR::canonNewObjCall(IRNode *CallNode,
ReaderCallTargetData *CallTargetData,
IRNode **OutResult) {
uint32_t ClassAttribs = CallTargetData->getClassAttribs();
CORINFO_CLASS_HANDLE ClassHandle = CallTargetData->getClassHandle();
CorInfoType CorInfoType;
uint32_t MbSize;
ReaderBase::getClassType(ClassHandle, ClassAttribs, &CorInfoType, &MbSize);
bool DoneBeingProcessed = false;
bool IsArray = ((ClassAttribs & CORINFO_FLG_ARRAY) != 0);
bool IsVarObjSize = ((ClassAttribs & CORINFO_FLG_VAROBJSIZE) != 0);
bool IsValueClass = ((ClassAttribs & CORINFO_FLG_VALUECLASS) != 0);
CallInst *CallInstruction = dyn_cast<CallInst>(CallNode);
BasicBlock *CurrentBlock = CallInstruction->getParent();
BasicBlock::iterator SavedInsertPoint = LLVMBuilder->GetInsertPoint();
LLVMBuilder->SetInsertPoint(CallInstruction);
if (IsArray) {
// Zero-based, one-dimensional arrays are allocated via newarr;
// all other arrays are allocated via newobj
*OutResult = canonNewArrayCall(CallNode, CallTargetData);
LLVMBuilder->SetInsertPoint(CurrentBlock, SavedInsertPoint);
DoneBeingProcessed = true;
} else if (IsVarObjSize) {
// We are allocating an object whose size depends on constructor args
// (e.g., string). In this case the call to the constructor will allocate
// the object.
// Leave the 'this' argument to the constructor call as null.
ASSERTNR(CallInstruction->getArgOperand(0)->getValueID() ==
Value::ConstantPointerNullVal);
// Change the type of the called function and
// the type of the CallInstruction.
CallInst *CallInstruction = cast<CallInst>(CallNode);
Value *CalledValue = CallInstruction->getCalledValue();
PointerType *CalledValueType = cast<PointerType>(CalledValue->getType());
FunctionType *FuncType =
cast<FunctionType>(CalledValueType->getElementType());
// Construct the new function type.
std::vector<Type *> Arguments;
for (unsigned I = 0; I < FuncType->getNumParams(); ++I) {
Arguments.push_back(FuncType->getParamType(I));
}
FunctionType *NewFunctionType = FunctionType::get(
FuncType->getParamType(0), Arguments, FuncType->isVarArg());
// Create a call target with the right type.
Value *NewCalledValue = LLVMBuilder->CreatePointerCast(
CalledValue, getUnmanagedPointerType(NewFunctionType));
CallInstruction->setCalledFunction(NewCalledValue);
// Change the type of the call instruction.
CallInstruction->mutateType(FuncType->getParamType(0));
LLVMBuilder->SetInsertPoint(CurrentBlock, SavedInsertPoint);
*OutResult = (IRNode *)CallInstruction;
} else if (IsValueClass) {
// We are allocating an instance of a value class on the stack.
Type *StructType = this->getType(CorInfoType, ClassHandle);
Instruction *AllocaInst = createTemporary(StructType);
// Initialize the struct to zero.
LLVMContext &LLVMContext = *this->JitContext->LLVMContext;
Value *ZeroByte = Constant::getNullValue(Type::getInt8Ty(LLVMContext));
uint32_t Align = 0;
LLVMBuilder->CreateMemSet(AllocaInst, ZeroByte, MbSize, Align);
// Create a managed pointer to the struct instance and pass it as the 'this'
// argument to the constructor call.
Type *ManagedPointerType = getManagedPointerType(StructType);
Value *ManagedPointerToStruct =
LLVMBuilder->CreateAddrSpaceCast(AllocaInst, ManagedPointerType);
Value *CalledValue = CallInstruction->getCalledValue();
PointerType *CalledValueType =
dyn_cast<PointerType>(CalledValue->getType());
FunctionType *FuncType =
dyn_cast<FunctionType>(CalledValueType->getElementType());
Type *ThisType = FuncType->getFunctionParamType(0);
ManagedPointerToStruct =
LLVMBuilder->CreatePointerCast(ManagedPointerToStruct, ThisType);
CallInstruction->setArgOperand(0, ManagedPointerToStruct);
LLVMBuilder->SetInsertPoint(CurrentBlock, SavedInsertPoint);
*OutResult = (IRNode *)makeLoadNonNull(AllocaInst, false);
} else {
// We are allocating a fixed-size class on the heap.
// Create a call to the newobj helper specific to this class,
// and use its return value as the
// 'this' pointer to be passed as the first argument to the constructor.
// Create the address operand for the newobj helper.
CorInfoHelpFunc HelperId = getNewHelper(CallTargetData->getResolvedToken());
Value *Dest = CallInstruction->getArgOperand(0);
Value *ThisPointer = callHelper(HelperId, (IRNode *)Dest,
CallTargetData->getClassHandleNode());
CallInstruction->setArgOperand(0, ThisPointer);
LLVMBuilder->SetInsertPoint(CurrentBlock, SavedInsertPoint);
*OutResult = (IRNode *)ThisPointer;
}
return DoneBeingProcessed;
}
IRNode *GenIR::canonNewArrayCall(IRNode *Call,
ReaderCallTargetData *CallTargetData) {
CallInst *CallInstruction = dyn_cast<CallInst>(Call);
Value *CalledValue = CallInstruction->getCalledValue();
PointerType *CalledValueType = dyn_cast<PointerType>(CalledValue->getType());
FunctionType *FuncType =
dyn_cast<FunctionType>(CalledValueType->getElementType());
// To construct the array we need to call a helper passing it the class handle
// for the constructor method, the number of arguments to the constructor and
// the arguments to the constructor.
// Construct the new function type.
std::vector<Type *> NewTypeArguments;
std::vector<Value *> NewArguments;
// The first argument is the class handle.
IRNode *ClassHandle = CallTargetData->getClassHandleNode();
ASSERTNR(ClassHandle);
NewTypeArguments.push_back(ClassHandle->getType());
NewArguments.push_back(ClassHandle);
// The second argument is the number of arguments to follow.
uint32_t NumBits = 32;
bool IsSigned = true;
Value *NumArgs = ConstantInt::get(
*JitContext->LLVMContext,
APInt(NumBits, CallTargetData->getSigInfo()->numArgs, IsSigned));
ASSERTNR(NumArgs);
NewTypeArguments.push_back(NumArgs->getType());
NewArguments.push_back(NumArgs);
// The rest of the arguments are the same as in the original newobj call.
// It's a vararg call so add arguments but not type arguments.
for (unsigned I = 1; I < FuncType->getNumParams(); ++I) {
NewArguments.push_back(CallInstruction->getArgOperand(I));
}
bool IsVarArg = true;
FunctionType *NewFunctionType =
FunctionType::get(FuncType->getParamType(0), NewTypeArguments, IsVarArg);
// Create a call target with the right type.
// Get the address of the Helper descr.
IRNode *Target = getHelperCallAddress(CORINFO_HELP_NEW_MDARR);
Value *NewCalledValue = LLVMBuilder->CreateIntToPtr(
Target, getUnmanagedPointerType(NewFunctionType));
// Replace the old call instruction with the new one.
CallInst *NewCallInstruction =
LLVMBuilder->CreateCall(NewCalledValue, NewArguments);
CallInstruction->eraseFromParent();
return (IRNode *)NewCallInstruction;
}
IRNode *GenIR::convertToBoxHelperArgumentType(IRNode *Opr,
CorInfoType DestType) {
Type *Ty = Opr->getType();
@ -3739,13 +3700,6 @@ IRNode *GenIR::convertToBoxHelperArgumentType(IRNode *Opr,
return Opr;
}
bool GenIR::callIsCorVarArgs(IRNode *CallNode) {
CallInst *CallInstruction = cast<CallInst>(CallNode);
Value *CalledValue = CallInstruction->getCalledValue();
PointerType *CalledValueType = dyn_cast<PointerType>(CalledValue->getType());
return dyn_cast<FunctionType>(CalledValueType->getElementType())->isVarArg();
}
IRNode *GenIR::canonStubCall(IRNode *CallNode,
ReaderCallTargetData *CallTargetData) {
assert(CallTargetData != nullptr);
@ -4047,17 +4001,6 @@ IRNode *GenIR::convert(Type *Ty, Value *Node, bool SourceIsSigned) {
return (IRNode *)Result;
}
IRNode *GenIR::makeCallReturnNode(CORINFO_SIG_INFO *Sig,
unsigned *HiddenMBParamSize,
GCLayout **GcInfo) {
if ((Sig->retType == CORINFO_TYPE_REFANY) ||
(Sig->retType == CORINFO_TYPE_VALUECLASS)) {
throw NotYetImplementedException("Return refany or value class");
}
return nullptr;
}
// Common to both recursive and non-recursive tail call considerations.
// The debug messages are only wanted when checking the general case
// and not for special recursive checks.
@ -4801,9 +4744,7 @@ IRNode *GenIR::loadVirtFunc(IRNode *Arg1, CORINFO_RESOLVED_TOKEN *ResolvedToken,
IRNode *CodeAddress = callHelperImpl(CORINFO_HELP_VIRTUAL_FUNC_PTR, Ty, Arg1,
TypeToken, MethodToken);
FunctionType *FunctionType = getFunctionType(CallInfo->hMethod);
return (IRNode *)LLVMBuilder->CreateIntToPtr(
CodeAddress, getUnmanagedPointerType(FunctionType));
return CodeAddress;
}
IRNode *GenIR::getPrimitiveAddress(IRNode *Addr, CorInfoType CorInfoType,