зеркало из https://github.com/dotnet/llilc.git
Merge pull request #486 from JosephTremoulet/MovePointBlocks
Reposition first-pass point blocks
This commit is contained in:
Коммит
158277621a
|
@ -3054,7 +3054,16 @@ public:
|
|||
uint32_t Element) = 0;
|
||||
virtual void insertEHAnnotationNode(IRNode *InsertionPointNode,
|
||||
IRNode *Node) = 0;
|
||||
/// Construct a new FlowGraphNode
|
||||
///
|
||||
/// \param TargetOffset The start MSIL offset for the new node
|
||||
/// \param PreviousNode The new node will follow \p PreviousNode in the
|
||||
/// node list if specified (may be nullptr, in which case
|
||||
/// the new node will simply be appended)
|
||||
/// \param Region EHRegion to apply to the new node
|
||||
/// \returns The new FlowGraphNode
|
||||
virtual FlowGraphNode *makeFlowGraphNode(uint32_t TargetOffset,
|
||||
FlowGraphNode *PreviousNode,
|
||||
EHRegion *Region) = 0;
|
||||
virtual void markAsEHLabel(IRNode *LabelNode) = 0;
|
||||
virtual IRNode *makeTryEndNode(void) = 0;
|
||||
|
|
|
@ -636,6 +636,7 @@ public:
|
|||
throw NotYetImplementedException("insertEHAnnotationNode");
|
||||
};
|
||||
FlowGraphNode *makeFlowGraphNode(uint32_t TargetOffset,
|
||||
FlowGraphNode *PreviousNode,
|
||||
EHRegion *Region) override;
|
||||
void markAsEHLabel(IRNode *LabelNode) override {
|
||||
throw NotYetImplementedException("markAsEHLabel");
|
||||
|
@ -1005,6 +1006,18 @@ private:
|
|||
/// \returns The newly-created successor block
|
||||
llvm::BasicBlock *splitCurrentBlock(llvm::TerminatorInst **Goto = nullptr);
|
||||
|
||||
/// \brief Move point blocks preceding \p OldBlock to just before \p NewBlock
|
||||
///
|
||||
/// Point blocks created during the first pass flow-graph construction are
|
||||
/// inserted before temp blocks created for their point. Then they are moved
|
||||
/// to the appropriate spot when branches to temp blocks are being rewritten.
|
||||
/// This is the routine invoked during branch rewriting to move them.
|
||||
///
|
||||
/// \param OldBlock Temporary block whose associated point blocks are to be
|
||||
/// fixed up
|
||||
/// \param NewBlock "Real" block that begins at the point in question
|
||||
void movePointBlocks(llvm::BasicBlock *OldBlock, llvm::BasicBlock *NewBlock);
|
||||
|
||||
/// Insert one instruction in place of another.
|
||||
///
|
||||
/// \param OldInstruction The instruction to be removed. Must have no uses.
|
||||
|
@ -1305,6 +1318,7 @@ private:
|
|||
llvm::BasicBlock *UnreachableContinuationBlock;
|
||||
bool KeepGenericContextAlive;
|
||||
bool NeedsSecurityObject;
|
||||
bool DoneBuildingFlowGraph;
|
||||
llvm::BasicBlock *EntryBlock;
|
||||
llvm::Instruction *TempInsertionPoint;
|
||||
IRNode *MethodSyncHandle; ///< If the method is synchronized, this is
|
||||
|
|
|
@ -1919,7 +1919,7 @@ FlowGraphNode *ReaderBase::buildFlowGraph(FlowGraphNode **FgTail) {
|
|||
// fgAddNodeMSILOffset
|
||||
//
|
||||
// The FlowGraphNodeOffsetList acts as a work list. Each time a
|
||||
// branch is added to the the IR stream a temporary target nodeis
|
||||
// branch is added to the the IR stream a temporary target node is
|
||||
// added to the FlowGraphNodeOffsetList. After all the branches have
|
||||
// been added the worklist is traversed and each temporary node is
|
||||
// replaced with a real one.
|
||||
|
@ -1969,7 +1969,7 @@ FlowGraphNodeOffsetList *ReaderBase::fgAddNodeMSILOffset(
|
|||
NewElement->setOffset(TargetOffset);
|
||||
|
||||
if (*Node == nullptr) {
|
||||
*Node = makeFlowGraphNode(TargetOffset,
|
||||
*Node = makeFlowGraphNode(TargetOffset, nullptr,
|
||||
fgGetRegionFromMSILOffset(TargetOffset));
|
||||
}
|
||||
NewElement->setNode(*Node);
|
||||
|
@ -2292,17 +2292,11 @@ ReaderBase::fgReplaceBranchTarget(uint32_t Offset,
|
|||
Start = fgNodeGetStartMSILOffset(Block);
|
||||
End = fgNodeGetEndMSILOffset(Block);
|
||||
|
||||
// There are blocks at the top of the flow graph that both Start and
|
||||
// End at offset 0. These don't correspond to MSIL blocks, though,
|
||||
// so we never want to insert labels in those blocks.
|
||||
// Note that this routine is used to insert labels *before* EH regions
|
||||
// are applied, and that branch targets can only be valid
|
||||
// MSIL offsets, which each have distinct instructions and hence
|
||||
// have non-zero block sizes. Another special case is the final
|
||||
// block, which may have a label but contain no MSIL due, for example,
|
||||
// to an Endfinally instruction.
|
||||
if ((Offset >= Start && Offset < End) ||
|
||||
(Offset == Start && Offset == End && !NextBlock)) {
|
||||
// Find the MSIL block corresponding to the branch target. Note that the
|
||||
// test used here precludes selecting a point block as the branch target;
|
||||
// point blocks created in the first pass are only reachable by branches
|
||||
// explicitly made to target them in the first pass.
|
||||
if (Offset >= Start && Offset < End) {
|
||||
|
||||
// Branch targets must be at the begining of basic blocks. Thus,
|
||||
// if this branch target does not Start the block we must split
|
||||
|
@ -2899,11 +2893,6 @@ void ReaderBase::fgBuildPhase1(FlowGraphNode *Block, uint8_t *ILInput,
|
|||
StackOffset = 0;
|
||||
}
|
||||
|
||||
NodeOffsetListArraySize =
|
||||
(ILInputSize / FLOW_GRAPH_NODE_LIST_ARRAY_STRIDE) + 1;
|
||||
NodeOffsetListArray = (FlowGraphNodeOffsetList **)getTempMemory(
|
||||
sizeof(FlowGraphNodeOffsetList *) * NodeOffsetListArraySize);
|
||||
|
||||
// init stuff prior to loop
|
||||
IsShortInstr = false;
|
||||
IsConditional = false;
|
||||
|
@ -3127,7 +3116,7 @@ void ReaderBase::fgBuildPhase1(FlowGraphNode *Block, uint8_t *ILInput,
|
|||
verifyReturnFlow(CurrentOffset);
|
||||
fgNodeSetEndMSILOffset(Block, NextOffset);
|
||||
if (NextOffset < ILInputSize) {
|
||||
Block = makeFlowGraphNode(NextOffset, nullptr);
|
||||
Block = makeFlowGraphNode(NextOffset, Block, nullptr);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -7894,6 +7883,13 @@ void ReaderBase::msilToIR(void) {
|
|||
FlowGraphNodeWorkList *Worklist;
|
||||
FlowGraphNode *FgHead, *FgTail;
|
||||
|
||||
// Initialize the NodeOffsetListArray so it can be used even in the
|
||||
// reader pre-pass
|
||||
NodeOffsetListArraySize =
|
||||
(MethodInfo->ILCodeSize / FLOW_GRAPH_NODE_LIST_ARRAY_STRIDE) + 1;
|
||||
NodeOffsetListArray = (FlowGraphNodeOffsetList **)getTempMemory(
|
||||
sizeof(FlowGraphNodeOffsetList *) * NodeOffsetListArraySize);
|
||||
|
||||
// Compiler dependent pre-pass
|
||||
readerPrePass(MethodInfo->ILCode, MethodInfo->ILCodeSize);
|
||||
|
||||
|
@ -8009,15 +8005,8 @@ void ReaderBase::msilToIR(void) {
|
|||
uint32_t StartOffset = fgNodeGetStartMSILOffset(Block);
|
||||
uint32_t EndOffset = fgNodeGetEndMSILOffset(Block);
|
||||
if (fgNodeIsVisited(Block)) {
|
||||
if (LastInsertedInOrderBlockEndOffset <= StartOffset) {
|
||||
LastInsertedInOrderBlockEndOffset = EndOffset;
|
||||
} else {
|
||||
// This is a block that's not in MSIL offset order.
|
||||
// Assert that this block doesn't propagate operand stack and
|
||||
// doesn't have any msil and, therefore, can be processed out-of-order.
|
||||
ASSERTNR(!fgNodePropagatesOperandStack(Block));
|
||||
ASSERTNR(StartOffset == EndOffset);
|
||||
}
|
||||
assert(LastInsertedInOrderBlockEndOffset <= StartOffset);
|
||||
LastInsertedInOrderBlockEndOffset = EndOffset;
|
||||
FlowGraphMSILOffsetOrder.push_back(Block);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -319,6 +319,7 @@ void GenIR::readerPrePass(uint8_t *Buffer, uint32_t NumBytes) {
|
|||
LocalVarCorTypes.resize(NumLocals);
|
||||
KeepGenericContextAlive = false;
|
||||
NeedsSecurityObject = false;
|
||||
DoneBuildingFlowGraph = false;
|
||||
UnreachableContinuationBlock = nullptr;
|
||||
|
||||
initParamsAndAutos(MethodSignature);
|
||||
|
@ -1893,9 +1894,12 @@ FlowGraphNode *GenIR::fgGetTailBlock() {
|
|||
}
|
||||
|
||||
FlowGraphNode *GenIR::makeFlowGraphNode(uint32_t TargetOffset,
|
||||
FlowGraphNode *PreviousNode,
|
||||
EHRegion *Region) {
|
||||
BasicBlock *NextBlock =
|
||||
(PreviousNode == nullptr ? nullptr : PreviousNode->getNextNode());
|
||||
FlowGraphNode *Node = (FlowGraphNode *)BasicBlock::Create(
|
||||
*JitContext->LLVMContext, "", Function);
|
||||
*JitContext->LLVMContext, "", Function, NextBlock);
|
||||
fgNodeSetStartMSILOffset(Node, TargetOffset);
|
||||
return Node;
|
||||
}
|
||||
|
@ -2044,21 +2048,14 @@ IRNode *GenIR::fgMakeEndFinally(IRNode *InsertNode, EHRegion *FinallyRegion,
|
|||
BasicBlock *TargetBlock = Switch->getParent();
|
||||
if (TargetBlock == nullptr) {
|
||||
// This is the first endfinally for this finally. Generate a block to
|
||||
// hold the switch.
|
||||
TargetBlock = BasicBlock::Create(*JitContext->LLVMContext, "endfinally",
|
||||
Function, Block->getNextNode());
|
||||
// hold the switch. Use the finally end offset as the switch block's
|
||||
// begin/end.
|
||||
TargetBlock = createPointBlock(FinallyRegion->EndMsilOffset, "endfinally");
|
||||
LLVMBuilder->SetInsertPoint(TargetBlock);
|
||||
|
||||
// Insert the load of the selector variable and the switch.
|
||||
LLVMBuilder->Insert((LoadInst *)Switch->getCondition());
|
||||
LLVMBuilder->Insert(Switch);
|
||||
|
||||
// Use the finally end offset as the switch block's begin/end.
|
||||
FlowGraphNode *TargetNode = (FlowGraphNode *)TargetBlock;
|
||||
uint32_t EndOffset = FinallyRegion->EndMsilOffset;
|
||||
fgNodeSetStartMSILOffset(TargetNode, EndOffset);
|
||||
fgNodeSetEndMSILOffset(TargetNode, EndOffset);
|
||||
fgNodeSetPropagatesOperandStack(TargetNode, false);
|
||||
}
|
||||
|
||||
// Generate and return branch to the block that holds the switch
|
||||
|
@ -2096,9 +2093,25 @@ IRNode *GenIR::fgNodeGetEndInsertIRNode(FlowGraphNode *FgNode) {
|
|||
return (IRNode *)InsertInst;
|
||||
}
|
||||
|
||||
void GenIR::movePointBlocks(BasicBlock *OldBlock, BasicBlock *NewBlock) {
|
||||
BasicBlock *MoveBeforeBlock = NewBlock;
|
||||
uint32_t PointOffset = fgNodeGetStartMSILOffset((FlowGraphNode *)OldBlock);
|
||||
BasicBlock *PointBlock = OldBlock->getPrevNode();
|
||||
BasicBlock *PrevBlock = PointBlock->getPrevNode();
|
||||
while (
|
||||
(PointOffset == fgNodeGetStartMSILOffset((FlowGraphNode *)PointBlock)) &&
|
||||
(PointOffset == fgNodeGetEndMSILOffset((FlowGraphNode *)PointBlock))) {
|
||||
PointBlock->moveBefore(MoveBeforeBlock);
|
||||
MoveBeforeBlock = PointBlock;
|
||||
PointBlock = PrevBlock;
|
||||
PrevBlock = PrevBlock->getPrevNode();
|
||||
}
|
||||
}
|
||||
|
||||
void GenIR::replaceFlowGraphNodeUses(FlowGraphNode *OldNode,
|
||||
FlowGraphNode *NewNode) {
|
||||
BasicBlock *OldBlock = (BasicBlock *)OldNode;
|
||||
movePointBlocks(OldBlock, NewNode);
|
||||
OldBlock->replaceAllUsesWith(NewNode);
|
||||
OldBlock->eraseFromParent();
|
||||
}
|
||||
|
@ -2219,7 +2232,7 @@ FlowGraphNode *GenIR::fgNodeGetNext(FlowGraphNode *FgNode) {
|
|||
|
||||
FlowGraphNode *GenIR::fgPrePhase(FlowGraphNode *Fg) { return FirstMSILBlock; }
|
||||
|
||||
void GenIR::fgPostPhase() { return; }
|
||||
void GenIR::fgPostPhase() { DoneBuildingFlowGraph = true; }
|
||||
|
||||
void GenIR::fgAddLabelToBranchList(IRNode *LabelNode, IRNode *BranchNode) {
|
||||
return;
|
||||
|
@ -4664,7 +4677,7 @@ uint32_t GenIR::updateLeaveOffset(EHRegion *Region, uint32_t LeaveOffset,
|
|||
// First finally for this function; generate an unreachable block
|
||||
// that can be used as the default switch target.
|
||||
UnreachableContinuationBlock =
|
||||
BasicBlock::Create(Context, "NullDefault", Function);
|
||||
createPointBlock(MethodInfo->ILCodeSize, "NullDefault");
|
||||
new UnreachableInst(Context, UnreachableContinuationBlock);
|
||||
fgNodeSetPropagatesOperandStack(
|
||||
(FlowGraphNode *)UnreachableContinuationBlock, false);
|
||||
|
@ -4850,6 +4863,22 @@ BasicBlock *GenIR::createPointBlock(uint32_t PointOffset,
|
|||
// predecessor.
|
||||
fgNodeSetPropagatesOperandStack(PointFlowGraphNode, false);
|
||||
|
||||
if (!DoneBuildingFlowGraph) {
|
||||
// Position this block in the list so that it will get moved to its point
|
||||
// at the end of flow-graph construction.
|
||||
if (PointOffset == MethodInfo->ILCodeSize) {
|
||||
// The point is the end of the function, which is already where this
|
||||
// block is.
|
||||
} else {
|
||||
// Request a split at PointOffset, and move this block before the temp
|
||||
// target so it will get moved after the split is created (in
|
||||
// movePointBlocks).
|
||||
FlowGraphNode *Next = nullptr;
|
||||
fgAddNodeMSILOffset(&Next, PointOffset);
|
||||
Block->moveBefore(Next);
|
||||
}
|
||||
}
|
||||
|
||||
return Block;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче