зеркало из https://github.com/dotnet/llilc.git
Merge branch 'master' of https://github.com/dotnet/llilc into RemoveCLRHeaders
This commit is contained in:
Коммит
e03dc5fecf
|
@ -81,16 +81,16 @@ public:
|
|||
/// In addition, any cache coherency operations needed to reliably use the
|
||||
/// memory are also performed.
|
||||
///
|
||||
/// \param ErrMsg[out] Additional information about finalization errors
|
||||
/// \param ErrMsg [out] Additional information about finalization errors.
|
||||
/// \returns false if an error occurred, true otherwise.
|
||||
bool finalizeMemory(std::string *ErrMsg = nullptr) override;
|
||||
|
||||
/// Inform the memory manager about the total amount of memory required to
|
||||
/// allocate all sections to be loaded.
|
||||
///
|
||||
/// \param CodeSize - the total size of all code sections
|
||||
/// \param DataSizeRO - the total size of all read-only data sections
|
||||
/// \param DataSizeRW - the total size of all read-write data sections
|
||||
/// \param CodeSize - the total size of all code sections.
|
||||
/// \param DataSizeRO - the total size of all read-only data sections.
|
||||
/// \param DataSizeRW - the total size of all read-write data sections.
|
||||
///
|
||||
/// Note that by default the callback is disabled. To enable it
|
||||
/// redefine the method needsToReserveAllocationSpace to return true.
|
||||
|
@ -108,19 +108,19 @@ public:
|
|||
///
|
||||
/// This is currently invoked once per .xdata section. The EE uses this info
|
||||
/// to build and register the appropriate .pdata with the OS.
|
||||
/// \param Addr The address of the data in the pre-loaded image
|
||||
/// \param LoadAddr The address the data will have once loaded
|
||||
/// \param Size Size of the unwind data in bytes
|
||||
/// \param Addr The address of the data in the pre-loaded image.
|
||||
/// \param LoadAddr The address the data will have once loaded.
|
||||
/// \param Size Size of the unwind data in bytes.
|
||||
/// \note Because we're not relocating data during loading, \p Addr and
|
||||
/// \p LoadAddr are currently identical.
|
||||
void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) override;
|
||||
|
||||
private:
|
||||
LLILCJitContext *Context; ///< LLVM context for types, etc
|
||||
uint8_t *HotCodeBlock; ///< Memory to hold the hot method code
|
||||
uint8_t *ColdCodeBlock; ///< Memory to hold the cold method code
|
||||
uint8_t *ReadOnlyDataBlock; ///< Memory to hold the readonly data
|
||||
uint8_t *ReadOnlyDataUnallocated; ///< Address of unallocated part of RO data
|
||||
LLILCJitContext *Context; ///< LLVM context for types, etc.
|
||||
uint8_t *HotCodeBlock; ///< Memory to hold the hot method code.
|
||||
uint8_t *ColdCodeBlock; ///< Memory to hold the cold method code.
|
||||
uint8_t *ReadOnlyDataBlock; ///< Memory to hold the readonly data.
|
||||
uint8_t *ReadOnlyDataUnallocated; ///< Address of unallocated part of RO data.
|
||||
};
|
||||
} // namespace llvm
|
||||
|
||||
|
|
|
@ -24,9 +24,9 @@
|
|||
|
||||
/// \brief Enum for LLVM IR Dump Level
|
||||
enum LLVMDumpLevel {
|
||||
NODUMP, ///< Do not dump any LLVM IR or summary
|
||||
SUMMARY, ///< Only dump one line summary per method
|
||||
VERBOSE ///< Dump full LLVM IR and method summary
|
||||
NODUMP, ///< Do not dump any LLVM IR or summary.
|
||||
SUMMARY, ///< Only dump one line summary per method.
|
||||
VERBOSE ///< Dump full LLVM IR and method summary.
|
||||
};
|
||||
|
||||
struct LLILCJitPerThreadState;
|
||||
|
@ -43,7 +43,7 @@ struct LLILCJitPerThreadState;
|
|||
struct LLILCJitContext {
|
||||
|
||||
/// Construct a context and push it onto the context stack.
|
||||
/// \param State the per-thread state for this thread
|
||||
/// \param State the per-thread state for this thread.
|
||||
LLILCJitContext(LLILCJitPerThreadState *State);
|
||||
|
||||
/// Destruct this context and pop it from the context stack.
|
||||
|
@ -73,32 +73,32 @@ struct LLILCJitContext {
|
|||
public:
|
||||
/// \name CoreCLR EE information
|
||||
//@{
|
||||
ICorJitInfo *JitInfo; ///< EE callback interface
|
||||
CORINFO_METHOD_INFO *MethodInfo; ///< Description of method to jit
|
||||
uint32_t Flags; ///< Flags controlling jit behavior
|
||||
CORINFO_EE_INFO EEInfo; ///< Information about internal EE data
|
||||
std::string MethodName; ///< Name of the method (for diagnostics)
|
||||
ICorJitInfo *JitInfo; ///< EE callback interface.
|
||||
CORINFO_METHOD_INFO *MethodInfo; ///< Description of method to jit.
|
||||
uint32_t Flags; ///< Flags controlling jit behavior.
|
||||
CORINFO_EE_INFO EEInfo; ///< Information about internal EE data.
|
||||
std::string MethodName; ///< Name of the method (for diagnostics).
|
||||
//@}
|
||||
|
||||
/// \name LLVM information
|
||||
//@{
|
||||
llvm::LLVMContext *LLVMContext; ///< LLVM context for types and similar
|
||||
llvm::Module *CurrentModule; ///< Module holding LLVM IR
|
||||
llvm::ExecutionEngine *EE; ///< MCJIT execution engine
|
||||
bool HasLoadedBitCode; ///< Flag for side-loaded LLVM IR
|
||||
llvm::LLVMContext *LLVMContext; ///< LLVM context for types and similar.
|
||||
llvm::Module *CurrentModule; ///< Module holding LLVM IR.
|
||||
llvm::ExecutionEngine *EE; ///< MCJIT execution engine.
|
||||
bool HasLoadedBitCode; ///< Flag for side-loaded LLVM IR.
|
||||
//@}
|
||||
|
||||
/// \name Context management
|
||||
//@{
|
||||
LLILCJitContext *Next; ///< Parent jit context, if any
|
||||
LLILCJitPerThreadState *State; ///< Per thread state for the jit
|
||||
LLILCJitContext *Next; ///< Parent jit context, if any.
|
||||
LLILCJitPerThreadState *State; ///< Per thread state for the jit.
|
||||
//@}
|
||||
|
||||
/// \name Jit output sizes
|
||||
//@{
|
||||
uint32_t HotCodeSize = 0; ///< Size of hot code section in bytes
|
||||
uint32_t ColdCodeSize = 0; ///< Size of cold code section in bytes
|
||||
uint32_t ReadOnlyDataSize = 0; ///< Size of readonly data ref'd from code
|
||||
uint32_t HotCodeSize = 0; ///< Size of hot code section in bytes.
|
||||
uint32_t ColdCodeSize = 0; ///< Size of cold code section in bytes.
|
||||
uint32_t ReadOnlyDataSize = 0; ///< Size of readonly data ref'd from code.
|
||||
//@}
|
||||
};
|
||||
|
||||
|
@ -114,8 +114,8 @@ struct LLILCJitPerThreadState {
|
|||
public:
|
||||
/// Construct a new state.
|
||||
LLILCJitPerThreadState()
|
||||
: LLVMContext(), ClassTypeMap(), ArrayTypeMap(), FieldIndexMap(),
|
||||
JitContext(nullptr) {}
|
||||
: LLVMContext(), ClassTypeMap(), BoxedTypeMap(), ArrayTypeMap(),
|
||||
FieldIndexMap(), JitContext(nullptr) {}
|
||||
|
||||
/// Each thread maintains its own \p LLVMContext. This is where
|
||||
/// LLVM keeps definitions of types and similar constructs.
|
||||
|
@ -127,6 +127,10 @@ public:
|
|||
/// Map from class handles to the LLVM types that represent them.
|
||||
std::map<CORINFO_CLASS_HANDLE, llvm::Type *> ClassTypeMap;
|
||||
|
||||
/// Map from class handles for value types to the LLVM types that represent
|
||||
/// their boxed versions.
|
||||
std::map<CORINFO_CLASS_HANDLE, llvm::Type *> BoxedTypeMap;
|
||||
|
||||
/// \brief Map from class handles for arrays to the LLVM types that represent
|
||||
/// them.
|
||||
///
|
||||
|
@ -165,11 +169,11 @@ public:
|
|||
/// Main entry point into the jit. Invoked once per method to be jitted.
|
||||
/// May be invoked re-entrantly and/or concurrently on multiple threads.
|
||||
///
|
||||
/// \param JitInfo Interface the jit can use for callbacks
|
||||
/// \param MethodInfo Data structure describing the method to jit
|
||||
/// \param Flags CorJitFlags controlling jit behavior
|
||||
/// \param NativeEntry[out] Address of the jitted code
|
||||
/// \param NativeSizeOfCode[out] Length of the jitted code
|
||||
/// \param JitInfo Interface the jit can use for callbacks.
|
||||
/// \param MethodInfo Data structure describing the method to jit.
|
||||
/// \param Flags CorJitFlags controlling jit behavior.
|
||||
/// \param NativeEntry [out] Address of the jitted code.
|
||||
/// \param NativeSizeOfCode [out] Length of the jitted code.
|
||||
///
|
||||
/// \returns Code indicating success or failure of the jit request.
|
||||
CorJitResult __stdcall compileMethod(ICorJitInfo *JitInfo,
|
||||
|
@ -181,7 +185,7 @@ public:
|
|||
void clearCache() override;
|
||||
|
||||
/// Check if cache cleanup is required.
|
||||
/// \returns \p true if the jit is caching information
|
||||
/// \returns \p true if the jit is caching information.
|
||||
BOOL isCacheCleanupRequired() override;
|
||||
|
||||
/// \brief Get the Jit's version identifier.
|
||||
|
@ -190,17 +194,21 @@ public:
|
|||
/// the jit for a version identifier GUID, and verify that it matches the
|
||||
/// expectations of the EE.
|
||||
///
|
||||
/// \param VersionIdentifier[out] Buffer where the jit's GUID can be stored
|
||||
/// \param VersionIdentifier [out] Buffer where the jit's GUID can be stored.
|
||||
void getVersionIdentifier(GUID *VersionIdentifier) override;
|
||||
|
||||
/// \brief Get access to the current jit context.
|
||||
///
|
||||
/// This method can be called from anywhere to retrieve the current jit
|
||||
/// context.
|
||||
///
|
||||
/// \returns Context for the current jit request.
|
||||
static LLILCJitContext *getLLILCJitContext() {
|
||||
return TheJit->State.get()->JitContext;
|
||||
}
|
||||
|
||||
/// Report a fatal error in the Jit.
|
||||
/// \param Errnum Error number to report in exception context
|
||||
/// \param Errnum Error number to report in exception context.
|
||||
static void __cdecl fatal(int Errnum, ...);
|
||||
|
||||
/// Signal handler for LLVM abort signals.
|
||||
|
|
|
@ -1220,10 +1220,10 @@ public:
|
|||
/// direct client processing for the method parameters and the local
|
||||
/// variables of the method.
|
||||
///
|
||||
/// \param NumParams Number of parameters to the method. Note this
|
||||
/// \param NumParam Number of parameters to the method. Note this
|
||||
/// includes implicit parameters like the this
|
||||
/// pointer.
|
||||
/// \param NumAutos Number of locals described in the local
|
||||
/// \param NumAuto Number of locals described in the local
|
||||
/// signature.
|
||||
/// \param HasSecretParameter Indicates whether or not the terminal parameter
|
||||
/// is the secret parameter of an IL stub.
|
||||
|
@ -1269,7 +1269,7 @@ public:
|
|||
CORINFO_CLASS_HANDLE *Class = nullptr,
|
||||
bool *IsPinned = nullptr);
|
||||
|
||||
/// \brief Build the flow graph for the method
|
||||
/// \brief Build the flow graph for the method.
|
||||
///
|
||||
/// Create a flow graph for the method. This determines which range of
|
||||
/// MSIL instructions will lie within each node in the flow graph,
|
||||
|
@ -1279,7 +1279,7 @@ public:
|
|||
/// \returns The first flow graph node in the graph.
|
||||
FlowGraphNode *buildFlowGraph(FlowGraphNode **FgTail);
|
||||
|
||||
/// \brief Split a flow graph node (aka block)
|
||||
/// \brief Split a flow graph node (aka block).
|
||||
///
|
||||
/// Break the indicated \p Block into two blocks, with the divsion
|
||||
/// happening at the indicated MSIL \p Offset. The client method
|
||||
|
@ -1289,7 +1289,7 @@ public:
|
|||
/// \param Block The flow graph mode to split
|
||||
/// \param Offset The MSIL offset of the split point. Must be within
|
||||
/// the MSIL range for the block.
|
||||
/// \param IRNode The IR node corresponding to the split point.
|
||||
/// \param Node The IR node corresponding to the split point.
|
||||
/// \returns The new node.
|
||||
FlowGraphNode *fgSplitBlock(FlowGraphNode *Block, uint32_t Offset,
|
||||
IRNode *Node);
|
||||
|
@ -1300,69 +1300,69 @@ public:
|
|||
/// Print the MSIL in the buffer for the given range. Output emitted via
|
||||
/// \p dbPrint().
|
||||
///
|
||||
/// \param Buf Buffer containing MSIL bytecode
|
||||
/// \param StartOffset Initial offset for the range to print
|
||||
/// \param EndOffset Ending offset for the range to print
|
||||
/// \param Buf Buffer containing MSIL bytecode.
|
||||
/// \param StartOffset Initial offset for the range to print.
|
||||
/// \param EndOffset Ending offset for the range to print.
|
||||
void printMSIL(uint8_t *Buf, uint32_t StartOffset, uint32_t EndOffset);
|
||||
#endif
|
||||
|
||||
/// \brief Determine the effect of this instruction on the operand stack
|
||||
/// \brief Determine the effect of this instruction on the operand stack.
|
||||
///
|
||||
/// Many MSIL instructions push or pop operands from the stack, or both pop
|
||||
/// and push operands. This method determines the net number of pushes and
|
||||
/// pops for a particular instruction.
|
||||
///
|
||||
/// \param Opcode The MSIL opcode for the instruction
|
||||
/// \param Opcode The MSIL opcode for the instruction.
|
||||
/// \param Operand For call opcodes with signature tokens, pointer to the
|
||||
/// token value in the IL stream
|
||||
/// \param Pop [out] Number of operands popped from the stack
|
||||
/// \param Push [out] Number of operands pushed onto the stack
|
||||
/// token value in the IL stream.
|
||||
/// \param Pop [out] Number of operands popped from the stack.
|
||||
/// \param Push [out] Number of operands pushed onto the stack.
|
||||
void getMSILInstrStackDelta(ReaderBaseNS::OPCODE Opcode, uint8_t *Operand,
|
||||
uint16_t *Pop, uint16_t *Push);
|
||||
|
||||
private:
|
||||
/// \brief Determine if a call instruction is a candidate to be a tail call
|
||||
/// \brief Determine if a call instruction is a candidate to be a tail call.
|
||||
///
|
||||
/// The client may decide to give special tail-call treatment to calls that
|
||||
/// are followed closely by returns, even if the calls are not marked with
|
||||
/// the tail prefix. This method determines if such treatment is possible.
|
||||
///
|
||||
/// \param ILInput Pointer to the start of the MSIL bytecode stream
|
||||
/// \param ILInputSize Length of the MSIL bytecode stream
|
||||
/// \param NextOffset Offset into the stream just past the call
|
||||
/// \param Token Token value for calls that have sig tokens
|
||||
/// \param ILInput Pointer to the start of the MSIL bytecode stream.
|
||||
/// \param ILInputSize Length of the MSIL bytecode stream.
|
||||
/// \param NextOffset Offset into the stream just past the call.
|
||||
/// \param Token Token value for calls that have sig tokens.
|
||||
///
|
||||
/// \returns True if treating this call as a tail call is
|
||||
/// reasonble.
|
||||
bool isUnmarkedTailCall(uint8_t *ILInput, uint32_t ILInputSize,
|
||||
uint32_t NextOffset, mdToken Token);
|
||||
|
||||
/// \brief Helper method called from \p isUnmarkedTailCall
|
||||
/// \brief Helper method called from \p isUnmarkedTailCall.
|
||||
///
|
||||
/// \param ILInput Pointer to the start of the MSIL bytecode stream
|
||||
/// \param ILInputSize Length of the MSIL bytecode stream
|
||||
/// \param NextOffset Offset into the stream just past the call
|
||||
/// \param Token Token value for calls that have sig tokens
|
||||
/// \param ILInput Pointer to the start of the MSIL bytecode stream.
|
||||
/// \param ILInputSize Length of the MSIL bytecode stream.
|
||||
/// \param NextOffset Offset into the stream just past the call.
|
||||
/// \param Token Token value for calls that have sig tokens.
|
||||
///
|
||||
/// \returns True if treating this call as a tail call is
|
||||
/// reasonble.
|
||||
bool isUnmarkedTailCallHelper(uint8_t *ILInput, uint32_t ILInputSize,
|
||||
uint32_t NextOffset, mdToken Token);
|
||||
|
||||
/// \brief Check if the current instruction is a valid explicit tail call
|
||||
/// \brief Check if the current instruction is a valid explicit tail call.
|
||||
///
|
||||
/// Verify that this call is a valid explicit tail call. The call must be
|
||||
/// closely followed by a return.
|
||||
///
|
||||
/// \param ILOffset Offset of the call instruction in the IL stream
|
||||
/// \param AllowPop true if it is acceptable for the call to be
|
||||
/// followed by a single pop before reaching the
|
||||
/// \param ILOffset Offset of the call instruction in the IL stream.
|
||||
/// \param AllowPop true if it is acceptable for the call to be.
|
||||
/// followed by a single pop before reaching the.
|
||||
/// return.
|
||||
/// \returns True if the current instruction is a valid explicit
|
||||
/// tail call.
|
||||
bool checkExplicitTailCall(uint32_t ILOffset, bool AllowPop);
|
||||
|
||||
/// \brief Convert the MSIL for this flow graph node into the client IR
|
||||
/// \brief Convert the MSIL for this flow graph node into the client IR.
|
||||
///
|
||||
/// Orchestrates client processing the MSIL in this flow graph node,
|
||||
/// filling in the block contents. This outer method sets up a parameter
|
||||
|
@ -1373,18 +1373,17 @@ private:
|
|||
/// \param IsVerifyOnly True if the reader is only verifying the MSIL.
|
||||
void readBytesForFlowGraphNode(FlowGraphNode *Fg, bool IsVerifyOnly);
|
||||
|
||||
/// \brief Helper method for \p readBytesForFlowGraphNode
|
||||
/// \brief Helper method for \p readBytesForFlowGraphNode.
|
||||
///
|
||||
/// Helper method that orchestrates client processing the MSIL in a flow
|
||||
/// graph node specified by the parameters.
|
||||
///
|
||||
/// \param Param Encapsulated state from the main method
|
||||
/// \param IsVerifyOnly True if the reader is only verifying the MSIL.
|
||||
/// \param Param Encapsulated state from the main method.
|
||||
void
|
||||
readBytesForFlowGraphNodeHelper(ReadBytesForFlowGraphNodeHelperParam *Param);
|
||||
|
||||
protected:
|
||||
/// \brief Create or return a flow graph node for the indicated offset
|
||||
/// \brief Create or return a flow graph node for the indicated offset.
|
||||
///
|
||||
/// This method sees if there is an existing flow graph node that begins at
|
||||
/// the indicated target. If so, \p Node is set to this block. If not, a
|
||||
|
@ -1392,25 +1391,25 @@ protected:
|
|||
/// to the \p NodeOffsetListArray so a subsequent pass can update the
|
||||
/// temporary target blocks to real target blocks.
|
||||
///
|
||||
/// \param Node [out] Node to use as the branch target
|
||||
/// \param TargetOffset MSIL offset of the branch target
|
||||
/// \returns List node of target in offset list
|
||||
/// \param Node [out] Node to use as the branch target.
|
||||
/// \param TargetOffset MSIL offset of the branch target.
|
||||
/// \returns List node of target in offset list.
|
||||
FlowGraphNodeOffsetList *fgAddNodeMSILOffset(FlowGraphNode **Node,
|
||||
uint32_t TargetOffset);
|
||||
|
||||
/// Get the innermost finally region enclosing the given \p Offset
|
||||
/// Get the innermost finally region enclosing the given \p Offset.
|
||||
///
|
||||
/// \param Offset MSIL offset of interest
|
||||
/// \param Offset MSIL offset of interest.
|
||||
/// \returns The innermost finally region enclosing \p Offset if one exists;
|
||||
/// nullptr otherwise
|
||||
/// nullptr otherwise.
|
||||
EHRegion *getInnermostFinallyRegion(uint32_t Offset);
|
||||
|
||||
/// Find the next-innermost region enclosing the given \p Offset
|
||||
/// Find the next-innermost region enclosing the given \p Offset.
|
||||
///
|
||||
/// \param OuterRegion Limit search to regions nested inside OuterRegion
|
||||
/// \param Offset Limit search to regions enclosing Offset
|
||||
/// \param OuterRegion Limit search to regions nested inside OuterRegion.
|
||||
/// \param Offset Limit search to regions enclosing Offset.
|
||||
/// \returns The outermost region that is nested inside \p OuterRegion and
|
||||
/// that includes \p Offset, if such a region exists; else nullptr
|
||||
/// that includes \p Offset, if such a region exists; else nullptr.
|
||||
EHRegion *getInnerEnclosingRegion(EHRegion *OuterRegion, uint32_t Offset);
|
||||
|
||||
private:
|
||||
|
@ -1426,11 +1425,11 @@ private:
|
|||
/// Helper used to check whether branch targets and similar are referring
|
||||
/// to the start of instructions.
|
||||
///
|
||||
/// \param Offset Offset into the MSIL stream
|
||||
/// \returns True if \pO Offset is the start of an MSIL instruction.
|
||||
/// \param Offset Offset into the MSIL stream.
|
||||
/// \returns True if \p Offset is the start of an MSIL instruction.
|
||||
bool isOffsetInstrStart(uint32_t Offset);
|
||||
|
||||
// \brief Get custom sequence points
|
||||
// \brief Get custom sequence points.
|
||||
///
|
||||
/// This method checks with the EE to see if there are any debugger-specified
|
||||
/// sequence points in the method. The results of this call is a bit vector
|
||||
|
@ -1448,30 +1447,30 @@ private:
|
|||
/// instructions (branches and similar). Uses these to instruct the client
|
||||
/// to produce a flow graph describing the method's control flow.
|
||||
///
|
||||
/// \param Buffer Buffer of MSIL bytecodes
|
||||
/// \param BufferSize Length of the buffer in bytes
|
||||
/// \param Buffer Buffer of MSIL bytecodes.
|
||||
/// \param BufferSize Length of the buffer in bytes.
|
||||
/// \returns Head node of the flow graph.
|
||||
FlowGraphNode *fgBuildBasicBlocksFromBytes(uint8_t *Buffer,
|
||||
uint32_t BufferSize);
|
||||
|
||||
/// \brief First pass of flow graph construction
|
||||
/// \brief First pass of flow graph construction.
|
||||
///
|
||||
/// This pass determines the legal starting points of all MSIL instructions,
|
||||
/// locates all block-ending instructions (branches and similar) and all
|
||||
/// branch targets, and builds blocks that end with the block-ending
|
||||
/// instructions and have appropriate flow graph edges to successor blocks.
|
||||
///
|
||||
/// \param Fg Nominal entry node for the method
|
||||
/// \param Buffer Buffer of MSIL bytecodes
|
||||
/// \param BufferSize Length of the buffer in bytes
|
||||
/// \param Fg Nominal entry node for the method.
|
||||
/// \param Buffer Buffer of MSIL bytecodes.
|
||||
/// \param BufferSize Length of the buffer in bytes.
|
||||
void fgBuildPhase1(FlowGraphNode *Fg, uint8_t *Buffer, uint32_t BufferSize);
|
||||
|
||||
/// Create initial global verification data for all blocks in the flow graph
|
||||
/// Create initial global verification data for all blocks in the flow graph.
|
||||
///
|
||||
/// \param HeadBlock Initial block in the flow graph
|
||||
/// \param HeadBlock Initial block in the flow graph.
|
||||
void fgAttachGlobalVerifyData(FlowGraphNode *HeadBlock);
|
||||
|
||||
/// Perform special case repair for recursive tail call and localloc
|
||||
/// Perform special case repair for recursive tail call and localloc.
|
||||
///
|
||||
/// The flow graph builder can optimistically describe recursive tail
|
||||
/// calls as branches back to the start of the method. However this must
|
||||
|
@ -1482,22 +1481,22 @@ private:
|
|||
|
||||
/// Helper method for building up the cases of a switch.
|
||||
///
|
||||
/// \param SwitchNode The client IR representing the switch
|
||||
/// \param LabelNode The client IR representing the case target
|
||||
/// \param Element The switch value for this case
|
||||
/// \param SwitchNode The client IR representing the switch.
|
||||
/// \param LabelNode The client IR representing the case target.
|
||||
/// \param Element The switch value for this case.
|
||||
/// \returns The case node added to the switch.
|
||||
IRNode *fgAddCaseToCaseListHelper(IRNode *SwitchNode, IRNode *LabelNode,
|
||||
uint32_t Element);
|
||||
|
||||
/// \brief Add the unvisited successors of this block to the worklist
|
||||
/// \brief Add the unvisited successors of this block to the worklist.
|
||||
///
|
||||
/// This method scans all the successor blocks of \p CurrBlock, and
|
||||
/// if there are any, creates new work list nodes for these successors,
|
||||
/// marks them as visited, and (despite the method name) prepends them,
|
||||
/// returning a new worklist head node.
|
||||
///
|
||||
/// \param Worklist The current worklist of unvisited blocks
|
||||
/// \param CurrBlock The block to examine for unvisited successors
|
||||
/// \param Worklist The current worklist of unvisited blocks.
|
||||
/// \param CurrBlock The block to examine for unvisited successors.
|
||||
/// \returns Updated list of unvisited blocks.
|
||||
FlowGraphNodeWorkList *
|
||||
fgAppendUnvisitedSuccToWorklist(FlowGraphNodeWorkList *Worklist,
|
||||
|
@ -1527,8 +1526,8 @@ private:
|
|||
/// Scan the EH regions of the method looking for the smallest region
|
||||
/// that contains this MSIL offset.
|
||||
///
|
||||
/// \param Offset The MSIL offset in question
|
||||
/// \returns Pointer to the innermost region, or nullptr if none
|
||||
/// \param Offset The MSIL offset in question.
|
||||
/// \returns Pointer to the innermost region, or nullptr if none.
|
||||
EHRegion *fgGetRegionFromMSILOffset(uint32_t Offset);
|
||||
|
||||
/// \brief Update the branches with temporary targets at this offset.
|
||||
|
@ -1538,84 +1537,84 @@ private:
|
|||
/// a particular temporary node with the actual node representing the
|
||||
/// target in the flow graph.
|
||||
///
|
||||
/// \param Offset The MSIL offset of the branch target
|
||||
/// \param TempBranchTarget The placeholder node for the target
|
||||
/// \param Offset The MSIL offset of the branch target.
|
||||
/// \param TempBranchTarget The placeholder node for the target.
|
||||
/// \param StartBlock A node at an offset less than the target.
|
||||
/// \returns The updated target block
|
||||
/// \returns The updated target block.
|
||||
FlowGraphNode *fgReplaceBranchTarget(uint32_t Offset,
|
||||
FlowGraphNode *TempBranchTarget,
|
||||
FlowGraphNode *StartBlock);
|
||||
|
||||
/// \brief Update all branches with temporary targets
|
||||
/// \brief Update all branches with temporary targets.
|
||||
///
|
||||
/// Walks the list of branch target offsets, invoking
|
||||
/// \p fgReplaceBranchTarget to update all branches with that target to
|
||||
/// refer to the proper blocks.
|
||||
void fgReplaceBranchTargets();
|
||||
|
||||
/// Process the end of a try region
|
||||
/// \param EHRegion The region to process.
|
||||
/// Process the end of a try region.
|
||||
/// \param EhRegion The region to process.
|
||||
void fgInsertTryEnd(EHRegion *EhRegion);
|
||||
|
||||
/// Place client IR into the start of the EH region that begins at Offset.
|
||||
///
|
||||
/// \param Offset MSIL offset of the start of an EH region
|
||||
/// \param EHNode Client IR to insert into the block that
|
||||
/// \param Offset MSIL offset of the start of an EH region.
|
||||
/// \param EHNode Client IR to insert into the block that.
|
||||
/// starts that region.
|
||||
void fgInsertBeginRegionExceptionNode(uint32_t Offset, IRNode *EHNode);
|
||||
|
||||
/// Place client IR into the end of the EH region that ends at Offset.
|
||||
///
|
||||
/// \param Offset MSIL offset of the end of an EH region
|
||||
/// \param Offset MSIL offset of the end of an EH region.
|
||||
/// \param EHNode Client IR to insert into the block that
|
||||
/// ends that region.
|
||||
void fgInsertEndRegionExceptionNode(uint32_t Offset, IRNode *EHNode);
|
||||
|
||||
/// Add client IR for an EH region and all contained regions.
|
||||
///
|
||||
/// \param Region Root region to process
|
||||
/// \param Region Root region to process.
|
||||
void fgInsertEHAnnotations(EHRegion *Region);
|
||||
|
||||
/// \brief Create branch IR
|
||||
/// \brief Create branch IR.
|
||||
///
|
||||
/// Have the client create a branch to \p LabelNode from \p BlockNode.
|
||||
///
|
||||
/// \param LabelNode target block of the branch
|
||||
/// \param BlockNode source block for the branch
|
||||
/// \param Offset MSIL offset of the branch target
|
||||
/// \param IsConditional true if this is a conditional branch
|
||||
/// \param IsNominal true if this is a nominal branch
|
||||
/// \returns IRNode for the branch created
|
||||
/// \param LabelNode target block of the branch.
|
||||
/// \param BlockNode source block for the branch.
|
||||
/// \param Offset MSIL offset of the branch target.
|
||||
/// \param IsConditional true if this is a conditional branch.
|
||||
/// \param IsNominal true if this is a nominal branch.
|
||||
/// \returns IRNode for the branch created.
|
||||
IRNode *fgMakeBranchHelper(IRNode *LabelNode, IRNode *BlockNode,
|
||||
uint32_t Offset, bool IsConditional,
|
||||
bool IsNominal);
|
||||
|
||||
/// \brief Create IR for an endfinally instruction
|
||||
/// \brief Create IR for an endfinally instruction.
|
||||
///
|
||||
/// Have the client create IR for an endfinally instruction. Note
|
||||
/// there can be more than one of these in a finally region.
|
||||
///
|
||||
/// \param BlockNode the block that is the end of the finally
|
||||
/// \param FinallyRegion the finally region being ended
|
||||
/// \param Offset msil offset for the endfinally instruction
|
||||
/// \returns the branch generated to terminate the block for this endfinally
|
||||
/// \param BlockNode the block that is the end of the finally.
|
||||
/// \param FinallyRegion the finally region being ended.
|
||||
/// \param Offset msil offset for the endfinally instruction.
|
||||
/// \returns the branch generated to terminate the block for this endfinally.
|
||||
IRNode *fgMakeEndFinallyHelper(IRNode *BlockNode, EHRegion *FinallyRegion,
|
||||
uint32_t Offset);
|
||||
|
||||
/// \brief Remove all unreachable blocks
|
||||
/// \brief Remove all unreachable blocks.
|
||||
///
|
||||
/// Walk the flow graph and remove any block (except the tail block)
|
||||
/// that cannot be reached from the head block. Blocks are removed by
|
||||
/// calling \p fgDeleteBlockAndNodes.
|
||||
///
|
||||
/// \param FgHead the head block of the flow graph
|
||||
/// \param FgTail the tail block of the flow graph
|
||||
/// \param FgHead the head block of the flow graph.
|
||||
/// \param FgTail the tail block of the flow graph.
|
||||
void fgRemoveUnusedBlocks(FlowGraphNode *FgHead, FlowGraphNode *FgTail);
|
||||
|
||||
/// Find the canonical landing point for leaves from an EH region
|
||||
/// Find the canonical landing point for leaves from an EH region.
|
||||
///
|
||||
/// \param Region The region in question.
|
||||
/// \returns The MSIL offset of the canonical landing point
|
||||
/// \returns The MSIL offset of the canonical landing point.
|
||||
uint32_t fgGetRegionCanonicalExitOffset(EHRegion *Region);
|
||||
|
||||
/// Buffer used by \p fgGetRegionCanonicalExitOffset for cases where
|
||||
|
@ -1624,13 +1623,13 @@ private:
|
|||
|
||||
/// Determine if a leave exits the enclosing EH region in a non-local manner.
|
||||
///
|
||||
/// \param Fg flow graph node containing the leave
|
||||
/// \param LeaveOffset MSIL offset of the leave
|
||||
/// \param LeaveTarget MSIL offset of the leave's target
|
||||
/// \param EndsWithNonLocalGoto [out] Target of the leave is not the
|
||||
/// canonical exit offset of the region
|
||||
/// \param Fg flow graph node containing the leave.
|
||||
/// \param LeaveOffset MSIL offset of the leave.
|
||||
/// \param LeaveTarget MSIL offset of the leave's target.
|
||||
/// \param EndsWithNonLocalGoto [out] Target of the leave is not the
|
||||
/// canonical exit offset of the region.
|
||||
///
|
||||
/// \returns True if this is a nonlocal leave
|
||||
/// \returns True if this is a nonlocal leave.
|
||||
bool fgLeaveIsNonLocal(FlowGraphNode *Fg, uint32_t LeaveOffset,
|
||||
uint32_t LeaveTarget, bool *EndsWithNonLocalGoto);
|
||||
|
||||
|
|
|
@ -267,7 +267,7 @@ enum ConvOpcode {
|
|||
ConvOvfI4, ///< As #ConvI4, but throws an exception if the result is out of
|
||||
///< range.
|
||||
|
||||
ConvOnvI8, ///< As #ConvI8, but throws an exception if the result is out of
|
||||
ConvOvfI8, ///< As #ConvI8, but throws an exception if the result is out of
|
||||
///< range.
|
||||
|
||||
ConvOvfU1, ///< As #ConvU1, but throws an exception if the result is out of
|
||||
|
@ -306,7 +306,7 @@ enum ConvOpcode {
|
|||
|
||||
ConvOvfIUn, ///< As #ConvOvfI, but treats its input as an unsigned integer.
|
||||
|
||||
ConvOvfUUn, ///< As #ConvOvfIU, but treats its input as an unsigned integer.
|
||||
ConvOvfUUn, ///< As #ConvOvfU, but treats its input as an unsigned integer.
|
||||
|
||||
ConvRUn, ///< Converts its argument to a floating-point number in the
|
||||
///< runtime's internal representation, treating its input as an
|
||||
|
@ -711,7 +711,7 @@ SELECTANY const char OpcodeRemap[ReaderBaseNS::CEE_MACRO_END -
|
|||
ReaderBaseNS::ConvOvfU2, // CEE_CONV_OVF_U2,
|
||||
ReaderBaseNS::ConvOvfI4, // CEE_CONV_OVF_I4,
|
||||
ReaderBaseNS::ConvOvfU4, // CEE_CONV_OVF_U4,
|
||||
ReaderBaseNS::ConvOnvI8, // CEE_CONV_OVF_I8,
|
||||
ReaderBaseNS::ConvOvfI8, // CEE_CONV_OVF_I8,
|
||||
ReaderBaseNS::ConvOvfU8, // CEE_CONV_OVF_U8,
|
||||
-1, // CEE_UNUSED50,
|
||||
-1, // CEE_UNUSED18,
|
||||
|
|
|
@ -240,6 +240,7 @@ class GenIR : public ReaderBase {
|
|||
public:
|
||||
GenIR(LLILCJitContext *JitContext,
|
||||
std::map<CORINFO_CLASS_HANDLE, llvm::Type *> *ClassTypeMap,
|
||||
std::map<CORINFO_CLASS_HANDLE, llvm::Type *> *BoxedTypeMap,
|
||||
std::map<std::tuple<CorInfoType, CORINFO_CLASS_HANDLE, uint32_t>,
|
||||
llvm::Type *> *ArrayTypeMap,
|
||||
std::map<CORINFO_FIELD_HANDLE, uint32_t> *FieldIndexMap)
|
||||
|
@ -247,6 +248,7 @@ public:
|
|||
JitContext->Flags) {
|
||||
this->JitContext = JitContext;
|
||||
this->ClassTypeMap = ClassTypeMap;
|
||||
this->BoxedTypeMap = BoxedTypeMap;
|
||||
this->ArrayTypeMap = ArrayTypeMap;
|
||||
this->FieldIndexMap = FieldIndexMap;
|
||||
}
|
||||
|
@ -847,6 +849,13 @@ private:
|
|||
llvm::Type *getClassType(CORINFO_CLASS_HANDLE ClassHandle, bool IsRefClass,
|
||||
bool GetRefClassFields);
|
||||
|
||||
/// \brief Construct the LLVM type of the boxed representation of the given
|
||||
/// value type.
|
||||
///
|
||||
/// \param Class The handle to the value type's class.
|
||||
/// \returns The LLVM type of the boxed representation of the value type.
|
||||
llvm::Type *getBoxedType(CORINFO_CLASS_HANDLE Class);
|
||||
|
||||
/// Convert node to the desired type.
|
||||
/// May reinterpret, truncate, or extend as needed.
|
||||
/// \param Type Desired type
|
||||
|
@ -1168,6 +1177,7 @@ private:
|
|||
// insertion point parameters).
|
||||
llvm::IRBuilder<> *LLVMBuilder;
|
||||
std::map<CORINFO_CLASS_HANDLE, llvm::Type *> *ClassTypeMap;
|
||||
std::map<CORINFO_CLASS_HANDLE, llvm::Type *> *BoxedTypeMap;
|
||||
std::map<std::tuple<CorInfoType, CORINFO_CLASS_HANDLE, uint32_t>,
|
||||
llvm::Type *> *ArrayTypeMap;
|
||||
std::map<CORINFO_FIELD_HANDLE, uint32_t> *FieldIndexMap;
|
||||
|
|
|
@ -285,7 +285,8 @@ bool LLILCJit::readMethod(LLILCJitContext *JitContext) {
|
|||
|
||||
LLILCJitPerThreadState *PerThreadState = State.get();
|
||||
GenIR Reader(JitContext, &PerThreadState->ClassTypeMap,
|
||||
&PerThreadState->ArrayTypeMap, &PerThreadState->FieldIndexMap);
|
||||
&PerThreadState->BoxedTypeMap, &PerThreadState->ArrayTypeMap,
|
||||
&PerThreadState->FieldIndexMap);
|
||||
|
||||
std::string FuncName = JitContext->CurrentModule->getModuleIdentifier();
|
||||
|
||||
|
|
|
@ -269,18 +269,21 @@ void GenIR::readerPrePass(uint8_t *Buffer, uint32_t NumBytes) {
|
|||
ASSERTNR(UNREACHED);
|
||||
}
|
||||
|
||||
const uint32_t JitFlags = JitContext->Flags;
|
||||
|
||||
HasSecretParameter = (JitFlags & CORJIT_FLG_PUBLISH_SECRET_PARAM) != 0;
|
||||
|
||||
CORINFO_METHOD_HANDLE MethodHandle = JitContext->MethodInfo->ftn;
|
||||
Function = getFunction(MethodHandle, HasSecretParameter);
|
||||
|
||||
// Capture low-level info about the return type for use in Return.
|
||||
CORINFO_SIG_INFO Sig;
|
||||
getMethodSig(MethodHandle, &Sig);
|
||||
ReturnCorType = Sig.retType;
|
||||
|
||||
if ((ReturnCorType == CORINFO_TYPE_REFANY) ||
|
||||
(ReturnCorType == CORINFO_TYPE_VALUECLASS)) {
|
||||
throw NotYetImplementedException("Return refany or value class");
|
||||
}
|
||||
|
||||
const uint32_t JitFlags = JitContext->Flags;
|
||||
HasSecretParameter = (JitFlags & CORJIT_FLG_PUBLISH_SECRET_PARAM) != 0;
|
||||
Function = getFunction(MethodHandle, HasSecretParameter);
|
||||
EntryBlock = BasicBlock::Create(*JitContext->LLVMContext, "entry", Function);
|
||||
|
||||
LLVMBuilder = new IRBuilder<>(*this->JitContext->LLVMContext);
|
||||
|
@ -1329,6 +1332,72 @@ Type *GenIR::getClassType(CORINFO_CLASS_HANDLE ClassHandle, bool IsRefClass,
|
|||
return ResultTy;
|
||||
}
|
||||
|
||||
Type *GenIR::getBoxedType(CORINFO_CLASS_HANDLE Class) {
|
||||
assert(JitContext->JitInfo->isValueClass(Class));
|
||||
|
||||
// Check to see if the boxed version of this type has already been generated.
|
||||
auto MapElement = BoxedTypeMap->find(Class);
|
||||
if (MapElement != BoxedTypeMap->end()) {
|
||||
return MapElement->second;
|
||||
}
|
||||
|
||||
// Normalize the source type from Nullable<T> to T, if necessary.
|
||||
CORINFO_CLASS_HANDLE TypeToBox = getTypeForBox(Class);
|
||||
|
||||
CorInfoType CorType = ReaderBase::getClassType(TypeToBox);
|
||||
Type *ValueType = getType(CorType, TypeToBox);
|
||||
|
||||
// Treat the boxed type as a subclass of Object with a single field of the
|
||||
// source type.
|
||||
CORINFO_CLASS_HANDLE ObjectClass =
|
||||
getBuiltinClass(CorInfoClassId::CLASSID_SYSTEM_OBJECT);
|
||||
|
||||
const bool IsRefClass = true;
|
||||
const bool GetRefClassFields = true;
|
||||
Type *ObjectPtrType =
|
||||
getClassType(ObjectClass, IsRefClass, GetRefClassFields);
|
||||
StructType *ObjectType =
|
||||
cast<StructType>(ObjectPtrType->getPointerElementType());
|
||||
ArrayRef<Type *> ObjectFields = ObjectType->elements();
|
||||
|
||||
std::vector<Type *> Fields(ObjectFields.size() + 1);
|
||||
|
||||
int I = 0;
|
||||
for (auto F : ObjectFields) {
|
||||
Fields[I++] = F;
|
||||
}
|
||||
Fields[I] = ValueType;
|
||||
|
||||
LLVMContext &Context = *JitContext->LLVMContext;
|
||||
const bool IsPacked = true;
|
||||
Type *BoxedType;
|
||||
|
||||
std::string BoxedTypeName;
|
||||
StructType *TheStructType = dyn_cast<StructType>(ValueType);
|
||||
if (TheStructType != nullptr) {
|
||||
StringRef StructTypeName = TheStructType->getStructName();
|
||||
if (!StructTypeName.empty()) {
|
||||
BoxedTypeName = Twine("Boxed_", StructTypeName).str();
|
||||
} else {
|
||||
BoxedTypeName = "Boxed_AnonStruct";
|
||||
}
|
||||
}
|
||||
|
||||
if (BoxedTypeName.empty()) {
|
||||
assert(ValueType->isFloatTy() || ValueType->isDoubleTy() ||
|
||||
ValueType->isIntegerTy());
|
||||
BoxedTypeName = "Boxed_Primitive";
|
||||
}
|
||||
|
||||
BoxedType = StructType::create(Context, Fields, BoxedTypeName, IsPacked);
|
||||
BoxedType = getManagedPointerType(BoxedType);
|
||||
(*BoxedTypeMap)[TypeToBox] = BoxedType;
|
||||
if (Class != TypeToBox) {
|
||||
(*BoxedTypeMap)[Class] = BoxedType;
|
||||
}
|
||||
return BoxedType;
|
||||
}
|
||||
|
||||
// Obtain an LLVM function type from a method handle.
|
||||
FunctionType *GenIR::getFunctionType(CORINFO_METHOD_HANDLE Method,
|
||||
bool HasSecretParameter) {
|
||||
|
@ -2324,8 +2393,11 @@ IRNode *GenIR::binaryOp(ReaderBaseNS::BinaryOpcode Opcode, IRNode *Arg1,
|
|||
Instruction::BinaryOps Op = Triple[Opcode].Op.Opcode;
|
||||
|
||||
if ((Op == Instruction::BinaryOps::SDiv) ||
|
||||
(Op == Instruction::BinaryOps::UDiv)) {
|
||||
// Integer divide throws a DivideByZeroException on 0 denominator
|
||||
(Op == Instruction::BinaryOps::UDiv) ||
|
||||
(Op == Instruction::BinaryOps::SRem) ||
|
||||
(Op == Instruction::BinaryOps::URem)) {
|
||||
// Integer divide and remainder throw a DivideByZeroException
|
||||
// if the divisor is zero
|
||||
if (UseExplicitZeroDivideChecks) {
|
||||
Value *IsZero = LLVMBuilder->CreateIsNull(Arg2);
|
||||
genConditionalThrow(IsZero, CORINFO_HELP_THROWDIVZERO,
|
||||
|
@ -2686,8 +2758,9 @@ IRNode *GenIR::loadAtAddress(IRNode *Address, Type *Ty, CorInfoType CorType,
|
|||
ReaderAlignType AlignmentPrefix, bool IsVolatile,
|
||||
bool AddressMayBeNull) {
|
||||
if (Ty->isStructTy()) {
|
||||
return loadObj(ResolvedToken, Address, AlignmentPrefix, IsVolatile, true,
|
||||
AddressMayBeNull);
|
||||
bool IsFieldAccess = ResolvedToken->hField != nullptr;
|
||||
return loadObj(ResolvedToken, Address, AlignmentPrefix, IsVolatile,
|
||||
IsFieldAccess, AddressMayBeNull);
|
||||
} else {
|
||||
LoadInst *LoadInst = makeLoad(Address, IsVolatile, AddressMayBeNull);
|
||||
uint32_t Align = convertReaderAlignment(AlignmentPrefix);
|
||||
|
@ -2944,9 +3017,7 @@ IRNode *GenIR::addressOfValue(IRNode *Leaf) {
|
|||
}
|
||||
|
||||
IRNode *GenIR::makeBoxDstOperand(CORINFO_CLASS_HANDLE Class) {
|
||||
const bool IsRefClass = false;
|
||||
const bool GetRefClassFields = false;
|
||||
Type *Ty = getClassType(getTypeForBox(Class), IsRefClass, GetRefClassFields);
|
||||
Type *Ty = getBoxedType(Class);
|
||||
Value *Ptr = llvm::Constant::getNullValue(getManagedPointerType(Ty));
|
||||
return (IRNode *)Ptr;
|
||||
}
|
||||
|
@ -4715,7 +4786,7 @@ IRNode *GenIR::conditionalDerefAddress(IRNode *Address) {
|
|||
|
||||
// Merge the two addresses and return the result.
|
||||
PHINode *Result = mergeConditionalResults(ContinueBlock, Address, TestBlock,
|
||||
UpdatedAddress, ContinueBlock);
|
||||
UpdatedAddress, IndirectionBlock);
|
||||
|
||||
return (IRNode *)Result;
|
||||
}
|
||||
|
@ -5163,16 +5234,20 @@ IRNode *GenIR::castOp(CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *ObjRefNode,
|
|||
}
|
||||
}
|
||||
|
||||
Type *ResultType =
|
||||
getType(CorInfoType::CORINFO_TYPE_CLASS, ResolvedToken->hClass);
|
||||
IRNode *Dst = (IRNode *)Constant::getNullValue(ResultType);
|
||||
CORINFO_CLASS_HANDLE Class = ResolvedToken->hClass;
|
||||
Type *ResultType = nullptr;
|
||||
if (JitContext->JitInfo->isValueClass(Class)) {
|
||||
ResultType = getBoxedType(Class);
|
||||
} else {
|
||||
ResultType = getType(CORINFO_TYPE_CLASS, Class);
|
||||
}
|
||||
|
||||
// Generate the helper call or intrinsic
|
||||
bool IsVolatile = false;
|
||||
bool DoesNotInvokeStaticCtor = Optimize;
|
||||
return callHelper(HelperId, Dst, ClassHandleNode, ObjRefNode, nullptr,
|
||||
nullptr, Reader_AlignUnknown, IsVolatile,
|
||||
DoesNotInvokeStaticCtor);
|
||||
const bool IsVolatile = false;
|
||||
const bool DoesNotInvokeStaticCtor = Optimize;
|
||||
return callHelperImpl(HelperId, ResultType, ClassHandleNode, ObjRefNode,
|
||||
nullptr, nullptr, Reader_AlignUnknown, IsVolatile,
|
||||
DoesNotInvokeStaticCtor);
|
||||
}
|
||||
|
||||
// Override the cast class optimization
|
||||
|
|
Загрузка…
Ссылка в новой задаче