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); }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 */); }
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); }