Merge pull request #486 from JosephTremoulet/MovePointBlocks

Reposition first-pass point blocks
This commit is contained in:
Joseph Tremoulet 2015-04-22 16:48:29 -04:00
Родитель 5955b02d45 45dc713586
Коммит 158277621a
4 изменённых файлов: 82 добавлений и 41 удалений

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

@ -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;
}