Beispiel #1
0
globle int FunctionCall(
  char *name,
  char *args,
  DATA_OBJECT *result)
  {
   FUNCTION_REFERENCE theReference;

   /*=======================================*/
   /* Call the function if it can be found. */
   /*=======================================*/

   if (GetFunctionReference(name,&theReference))
     { return(FunctionCall2(&theReference,args,result)); }

   /*=========================================================*/
   /* Otherwise signal an error if a deffunction, defgeneric, */
   /* or user defined function doesn't exist that matches     */
   /* the specified function name.                            */
   /*=========================================================*/

   PrintErrorID("EVALUATN",2,FALSE);
   PrintRouter(WERROR,"No function, generic function or deffunction of name ");
   PrintRouter(WERROR,name);
   PrintRouter(WERROR," exists for external call.\n");
   return(TRUE);
  }
Beispiel #2
0
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    void Print(CallGraph* callGraph, Unit* unit) {
        // Print the external and unknown nodes.
        NewNode(ExternalCallNode::GetExternalNode(), "EXTERNAL", 
                COLOR_LIGHT_PINK, SHAPE_RECT);
        NewNode(UnknownCallNode::GetUnknownNode(), "UNKNOWN", 
                COLOR_LIGHT_GREEN, SHAPE_RECT);

        // Print the nodes for each function, then create the links.
        for(auto funct = unit->Functions().First(); funct; funct = funct->Next) {
            auto functionRef = GetFunctionReference(funct->Value, unit);
            auto node = callGraph->GetNode(functionRef);
            NewNode(node, *funct->Value->Name(), COLOR_LIGHT_BLUE, SHAPE_TRAPEZIUM);

            node->ForEachCallSite([this](CallSite* site) -> bool {
                string name = string::Format(L"%d", site->GetCallId());
                NewNode(site, name, COLOR_LIGHT_GREY, SHAPE_ELLIPSE);
                return true;
            });
        }

        auto& nodeGroups = callGraph->GetCallNodeGroups();

        for(int i = 0; i < nodeGroups.Count(); i++) {
            auto nodeGroup = nodeGroups[i];
            string name = string::Format(L"Group: %d", nodeGroup->NodeCount());
            NewNode(nodeGroup, name, COLOR_YELLOW, SHAPE_DIAMOND);

            nodeGroup->ForEachNode([this, nodeGroup](CallNodeBase* node) -> bool {
                Link(nodeGroup, node);
                return true;
            });
        }

        for(auto funct = unit->Functions().First(); funct; funct = funct->Next) {
            auto functionRef = GetFunctionReference(funct->Value, unit);
            auto node = callGraph->GetNode(functionRef);
            CreateLinks(node);
        }

        CreateLinks(ExternalCallNode::GetExternalNode());
        CreateLinks(UnknownCallNode::GetUnknownNode());
        Close();
    }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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 */);
}
Beispiel #4
0
globle void FuncallFunction(
    void *theEnv,
    DATA_OBJECT *returnValue)
{
    int argCount, i, j;
    DATA_OBJECT theValue;
    FUNCTION_REFERENCE theReference;
    char *name;
    struct multifield *theMultifield;
    struct expr *lastAdd = NULL, *nextAdd, *multiAdd;

    /*==================================*/
    /* Set up the default return value. */
    /*==================================*/

    SetpType(returnValue,SYMBOL);
    SetpValue(returnValue,EnvFalseSymbol(theEnv));

    /*=================================================*/
    /* The funcall function has at least one argument: */
    /* the name of the function being called.          */
    /*=================================================*/

    if ((argCount = EnvArgCountCheck(theEnv,"funcall",AT_LEAST,1)) == -1) return;

    /*============================================*/
    /* Get the name of the function to be called. */
    /*============================================*/

    if (EnvArgTypeCheck(theEnv,"funcall",1,SYMBOL_OR_STRING,&theValue) == FALSE)
    {
        return;
    }

    /*====================*/
    /* Find the function. */
    /*====================*/

    name = DOToString(theValue);
    if (! GetFunctionReference(theEnv,name,&theReference))
    {
        ExpectedTypeError1(theEnv,"funcall",1,"function, deffunction, or generic function name");
        return;
    }

    ExpressionInstall(theEnv,&theReference);

    /*======================================*/
    /* Add the arguments to the expression. */
    /*======================================*/

    for (i = 2; i <= argCount; i++)
    {
        EnvRtnUnknown(theEnv,i,&theValue);
        if (GetEvaluationError(theEnv))
        {
            ExpressionDeinstall(theEnv,&theReference);
            return;
        }

        switch(GetType(theValue))
        {
        case MULTIFIELD:
            nextAdd = GenConstant(theEnv,FCALL,(void *) FindFunction(theEnv,"create$"));

            if (lastAdd == NULL)
            {
                theReference.argList = nextAdd;
            }
            else
            {
                lastAdd->nextArg = nextAdd;
            }
            lastAdd = nextAdd;

            multiAdd = NULL;
            theMultifield = (struct multifield *) GetValue(theValue);
            for (j = GetDOBegin(theValue); j <= GetDOEnd(theValue); j++)
            {
                nextAdd = GenConstant(theEnv,GetMFType(theMultifield,j),GetMFValue(theMultifield,j));
                if (multiAdd == NULL)
                {
                    lastAdd->argList = nextAdd;
                }
                else
                {
                    multiAdd->nextArg = nextAdd;
                }
                multiAdd = nextAdd;
            }

            ExpressionInstall(theEnv,lastAdd);
            break;

        default:
            nextAdd = GenConstant(theEnv,GetType(theValue),GetValue(theValue));
            if (lastAdd == NULL)
            {
                theReference.argList = nextAdd;
            }
            else
            {
                lastAdd->nextArg = nextAdd;
            }
            lastAdd = nextAdd;
            ExpressionInstall(theEnv,lastAdd);
            break;
        }
    }

    /*===========================================================*/
    /* Verify a deffunction has the correct number of arguments. */
    /*===========================================================*/

#if DEFFUNCTION_CONSTRUCT
    if (theReference.type == PCALL)
    {
        if (CheckDeffunctionCall(theEnv,theReference.value,CountArguments(theReference.argList)) == FALSE)
        {
            PrintErrorID(theEnv,"MISCFUN",4,FALSE);
            EnvPrintRouter(theEnv,WERROR,"Function funcall called with the wrong number of arguments for deffunction ");
            EnvPrintRouter(theEnv,WERROR,EnvGetDeffunctionName(theEnv,theReference.value));
            EnvPrintRouter(theEnv,WERROR,"\n");
            ExpressionDeinstall(theEnv,&theReference);
            ReturnExpression(theEnv,theReference.argList);
            return;
        }
    }
#endif

    /*======================*/
    /* Call the expression. */
    /*======================*/

    EvaluateExpression(theEnv,&theReference,returnValue);

    /*========================================*/
    /* Return the expression data structures. */
    /*========================================*/

    ExpressionDeinstall(theEnv,&theReference);
    ReturnExpression(theEnv,theReference.argList);
}