Vuo  2.1.0
VuoCompilerNode.cc
Go to the documentation of this file.
1 
10 #include <sstream>
11 
14 #include "VuoCompilerException.hh"
18 #include "VuoCompilerIssue.hh"
19 #include "VuoCompilerNode.hh"
20 #include "VuoCompilerNodeClass.hh"
23 #include "VuoCompilerType.hh"
24 #include "VuoNode.hh"
25 #include "VuoNodeClass.hh"
26 #include "VuoPort.hh"
27 #include "VuoStringUtilities.hh"
28 #include "VuoType.hh"
29 
30 
35  : VuoBaseDetail<VuoNode>("VuoNode", baseNode)
36 {
37  getBase()->setCompiler(this);
38 
39  instanceData = NULL;
41  if (instanceDataClass)
42  instanceData = new VuoCompilerInstanceData(instanceDataClass);
43 
44  graphvizIdentifier = getGraphvizIdentifierPrefix();
45 
46  constantStrings = NULL;
47  indexInOrderedNodes = ULONG_MAX - 1;
48 }
49 
53 void VuoCompilerNode::setIndexInOrderedNodes(size_t indexInOrderedNodes)
54 {
55  this->indexInOrderedNodes = indexInOrderedNodes;
56 }
57 
62 {
63  return indexInOrderedNodes;
64 }
65 
70 {
71  this->constantStrings = constantStrings;
72 
73  vector<VuoPort *> inputPorts = getBase()->getInputPorts();
74  vector<VuoPort *> outputPorts = getBase()->getOutputPorts();
75  vector<VuoPort *> ports;
76  ports.insert(ports.end(), inputPorts.begin(), inputPorts.end());
77  ports.insert(ports.end(), outputPorts.begin(), outputPorts.end());
78  for (vector<VuoPort *>::iterator i = ports.begin(); i != ports.end(); ++i)
79  {
80  VuoCompilerPort *port = static_cast<VuoCompilerPort *>( (*i)->getCompiler() );
81  port->setConstantStringCache(constantStrings);
82  }
83 }
84 
89 {
90  return constantStrings->get(module, getIdentifier());
91 }
92 
99 Value * VuoCompilerNode::generateSubcompositionIdentifierValue(Module *module, BasicBlock *block, Value *compositionIdentifierValue)
100 {
101  vector<Value *> identifierParts;
102  identifierParts.push_back(compositionIdentifierValue);
103  identifierParts.push_back(constantStrings->get(module, "/" + getIdentifier()));
104  return VuoCompilerCodeGenUtilities::generateStringConcatenation(module, block, identifierParts, *constantStrings);
105 }
106 
110 Value * VuoCompilerNode::generateGetContext(Module *module, BasicBlock *block, Value *compositionStateValue)
111 {
112  return VuoCompilerCodeGenUtilities::generateGetNodeContext(module, block, compositionStateValue, indexInOrderedNodes);
113 }
114 
119 void VuoCompilerNode::generateAddMetadata(Module *module, BasicBlock *block, Value *compositionStateValue,
120  const vector<VuoCompilerType *> &orderedTypes,
121  Function *compositionCreateContextForNode,
122  Function *compositionSetPortValueFunction, Function *compositionGetPortValueFunction,
123  Function *compositionFireTriggerPortEventFunction, Function *compositionReleasePortDataFunction)
124 {
125  Function *subcompositionFunctionSrc = getBase()->getNodeClass()->getCompiler()->getCompositionAddNodeMetadataFunction();
126 
127  Value *nodeIdentifierValue = generateIdentifierValue(module);
128  VuoCompilerCodeGenUtilities::generateAddNodeMetadata(module, block, compositionStateValue, nodeIdentifierValue,
129  compositionCreateContextForNode, compositionSetPortValueFunction,
130  compositionGetPortValueFunction, compositionFireTriggerPortEventFunction,
131  compositionReleasePortDataFunction);
132 
133  vector<VuoPort *> inputPorts = getBase()->getInputPorts();
134  vector<VuoPort *> outputPorts = getBase()->getOutputPorts();
135  vector<VuoPort *> ports;
136  ports.insert(ports.end(), inputPorts.begin(), inputPorts.end());
137  ports.insert(ports.end(), outputPorts.begin(), outputPorts.end());
138  for (vector<VuoPort *>::iterator i = ports.begin(); i != ports.end(); ++i)
139  {
140  VuoCompilerPort *port = static_cast<VuoCompilerPort *>( (*i)->getCompiler() );
141 
142  Value *portIdentifierValue = constantStrings->get(module, port->getIdentifier());
143  Value *portNameValue = constantStrings->get(module, port->getBase()->getClass()->getName());
144 
145  size_t typeIndex;
146  string initialValue;
147 
148  VuoType *dataType = port->getDataVuoType();
149  if (dataType)
150  {
151  vector<VuoCompilerType *>::const_iterator typeIter = find(orderedTypes.begin(), orderedTypes.end(), dataType->getCompiler());
152  typeIndex = typeIter - orderedTypes.begin();
153 
154  VuoCompilerInputEventPort *inputEventPort = dynamic_cast<VuoCompilerInputEventPort *>(port);
155  initialValue = (inputEventPort ? inputEventPort->getData()->getInitialValue() : "");
156  }
157  else
158  {
159  typeIndex = orderedTypes.size();
160  }
161 
162  Value *initialValueValue = constantStrings->get(module, initialValue);
163 
164  VuoCompilerCodeGenUtilities::generateAddPortMetadata(module, block, compositionStateValue, portIdentifierValue,
165  portNameValue, typeIndex, initialValueValue);
166  }
167 
168  if (subcompositionFunctionSrc)
169  {
170  Value *runtimeStateValue = VuoCompilerCodeGenUtilities::generateGetCompositionStateRuntimeState(module, block, compositionStateValue);
171  Value *compositionIdentifierValue = VuoCompilerCodeGenUtilities::generateGetCompositionStateCompositionIdentifier(module, block, compositionStateValue);
172  Value *subcompositionIdentifierValue = generateSubcompositionIdentifierValue(module, block, compositionIdentifierValue);
173  Value *subcompositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, runtimeStateValue, subcompositionIdentifierValue);
174 
175  Function *subcompositionFunctionDst = VuoCompilerModule::declareFunctionInModule(module, subcompositionFunctionSrc);
176  Value *arg = VuoCompilerCodeGenUtilities::convertArgumentToParameterType(subcompositionStateValue, subcompositionFunctionDst, 0, NULL, module, block);
177  CallInst::Create(subcompositionFunctionDst, arg, "", block);
178 
179  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, subcompositionStateValue);
180  VuoCompilerCodeGenUtilities::generateFreeCall(module, block, subcompositionIdentifierValue);
181  }
182 }
183 
187 Value * VuoCompilerNode::generateCreateContext(Module *module, BasicBlock *block)
188 {
189  // Create the node context.
190 
191  bool isSubcomposition = getBase()->getNodeClass()->getCompiler()->isSubcomposition();
192  unsigned long publishedOutputPortCount = (isSubcomposition ?
194 
195  Value * nodeContextValue = VuoCompilerCodeGenUtilities::generateCreateNodeContext(module, block, instanceData, isSubcomposition, publishedOutputPortCount);
196 
197  // Create each port's context.
198 
199  vector<VuoPort *> inputPorts = getBase()->getInputPorts();
200  vector<VuoPort *> outputPorts = getBase()->getOutputPorts();
201  vector<VuoPort *> ports;
202  ports.insert(ports.end(), inputPorts.begin(), inputPorts.end());
203  ports.insert(ports.end(), outputPorts.begin(), outputPorts.end());
204  vector<Value *> portContextValues;
205  for (vector<VuoPort *>::iterator i = ports.begin(); i != ports.end(); ++i)
206  {
207  VuoCompilerPort *port = static_cast<VuoCompilerPort *>( (*i)->getCompiler() );
208 
209  Value *portContextValue = port->generateCreatePortContext(module, block);
210  portContextValues.push_back(portContextValue);
211  }
212 
213  VuoCompilerCodeGenUtilities::generateSetNodeContextPortContexts(module, block, nodeContextValue, portContextValues);
214 
215  return nodeContextValue;
216 }
217 
230 void VuoCompilerNode::generateEventFunctionCall(Module *module, Function *function, BasicBlock *&currentBlock,
231  Value *compositionStateValue)
232 {
233  Function *functionSrc = getBase()->getNodeClass()->getCompiler()->getEventFunction();
234 
235  Value *nodeContextValue = generateGetContext(module, currentBlock, compositionStateValue);
236 
237  map<VuoCompilerEventPort *, Value *> portContextForEventPort;
238  vector<VuoPort *> inputPorts = getBase()->getInputPorts();
239  vector<VuoPort *> outputPorts = getBase()->getOutputPorts();
240  vector<VuoPort *> ports;
241  ports.insert(ports.end(), inputPorts.begin(), inputPorts.end());
242  ports.insert(ports.end(), outputPorts.begin(), outputPorts.end());
243  for (vector<VuoPort *>::iterator i = ports.begin(); i != ports.end(); ++i)
244  {
245  VuoCompilerEventPort *eventPort = dynamic_cast<VuoCompilerEventPort *>((*i)->getCompiler());
246  if (eventPort)
247  portContextForEventPort[eventPort] = eventPort->generateGetPortContext(module, currentBlock, nodeContextValue);
248  }
249 
250  generateFunctionCall(functionSrc, module, currentBlock, compositionStateValue, nodeContextValue, portContextForEventPort);
251 
252  // The output port should transmit an event if any non-blocking input port received the event.
253  // The output port should not transmit an event if no non-blocking or door input ports received the event.
254  // Otherwise, the output port's event transmission is handled by the node class implementation.
255 
256  vector<VuoPort *> nonBlockingInputPorts;
257  vector<VuoPort *> doorInputPorts;
258  for (vector<VuoPort *>::iterator i = inputPorts.begin(); i != inputPorts.end(); ++i)
259  {
260  VuoPortClass::EventBlocking eventBlocking = (*i)->getClass()->getEventBlocking();
261  if (eventBlocking == VuoPortClass::EventBlocking_None)
262  nonBlockingInputPorts.push_back(*i);
263  else if (eventBlocking == VuoPortClass::EventBlocking_Door)
264  doorInputPorts.push_back(*i);
265  }
266 
267  Value *eventHitNonBlockingInputPort = generateReceivedEventCondition(module, currentBlock, nodeContextValue, nonBlockingInputPorts,
268  portContextForEventPort);
269  Value *transmitForAllOutputPorts = eventHitNonBlockingInputPort;
270 
271  BasicBlock *handleTransmissionBlock = NULL;
272  BasicBlock *nextBlock = NULL;
273  if (! doorInputPorts.empty())
274  {
275  handleTransmissionBlock = BasicBlock::Create(module->getContext(), "handleTransmission", function, 0);
276  nextBlock = BasicBlock::Create(module->getContext(), "next", function, 0);
277 
278  Value *eventHitDoorInputPort = generateReceivedEventCondition(module, currentBlock, nodeContextValue, doorInputPorts,
279  portContextForEventPort);
280 
281  Value *blockForAllOutputPorts = BinaryOperator::Create(Instruction::And,
282  BinaryOperator::CreateNot(eventHitNonBlockingInputPort, "", currentBlock),
283  BinaryOperator::CreateNot(eventHitDoorInputPort, "", currentBlock),
284  "", currentBlock);
285  Value *handleTransmission = BinaryOperator::Create(Instruction::Or, transmitForAllOutputPorts, blockForAllOutputPorts, "", currentBlock);
286 
287  Constant *zeroValue = ConstantInt::get(transmitForAllOutputPorts->getType(), 0);
288  ICmpInst *handleTransmissionComparison = new ICmpInst(*currentBlock, ICmpInst::ICMP_NE, handleTransmission, zeroValue, "");
289  BranchInst::Create(handleTransmissionBlock, nextBlock, handleTransmissionComparison, currentBlock);
290  }
291  else
292  {
293  handleTransmissionBlock = currentBlock;
294  }
295 
296  for (vector<VuoPort *>::iterator i = outputPorts.begin(); i != outputPorts.end(); ++i)
297  {
298  VuoCompilerOutputEventPort *eventPort = dynamic_cast<VuoCompilerOutputEventPort *>((*i)->getCompiler());
299  if (eventPort)
300  {
301  Value *portContextValue = portContextForEventPort[eventPort];
302  eventPort->generateStoreEvent(module, handleTransmissionBlock, nodeContextValue, transmitForAllOutputPorts, portContextValue);
303  }
304  }
305 
306  if (! doorInputPorts.empty())
307  {
308  BranchInst::Create(nextBlock, handleTransmissionBlock);
309  currentBlock = nextBlock;
310  }
311 }
312 
324 void VuoCompilerNode::generateInitFunctionCall(Module *module, BasicBlock *block, Value *compositionStateValue)
325 {
326  Function *functionSrc = getBase()->getNodeClass()->getCompiler()->getInitFunction();
327 
328  Value *nodeContextValue = generateGetContext(module, block, compositionStateValue);
329  CallInst *call = generateFunctionCall(functionSrc, module, block, compositionStateValue, nodeContextValue);
330 
331  Type *instanceDataType = instanceData->getBase()->getClass()->getCompiler()->getType();
332  Value *callCasted = VuoCompilerCodeGenUtilities::generateTypeCast(module, block, call, instanceDataType);
333  instanceData->generateStore(module, block, nodeContextValue, callCasted);
334 
335  // Retain the instance data.
336  Value *instanceDataValue = instanceData->generateLoad(module, block, nodeContextValue);
337  VuoCompilerCodeGenUtilities::generateRetainCall(module, block, instanceDataValue);
338 }
339 
350 void VuoCompilerNode::generateFiniFunctionCall(Module *module, BasicBlock *block, Value *compositionStateValue)
351 {
352  Function *functionSrc = getBase()->getNodeClass()->getCompiler()->getFiniFunction();
353 
354  Value *nodeContextValue = generateGetContext(module, block, compositionStateValue);
355  if (functionSrc)
356  generateFunctionCall(functionSrc, module, block, compositionStateValue, nodeContextValue);
357 
358  // Release the instance data.
359  Value *instanceDataValue = instanceData->generateLoad(module, block, nodeContextValue);
360  VuoCompilerCodeGenUtilities::generateReleaseCall(module, block, instanceDataValue);
361 }
362 
371 void VuoCompilerNode::generateCallbackStartFunctionCall(Module *module, BasicBlock *block, Value *compositionStateValue)
372 {
373  Function *functionSrc = getBase()->getNodeClass()->getCompiler()->getCallbackStartFunction();
374  if (! functionSrc)
375  return;
376 
377  Value *nodeContextValue = generateGetContext(module, block, compositionStateValue);
378  generateFunctionCall(functionSrc, module, block, compositionStateValue, nodeContextValue);
379 }
380 
389 void VuoCompilerNode::generateCallbackUpdateFunctionCall(Module *module, BasicBlock *block, Value *compositionStateValue)
390 {
391  Function *functionSrc = getBase()->getNodeClass()->getCompiler()->getCallbackUpdateFunction();
392  if (! functionSrc)
393  return;
394 
395  Value *nodeContextValue = generateGetContext(module, block, compositionStateValue);
396  generateFunctionCall(functionSrc, module, block, compositionStateValue, nodeContextValue);
397 }
398 
407 void VuoCompilerNode::generateCallbackStopFunctionCall(Module *module, BasicBlock *block, Value *compositionStateValue)
408 {
409  Function *functionSrc = getBase()->getNodeClass()->getCompiler()->getCallbackStopFunction();
410  if (! functionSrc)
411  return;
412 
413  Value *nodeContextValue = generateGetContext(module, block, compositionStateValue);
414  generateFunctionCall(functionSrc, module, block, compositionStateValue, nodeContextValue);
415 }
416 
428 CallInst * VuoCompilerNode::generateFunctionCall(Function *functionSrc, Module *module, BasicBlock *block,
429  Value *compositionStateValue, Value *nodeContextValue,
430  const map<VuoCompilerEventPort *, Value *> &portContextForEventPort)
431 {
432  Function *functionDst = VuoCompilerModule::declareFunctionInModule(module, functionSrc);
433 
434  vector<Value *> args(functionDst->getFunctionType()->getNumParams());
435 
436  // Set up the argument for the composition state (if a subcomposition).
437  Value *subcompositionIdentifierValue = NULL;
438  Value *subcompositionStateValue = NULL;
439  if (getBase()->getNodeClass()->getCompiler()->isSubcomposition())
440  {
441  Value *runtimeStateValue = VuoCompilerCodeGenUtilities::generateGetCompositionStateRuntimeState(module, block, compositionStateValue);
442  Value *compositionIdentifierValue = VuoCompilerCodeGenUtilities::generateGetCompositionStateCompositionIdentifier(module, block, compositionStateValue);
443  subcompositionIdentifierValue = generateSubcompositionIdentifierValue(module, block, compositionIdentifierValue);
444  subcompositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, runtimeStateValue, subcompositionIdentifierValue);
445  args[0] = VuoCompilerCodeGenUtilities::convertArgumentToParameterType(subcompositionStateValue, functionDst, 0, NULL, module, block);
446  }
447 
448  // Set up the arguments for input ports.
449  vector<VuoPort *> inputPorts = getBase()->getInputPorts();
450  for (vector<VuoPort *>::iterator i = inputPorts.begin(); i != inputPorts.end(); ++i)
451  {
452  VuoCompilerInputEventPort *eventPort = dynamic_cast<VuoCompilerInputEventPort *>((*i)->getCompiler());
453 
454  VuoCompilerInputData *data = eventPort->getData();
455  bool isEventArgumentInFunction = isArgumentInFunction(eventPort, functionSrc);
456  bool isDataArgumentInFunction = data && isArgumentInFunction(data, functionSrc);
457 
458  if (isEventArgumentInFunction || isDataArgumentInFunction)
459  {
460  map<VuoCompilerEventPort *, Value *>::const_iterator iter = portContextForEventPort.find(eventPort);
461  Value *portContextValue = (iter != portContextForEventPort.end() ?
462  iter->second :
463  eventPort->generateGetPortContext(module, block, nodeContextValue));
464 
465  if (isEventArgumentInFunction)
466  {
467  size_t index = getArgumentIndexInFunction(eventPort, functionSrc);
468  args[index] = eventPort->generateLoadEvent(module, block, nodeContextValue, portContextValue);
469  }
470 
471  if (isDataArgumentInFunction)
472  {
473  size_t index = getArgumentIndexInFunction(data, functionSrc);
474  Value *arg = eventPort->generateLoadData(module, block, nodeContextValue, portContextValue);
475  Value *secondArg = NULL;
476 
477  // If we're calling a node function for a subcomposition, and the parameter is a struct that
478  // would normally be passed "byval", instead generate code equivalent to the "byval" semantics:
479  // Allocate a stack variable, copy the struct into it, and pass the variable's address as
480  // the argument to the node function.
481  //
482  // This is a workaround for a bug where LLVM would sometimes give the node function body
483  // an invalid value for a "byval" struct argument. https://b33p.net/kosada/node/11386
484  if (getBase()->getNodeClass()->getCompiler()->isSubcomposition() &&
485  arg->getType()->isStructTy() &&
486  eventPort->getDataVuoType()->getCompiler()->getFunctionParameterAttributes().hasAttrSomewhere(Attribute::ByVal))
487  {
488  Value *argAsPointer = VuoCompilerCodeGenUtilities::generatePointerToValue(block, arg);
489  arg = new BitCastInst(argAsPointer, functionSrc->getFunctionType()->getParamType(index), "", block);
490  }
491  else
492  {
493  bool isLoweredToTwoParameters = static_cast<VuoCompilerInputDataClass *>(data->getBase()->getClass()->getCompiler())->isLoweredToTwoParameters();
494  Value **secondArgIfNeeded = (isLoweredToTwoParameters ? &secondArg : NULL);
495  arg = VuoCompilerCodeGenUtilities::convertArgumentToParameterType(arg, functionDst, index, secondArgIfNeeded, module, block);
496  if (!arg)
497  {
498  VUserLog("Warning: Couldn't convert argument for input port '%s' of function %s; not generating call.",
499  (*i)->getClass()->getName().c_str(),
500  functionDst->getName().str().c_str());
501  return nullptr;
502  }
503  }
504 
505  args[index] = arg;
506  if (secondArg)
507  args[index + 1] = secondArg;
508  }
509  }
510  }
511 
512  // Set up the arguments for output ports.
513  vector<VuoPort *> outputPorts = getBase()->getOutputPorts();
514  map<VuoCompilerOutputEventPort *, Value *> outputPortDataVariables;
515  map<VuoCompilerOutputEventPort *, AllocaInst *> outputPortEventVariables;
516  for (vector<VuoPort *>::iterator i = outputPorts.begin(); i != outputPorts.end(); ++i)
517  {
518  VuoCompilerOutputEventPort *eventPort = dynamic_cast<VuoCompilerOutputEventPort *>((*i)->getCompiler());
519  if (eventPort)
520  {
521  VuoCompilerOutputData *data = eventPort->getData();
522  bool isEventArgumentInFunction = isArgumentInFunction(eventPort, functionSrc);
523  bool isDataArgumentInFunction = data && isArgumentInFunction(data, functionSrc);
524 
525  if (isEventArgumentInFunction)
526  {
527  size_t index = getArgumentIndexInFunction(eventPort, functionSrc);
528  PointerType *eventPointerType = static_cast<PointerType *>( functionDst->getFunctionType()->getParamType(index) );
529  AllocaInst *arg = new AllocaInst(eventPointerType->getElementType(), "", block);
530  new StoreInst(ConstantInt::get(eventPointerType->getElementType(), 0), arg, block);
531  outputPortEventVariables[eventPort] = arg;
532  args[index] = arg;
533  }
534 
535  if (isDataArgumentInFunction)
536  {
537  map<VuoCompilerEventPort *, Value *>::const_iterator iter = portContextForEventPort.find(eventPort);
538  Value *portContextValue = (iter != portContextForEventPort.end() ?
539  iter->second :
540  eventPort->generateGetPortContext(module, block, nodeContextValue));
541 
542  size_t index = getArgumentIndexInFunction(data, functionSrc);
543  Type *type = eventPort->getDataVuoType()->getCompiler()->getType();
544  Value *dataVariable = VuoCompilerCodeGenUtilities::generateGetPortContextDataVariable(module, block, portContextValue, type);
545  outputPortDataVariables[eventPort] = dataVariable;
546 
547  Value *arg = VuoCompilerCodeGenUtilities::convertArgumentToParameterType(dataVariable, functionDst, index, NULL, module, block);
548  if (!arg)
549  {
550  VUserLog("Warning: Couldn't convert argument for output port '%s' of function %s; not generating call.",
551  (*i)->getClass()->getName().c_str(),
552  functionDst->getName().str().c_str());
553  return nullptr;
554  }
555  args[index] = arg;
556  }
557  }
558  else
559  {
560  VuoCompilerTriggerPort *triggerPort = (VuoCompilerTriggerPort *)((*i)->getCompiler());
561  if (isArgumentInFunction(triggerPort, functionSrc))
562  {
563  size_t index = getArgumentIndexInFunction(triggerPort, functionSrc);
564  args[index] = triggerPort->generateLoadFunction(module, block, nodeContextValue);
565  }
566  }
567  }
568 
569  // Set up the argument for the instance data (if it exists).
570  Value *instanceDataVariable = NULL;
571  if (instanceData && isArgumentInFunction(instanceData, functionSrc))
572  {
573  Type *type = instanceData->getBase()->getClass()->getCompiler()->getType();
574  instanceDataVariable = VuoCompilerCodeGenUtilities::generateGetNodeContextInstanceDataVariable(module, block, nodeContextValue, type);
575 
576  size_t index = getArgumentIndexInFunction(instanceData, functionSrc);
577  Value *arg = instanceDataVariable;
578  args[index] = VuoCompilerCodeGenUtilities::convertArgumentToParameterType(arg, functionDst, index, NULL, module, block);
579  if (!args[index])
580  {
581  VUserLog("Warning: Couldn't convert argument for instance data of function %s; not generating call.", functionDst->getName().str().c_str());
582  return nullptr;
583  }
584  }
585 
586  // Save the old output port values so they can be released later.
587  map<VuoCompilerOutputEventPort *, Value *> oldOutputDataValues;
588  for (map<VuoCompilerOutputEventPort *, Value *>::iterator i = outputPortDataVariables.begin(); i != outputPortDataVariables.end(); ++i)
589  {
590  VuoCompilerOutputEventPort *eventPort = i->first;
591  Value *dataVariable = i->second;
592 
593  oldOutputDataValues[eventPort] = new LoadInst(dataVariable, "", false, block);
594  }
595 
596  // Save the old instance data value so it can be released later.
597  Value *oldInstanceDataValue = NULL;
598  if (instanceDataVariable)
599  {
600  oldInstanceDataValue = new LoadInst(instanceDataVariable, "", false, block);
601  }
602 
604 
605  {
606  int i = 0;
607  for (auto arg : args)
608  {
609  if (!arg)
610  {
611  string s;
612  raw_string_ostream type(s);
613  functionDst->getFunctionType()->getParamType(i)->print(type);
614  ostringstream argIndex;
615  argIndex << i;
616  string details = "When trying to generate a call to function " + functionDst->getName().str() +
617  ", argument " + argIndex.str() + " (" + type.str() + ") was missing.";
618  VuoCompilerIssue issue(VuoCompilerIssue::Error, "compiling composition", "", "", details);
619  throw VuoCompilerException(issue);
620  }
621  ++i;
622  }
623  }
624 
625  // Call the node class's function.
626  CallInst *call = CallInst::Create(functionDst, args, "", block);
627 
629 
630  // Save the output events from temporary variables to the ports.
631  // (The temporary variables are needed to avoid mismatched types between the parameters and the arguments, e.g. i8* vs. i64*.)
632  for (map<VuoCompilerOutputEventPort *, AllocaInst *>::iterator i = outputPortEventVariables.begin(); i != outputPortEventVariables.end(); ++i)
633  {
634  VuoCompilerOutputEventPort *eventPort = i->first;
635  AllocaInst *eventVariable = i->second;
636  Value *eventValue = new LoadInst(eventVariable, "", false, block);
637  eventPort->generateStoreEvent(module, block, nodeContextValue, eventValue);
638  }
639 
640  // Retain the new output port values.
641  for (map<VuoCompilerOutputEventPort *, Value *>::iterator i = outputPortDataVariables.begin(); i != outputPortDataVariables.end(); ++i)
642  {
643  VuoCompilerOutputEventPort *eventPort = i->first;
644  Value *dataVariable = i->second;
645 
646  Value *outputDataValue = new LoadInst(dataVariable, "", false, block);
647  VuoCompilerType *type = eventPort->getDataVuoType()->getCompiler();
648  type->generateRetainCall(module, block, outputDataValue);
649  }
650 
651  // Release the old output port values.
652  for (map<VuoCompilerOutputEventPort *, Value *>::iterator i = oldOutputDataValues.begin(); i != oldOutputDataValues.end(); ++i)
653  {
654  VuoCompilerOutputEventPort *eventPort = i->first;
655  Value *oldOutputDataValue = i->second;
656 
657  VuoCompilerType *type = eventPort->getDataVuoType()->getCompiler();
658  type->generateReleaseCall(module, block, oldOutputDataValue);
659  }
660 
661  if (instanceDataVariable)
662  {
663  // Retain the new instance data value.
664  Value *instanceDataValue = new LoadInst(instanceDataVariable, "", false, block);
665  VuoCompilerCodeGenUtilities::generateRetainCall(module, block, instanceDataValue);
666 
667  // Release the old instance data value.
668  VuoCompilerCodeGenUtilities::generateReleaseCall(module, block, oldInstanceDataValue);
669  }
670 
671  if (getBase()->getNodeClass()->getCompiler()->isSubcomposition())
672  {
673  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, subcompositionStateValue);
674  VuoCompilerCodeGenUtilities::generateFreeCall(module, block, subcompositionIdentifierValue);
675  }
676 
677  return call;
678 }
679 
686 bool VuoCompilerNode::isArgumentInFunction(VuoCompilerNodeArgument *argument, Function *function)
687 {
688  VuoCompilerNodeArgumentClass *argumentClass = argument->getBase()->getClass()->getCompiler();
689  if (function == getBase()->getNodeClass()->getCompiler()->getEventFunction())
690  return argumentClass->isInEventFunction();
691  else if (function == getBase()->getNodeClass()->getCompiler()->getInitFunction())
692  return argumentClass->isInInitFunction();
693  else if (function == getBase()->getNodeClass()->getCompiler()->getCallbackStartFunction())
694  return argumentClass->isInCallbackStartFunction();
695  else if (function == getBase()->getNodeClass()->getCompiler()->getCallbackUpdateFunction())
696  return argumentClass->isInCallbackUpdateFunction();
697  else if (function == getBase()->getNodeClass()->getCompiler()->getCallbackStopFunction())
698  return argumentClass->isInCallbackStopFunction();
699  else if (instanceData == argument &&
700  (function == getBase()->getNodeClass()->getCompiler()->getFiniFunction()))
701  return true;
702  return false;
703 }
704 
711 size_t VuoCompilerNode::getArgumentIndexInFunction(VuoCompilerNodeArgument *argument, Function *function)
712 {
713  VuoCompilerNodeArgumentClass *argumentClass = argument->getBase()->getClass()->getCompiler();
714  if (function == getBase()->getNodeClass()->getCompiler()->getEventFunction())
715  return argumentClass->getIndexInEventFunction();
716  else if (function == getBase()->getNodeClass()->getCompiler()->getInitFunction())
717  return argumentClass->getIndexInInitFunction();
718  else if (function == getBase()->getNodeClass()->getCompiler()->getFiniFunction())
719  return (getBase()->getNodeClass()->getCompiler()->isSubcomposition() ? 1 : 0);
720  else if (function == getBase()->getNodeClass()->getCompiler()->getCallbackStartFunction())
721  return argumentClass->getIndexInCallbackStartFunction();
722  else if (function == getBase()->getNodeClass()->getCompiler()->getCallbackUpdateFunction())
723  return argumentClass->getIndexInCallbackUpdateFunction();
724  else if (function == getBase()->getNodeClass()->getCompiler()->getCallbackStopFunction())
725  return argumentClass->getIndexInCallbackStopFunction();
726  return 0;
727 }
728 
732 Value * VuoCompilerNode::generateReceivedEventCondition(Module *module, BasicBlock *block, Value *nodeContextValue)
733 {
734  return generateReceivedEventCondition(module, block, nodeContextValue, getBase()->getInputPorts());
735 }
736 
740 Value * VuoCompilerNode::generateReceivedEventCondition(Module *module, BasicBlock *block, Value *nodeContextValue,
741  vector<VuoPort *> selectedInputPorts,
742  const map<VuoCompilerEventPort *, Value *> &portContextForEventPort)
743 {
744  Value *conditionValue = ConstantInt::getFalse(block->getContext());
745  for (vector<VuoPort *>::iterator i = selectedInputPorts.begin(); i != selectedInputPorts.end(); ++i)
746  {
747  VuoCompilerInputEventPort *eventPort = dynamic_cast<VuoCompilerInputEventPort *>((*i)->getCompiler());
748  if (eventPort)
749  {
750  map<VuoCompilerEventPort *, Value *>::const_iterator iter = portContextForEventPort.find(eventPort);
751  Value *portContextValue = (iter != portContextForEventPort.end() ?
752  iter->second :
753  eventPort->generateGetPortContext(module, block, nodeContextValue));
754 
755  Value *pushValue = eventPort->generateLoadEvent(module, block, nodeContextValue, portContextValue);
756  conditionValue = BinaryOperator::Create(Instruction::Or, conditionValue, pushValue, "", block);
757  }
758  }
759  return conditionValue;
760 }
761 
766 {
767  return instanceData;
768 }
769 
777 {
778  return getGraphvizIdentifier();
779 }
780 
790 {
791  string titleWithoutSpaces = VuoStringUtilities::convertToCamelCase(getBase()->getTitle(), true, false, false);
792 
793  if (titleWithoutSpaces.empty())
794  return "Node";
795  else
796  return titleWithoutSpaces;
797 }
798 
802 void VuoCompilerNode::setGraphvizIdentifier(string graphvizIdentifier)
803 {
804  this->graphvizIdentifier = graphvizIdentifier;
805 }
806 
811 {
812  return graphvizIdentifier;
813 }
814 
819 string VuoCompilerNode::getGraphvizDeclaration(bool shouldPrintPosition, double xPositionOffset, double yPositionOffset,
820  VuoPort *manuallyFirableInputPort)
821 {
822  ostringstream declaration;
823 
824  vector<VuoPort *> inputPorts = getBase()->getInputPorts();
825  vector<VuoPort *> outputPorts = getBase()->getOutputPorts();
826 
827  // name
828  declaration << getGraphvizIdentifier();
829 
830  // type
831  declaration << " [type=\"" << getBase()->getNodeClass()->getClassName() << "\"";
832 
833  // version
834  declaration << " version=\"" << getBase()->getNodeClass()->getVersion() << "\"";
835 
836  // label
837  declaration << " label=\"" << VuoStringUtilities::transcodeToGraphvizIdentifier(getBase()->getTitle());
838  for (vector<VuoPort *>::iterator i = inputPorts.begin(); i != inputPorts.end(); ++i)
839  {
840  string portName = VuoStringUtilities::transcodeToGraphvizIdentifier((*i)->getClass()->getName());
841  declaration << "|<" << portName << ">" << portName << "\\l";
842  }
843  for (vector<VuoPort *>::iterator i = outputPorts.begin(); i != outputPorts.end(); ++i)
844  {
845  string portName = VuoStringUtilities::transcodeToGraphvizIdentifier((*i)->getClass()->getName());
846  declaration << "|<" << portName << ">" << portName << "\\r";
847  }
848  declaration << "\"";
849 
850  // position
851  if (shouldPrintPosition)
852  declaration << " pos=\"" << getBase()->getX()+xPositionOffset << "," << getBase()->getY()+yPositionOffset << "\"";
853 
854  // collapsed
855  if (getBase()->isCollapsed())
856  declaration << " collapsed";
857 
858  // tint color
859  if (getBase()->getTintColor() != VuoNode::TintNone)
860  declaration << " fillcolor=\"" << getBase()->getTintColorGraphvizName() << "\"";
861 
862  // constant values
863  for (vector<VuoPort *>::iterator i = inputPorts.begin(); i != inputPorts.end(); ++i)
864  {
865  VuoPort *port = *i;
866  VuoCompilerInputEventPort *eventPort = static_cast<VuoCompilerInputEventPort *>(port->getCompiler());
867  VuoCompilerInputData *data = eventPort->getData();
868  if (data && (! eventPort->hasConnectedDataCable() && ! data->getInitialValue().empty()))
869  {
870  string portConstant = data->getInitialValue();
871  string escapedPortConstant = VuoStringUtilities::transcodeToGraphvizIdentifier(portConstant);
872  declaration << " _" << port->getClass()->getName() << "=\"" << escapedPortConstant << "\"";
873  }
874  }
875 
876  // event throttling
877  for (vector<VuoPort *>::iterator i = outputPorts.begin(); i != outputPorts.end(); ++i)
878  {
879  VuoPort *port = *i;
881  {
882  string eventThrottling = (port->getEventThrottling() == VuoPortClass::EventThrottling_Enqueue ? "enqueue" : "drop");
883  declaration << " _" << port->getClass()->getName() << "_eventThrottling=\"" << eventThrottling << "\"";
884  }
885  }
886 
887  // manually firable input port
888  if (manuallyFirableInputPort)
889  declaration << " _" << manuallyFirableInputPort->getClass()->getName() << "_manuallyFirable";
890 
891  declaration << "];";
892 
893  return declaration.str();
894 }