int main() { pid_t pid = fork(); if (pid == 0) { ChildFunction(); return 0; } else { ParentFunction(); } return 0; }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void IndirectCallPromotion::PromoteCallWithMultipleTargets(CallInstr* instr, CallSite* callSite, CallEdgeList& targetEdges, int promotedTargets, bool hasUnpromotedTargets) { // Split the block that contains the 'call' before it. // If the called functions return values this block will contain // a 'phi' that combines them. auto originalBlock = instr->ParentBlock(); auto& symbols = originalBlock->ParentFunction()->Symbols(); auto continuationName = BlockUtils::CreateUniqueName("#indir_prom_cont", symbols); auto continuationBlock = instr->ParentBlock()->SplitAt(instr, continuationName); // Any incoming 'phi' operand from the original block // is now incoming from 'continuationBlock'. for(int i = 0; i < continuationBlock->SuccessorCount(); i++) { BlockUtils::ReplacePhiOperandsBlock(continuationBlock->SuccessorAt(i), originalBlock, continuationBlock); } // For each potential target we create a test block // and a block that contains the actual call. For the first target // the test block is not created (the block where the original call // was found is used) and for the last one too, but only if we have // no unpromoted targets. If we have we create an "else" block // where we move the original call (otherwise the call is deleted). BlockList testBlocks; BlockList callBlocks; CallList createdCalls; Block* previousBlock; // Used to insert the blocks in order. // Remove the 'goto' to 'continuationBlock'. originalBlock->RemoveInstruction(originalBlock->LastInstruction()); for(int i = 0; i < targetEdges.Count(); i++) { DebugValidator::IsFalse(targetEdges[i].Callee()->IsNodeGroup()); auto targetCallNode = static_cast<CallNode*>(targetEdges[i].Callee()); auto targetFunctionRef = targetCallNode->GetFunctionReference(); // Create the test block. Block* testBlock = nullptr; auto targetComparison = CreateTargetComparison(instr->TargetOp(), targetFunctionRef); if(i == 0) { // The first comparison is inserted in the original block. testBlock = originalBlock; } else if((i < (targetEdges.Count() - 1)) || hasUnpromotedTargets) { // Create a new block for the other comparisons. testBlock = CreateTestBlock(symbols, previousBlock); } if(testBlock) { testBlock->InsertInstruction(targetComparison); testBlocks.Add(testBlock); previousBlock = testBlock; } // Create the call block. Block* callBlock = CreateCallBlock(symbols, previousBlock); auto callInstr = CreateTargetCall(targetFunctionRef, instr); createdCalls.Add(callInstr); callBlock->InsertInstruction(callInstr); callBlock->InsertInstruction(CreateGoto(continuationBlock)); callBlocks.Add(callBlock); previousBlock = callBlock; } // If there are calls to unpromoted targets (or to Unknown) // create a block where the original 'call' is cloned. // This block is executed if none of the known targets match. if(hasUnpromotedTargets) { auto unknownBlock = CreateCallBlock(symbols, previousBlock); callBlocks.Add(unknownBlock); auto callInstr = CreateTargetCall(instr->TargetOp(), instr); createdCalls.Add(callInstr); unknownBlock->InsertInstruction(callInstr); unknownBlock->InsertInstruction(CreateGoto(continuationBlock)); } // Connect the generated blocks so that the targets // are tested in a linear order, most frequently called first. ConnectGeneratedBlocks(testBlocks, callBlocks); // Create a 'phi' in the continuation block that merges // the values returned by each of the created calls. MergeReturnedValues(callBlocks, continuationBlock, instr); // Create a new call site for each new call // and delete the one associated with the original one. UpdateCallGraph(createdCalls, instr); // The original 'call' is no longer needed. instr->RemoveFromBlock(true /* free */); }