int main() {
  pid_t pid = fork();
  if (pid == 0) {
    ChildFunction();
    return 0;
  } else {
    ParentFunction();
  }
  return 0;
}
예제 #2
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 */);
}