Vuo  2.3.2
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  constantsCache = 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->constantsCache = constantsCache;
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->setConstantsCache(constantsCache);
82  }
83 }
84 
89 {
90  return constantsCache->get(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(constantsCache->get("/" + getIdentifier()));
104  return VuoCompilerCodeGenUtilities::generateStringConcatenation(module, block, identifierParts, constantsCache);
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 = constantsCache->get(port->getIdentifier());
143  Value *portNameValue = constantsCache->get(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 = constantsCache->get(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 = new BitCastInst(subcompositionStateValue, subcompositionFunctionDst->getFunctionType()->getParamType(0), "", 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->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] = new BitCastInst(subcompositionStateValue, functionDst->getFunctionType()->getParamType(0), "", 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 *pointerToDataAsVoidPointer = VuoCompilerCodeGenUtilities::generateGetPortContextDataVariableAsVoidPointer(module, block, portContextValue);
475  vector<Value *> loweredArgs = eventPort->getDataType()->convertPortDataToArgs(module, block, pointerToDataAsVoidPointer,
476  functionDst->getFunctionType(), index,
477  isUnloweredStructPointerParameter(data, functionSrc));
478  for (auto a : loweredArgs)
479  args[index++] = a;
480  }
481  }
482  }
483 
484  // Set up the arguments for output ports.
485  vector<VuoPort *> outputPorts = getBase()->getOutputPorts();
486  map<VuoCompilerOutputEventPort *, Value *> outputPortDataVariables;
487  map<VuoCompilerOutputEventPort *, AllocaInst *> outputPortEventVariables;
488  for (vector<VuoPort *>::iterator i = outputPorts.begin(); i != outputPorts.end(); ++i)
489  {
490  VuoCompilerOutputEventPort *eventPort = dynamic_cast<VuoCompilerOutputEventPort *>((*i)->getCompiler());
491  if (eventPort)
492  {
493  VuoCompilerOutputData *data = eventPort->getData();
494  bool isEventArgumentInFunction = isArgumentInFunction(eventPort, functionSrc);
495  bool isDataArgumentInFunction = data && isArgumentInFunction(data, functionSrc);
496 
497  if (isEventArgumentInFunction)
498  {
499  size_t index = getArgumentIndexInFunction(eventPort, functionSrc);
500  PointerType *eventPointerType = static_cast<PointerType *>( functionDst->getFunctionType()->getParamType(index) );
501  AllocaInst *arg = new AllocaInst(eventPointerType->getElementType(), 0, "", block);
502  new StoreInst(ConstantInt::get(eventPointerType->getElementType(), 0), arg, block);
503  outputPortEventVariables[eventPort] = arg;
504  args[index] = arg;
505  }
506 
507  if (isDataArgumentInFunction)
508  {
509  map<VuoCompilerEventPort *, Value *>::const_iterator iter = portContextForEventPort.find(eventPort);
510  Value *portContextValue = (iter != portContextForEventPort.end() ?
511  iter->second :
512  eventPort->generateGetPortContext(module, block, nodeContextValue));
513 
514  size_t index = getArgumentIndexInFunction(data, functionSrc);
515  VuoCompilerType *type = eventPort->getDataVuoType()->getCompiler();
516  Value *dataPointer = VuoCompilerCodeGenUtilities::generateGetPortContextDataVariable(module, block, portContextValue, type);
517  outputPortDataVariables[eventPort] = dataPointer;
518 
519  Value *arg = new BitCastInst(dataPointer, functionDst->getFunctionType()->getParamType(index), "dataArgumentCasted", block);
520  args[index] = arg;
521  }
522  }
523  else
524  {
525  VuoCompilerTriggerPort *triggerPort = (VuoCompilerTriggerPort *)((*i)->getCompiler());
526  if (isArgumentInFunction(triggerPort, functionSrc))
527  {
528  size_t index = getArgumentIndexInFunction(triggerPort, functionSrc);
529  Value *triggerFunction = triggerPort->generateLoadFunction(module, block, nodeContextValue);
530  args[index] = new BitCastInst(triggerFunction, functionDst->getFunctionType()->getParamType(index), "triggerArgumentCasted", block);
531  }
532  }
533  }
534 
535  // Set up the argument for the instance data (if it exists).
536  Value *instanceDataVariable = NULL;
537  if (instanceData && isArgumentInFunction(instanceData, functionSrc))
538  {
539  Type *type = instanceData->getType();
540  instanceDataVariable = VuoCompilerCodeGenUtilities::generateGetNodeContextInstanceDataVariable(module, block, nodeContextValue, type);
541 
542  size_t index = getArgumentIndexInFunction(instanceData, functionSrc);
543  Value *arg = instanceDataVariable;
544  args[index] = new BitCastInst(arg, functionDst->getFunctionType()->getParamType(index), "", block);
545  if (!args[index])
546  {
547  VUserLog("Warning: Couldn't convert argument for instance data of function %s; not generating call.", functionDst->getName().str().c_str());
548  return nullptr;
549  }
550  }
551 
552  // Save the old output port values so they can be released later.
553  map<VuoCompilerOutputEventPort *, Value *> oldOutputDataPointers;
554  for (map<VuoCompilerOutputEventPort *, Value *>::iterator i = outputPortDataVariables.begin(); i != outputPortDataVariables.end(); ++i)
555  {
556  VuoCompilerOutputEventPort *eventPort = i->first;
557  Value *dataVariable = i->second; // For VuoText, this is `char **`
558  Value *dataPointer = new AllocaInst(static_cast<PointerType *>(dataVariable->getType())->getElementType(), 0, "", block); // For VuoText, this is `char **`
559  Value *dataValue = new LoadInst(dataVariable, "", false, block); // For VuoText, this is `char *`
560  new StoreInst(dataValue, dataPointer, block);
561  oldOutputDataPointers[eventPort] = dataPointer;
562  }
563 
564  // Save the old instance data value so it can be released later.
565  Value *oldInstanceDataValue = NULL;
566  if (instanceDataVariable)
567  {
568  oldInstanceDataValue = new LoadInst(instanceDataVariable, "", false, block);
569  }
570 
572 
573  {
574  int i = 0;
575  for (auto arg : args)
576  {
577  if (!arg)
578  {
579  string s;
580  raw_string_ostream type(s);
581  functionDst->getFunctionType()->getParamType(i)->print(type);
582  ostringstream argIndex;
583  argIndex << i;
584  string details = "When trying to generate a call to function " + functionDst->getName().str() +
585  ", argument " + argIndex.str() + " (" + type.str() + ") was missing.";
586  VuoCompilerIssue issue(VuoCompilerIssue::Error, "compiling composition", "", "", details);
587  throw VuoCompilerException(issue);
588  }
589  ++i;
590  }
591  }
592 
593  // Call the node class's function.
594  CallInst *call = CallInst::Create(functionDst, args, "", block);
595 
597 
598  // Save the output events from temporary variables to the ports.
599  // (The temporary variables are needed to avoid mismatched types between the parameters and the arguments, e.g. i8* vs. i64*.)
600  for (map<VuoCompilerOutputEventPort *, AllocaInst *>::iterator i = outputPortEventVariables.begin(); i != outputPortEventVariables.end(); ++i)
601  {
602  VuoCompilerOutputEventPort *eventPort = i->first;
603  AllocaInst *eventVariable = i->second;
604  Value *eventValue = new LoadInst(eventVariable, "", false, block);
605  eventPort->generateStoreEvent(module, block, nodeContextValue, eventValue);
606  }
607 
608  // Retain the new output port values.
609  for (map<VuoCompilerOutputEventPort *, Value *>::iterator i = outputPortDataVariables.begin(); i != outputPortDataVariables.end(); ++i)
610  {
611  VuoCompilerOutputEventPort *eventPort = i->first;
612  Value *dataVariable = i->second;
613 
614  VuoCompilerType *type = eventPort->getDataVuoType()->getCompiler();
615  type->generateRetainCall(module, block, dataVariable);
616  }
617 
618  // Release the old output port values.
619  for (map<VuoCompilerOutputEventPort *, Value *>::iterator i = oldOutputDataPointers.begin(); i != oldOutputDataPointers.end(); ++i)
620  {
621  VuoCompilerOutputEventPort *eventPort = i->first;
622  Value *oldOutputDataPointer = i->second; // For VuoText, this is `char **`
623 
624  VuoCompilerType *type = eventPort->getDataVuoType()->getCompiler();
625  type->generateReleaseCall(module, block, oldOutputDataPointer);
626  }
627 
628  if (instanceDataVariable)
629  {
630  // Retain the new instance data value.
631  Value *instanceDataValue = new LoadInst(instanceDataVariable, "", false, block);
632  VuoCompilerCodeGenUtilities::generateRetainCall(module, block, instanceDataValue);
633 
634  // Release the old instance data value.
635  VuoCompilerCodeGenUtilities::generateReleaseCall(module, block, oldInstanceDataValue);
636  }
637 
638  if (getBase()->getNodeClass()->getCompiler()->isSubcomposition())
639  {
640  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, subcompositionStateValue);
641  VuoCompilerCodeGenUtilities::generateFreeCall(module, block, subcompositionIdentifierValue);
642  }
643 
644  return call;
645 }
646 
653 bool VuoCompilerNode::isArgumentInFunction(VuoCompilerNodeArgument *argument, Function *function)
654 {
655  VuoCompilerNodeArgumentClass *argumentClass = argument->getBase()->getClass()->getCompiler();
656  if (function == getBase()->getNodeClass()->getCompiler()->getEventFunction())
657  return argumentClass->isInEventFunction();
658  else if (function == getBase()->getNodeClass()->getCompiler()->getInitFunction())
659  return argumentClass->isInInitFunction();
660  else if (function == getBase()->getNodeClass()->getCompiler()->getCallbackStartFunction())
661  return argumentClass->isInCallbackStartFunction();
662  else if (function == getBase()->getNodeClass()->getCompiler()->getCallbackUpdateFunction())
663  return argumentClass->isInCallbackUpdateFunction();
664  else if (function == getBase()->getNodeClass()->getCompiler()->getCallbackStopFunction())
665  return argumentClass->isInCallbackStopFunction();
666  else if (instanceData == argument &&
667  (function == getBase()->getNodeClass()->getCompiler()->getFiniFunction()))
668  return true;
669  return false;
670 }
671 
678 size_t VuoCompilerNode::getArgumentIndexInFunction(VuoCompilerNodeArgument *argument, Function *function)
679 {
680  VuoCompilerNodeArgumentClass *argumentClass = argument->getBase()->getClass()->getCompiler();
681  if (function == getBase()->getNodeClass()->getCompiler()->getEventFunction())
682  return argumentClass->getIndexInEventFunction();
683  else if (function == getBase()->getNodeClass()->getCompiler()->getInitFunction())
684  return argumentClass->getIndexInInitFunction();
685  else if (function == getBase()->getNodeClass()->getCompiler()->getFiniFunction())
686  return (getBase()->getNodeClass()->getCompiler()->isSubcomposition() ? 1 : 0);
687  else if (function == getBase()->getNodeClass()->getCompiler()->getCallbackStartFunction())
688  return argumentClass->getIndexInCallbackStartFunction();
689  else if (function == getBase()->getNodeClass()->getCompiler()->getCallbackUpdateFunction())
690  return argumentClass->getIndexInCallbackUpdateFunction();
691  else if (function == getBase()->getNodeClass()->getCompiler()->getCallbackStopFunction())
692  return argumentClass->getIndexInCallbackStopFunction();
693  return 0;
694 }
695 
703 bool VuoCompilerNode::isUnloweredStructPointerParameter(VuoCompilerInputData *inputData, Function *function)
704 {
705  VuoCompilerInputDataClass *inputDataClass = static_cast<VuoCompilerInputDataClass *>(inputData->getBase()->getClass()->getCompiler());
706  if (function == getBase()->getNodeClass()->getCompiler()->getEventFunction())
707  return inputDataClass->isUnloweredStructPointerInEventFunction();
708  else if (function == getBase()->getNodeClass()->getCompiler()->getInitFunction())
709  return inputDataClass->isUnloweredStructPointerInInitFunction();
710  else if (function == getBase()->getNodeClass()->getCompiler()->getCallbackStartFunction())
711  return inputDataClass->isUnloweredStructPointerInCallbackStartFunction();
712  else if (function == getBase()->getNodeClass()->getCompiler()->getCallbackUpdateFunction())
713  return inputDataClass->isUnloweredStructPointerInCallbackUpdateFunction();
714  else if (function == getBase()->getNodeClass()->getCompiler()->getCallbackStopFunction())
715  return inputDataClass->isUnloweredStructPointerInCallbackStopFunction();
716  return false;
717 }
718 
722 Value * VuoCompilerNode::generateReceivedEventCondition(Module *module, BasicBlock *block, Value *nodeContextValue)
723 {
724  return generateReceivedEventCondition(module, block, nodeContextValue, getBase()->getInputPorts());
725 }
726 
730 Value * VuoCompilerNode::generateReceivedEventCondition(Module *module, BasicBlock *block, Value *nodeContextValue,
731  vector<VuoPort *> selectedInputPorts,
732  const map<VuoCompilerEventPort *, Value *> &portContextForEventPort)
733 {
734  Value *conditionValue = ConstantInt::getFalse(block->getContext());
735  for (vector<VuoPort *>::iterator i = selectedInputPorts.begin(); i != selectedInputPorts.end(); ++i)
736  {
737  VuoCompilerInputEventPort *eventPort = dynamic_cast<VuoCompilerInputEventPort *>((*i)->getCompiler());
738  if (eventPort)
739  {
740  map<VuoCompilerEventPort *, Value *>::const_iterator iter = portContextForEventPort.find(eventPort);
741  Value *portContextValue = (iter != portContextForEventPort.end() ?
742  iter->second :
743  eventPort->generateGetPortContext(module, block, nodeContextValue));
744 
745  Value *pushValue = eventPort->generateLoadEvent(module, block, nodeContextValue, portContextValue);
746  conditionValue = BinaryOperator::Create(Instruction::Or, conditionValue, pushValue, "", block);
747  }
748  }
749  return conditionValue;
750 }
751 
756 {
757  return instanceData;
758 }
759 
767 {
768  return getGraphvizIdentifier();
769 }
770 
780 {
781  string titleWithoutSpaces = VuoStringUtilities::convertToCamelCase(getBase()->getTitle(), true, false, false);
782 
783  if (titleWithoutSpaces.empty())
784  return "Node";
785  else
786  return titleWithoutSpaces;
787 }
788 
792 void VuoCompilerNode::setGraphvizIdentifier(string graphvizIdentifier)
793 {
794  this->graphvizIdentifier = graphvizIdentifier;
795 }
796 
801 {
802  return graphvizIdentifier;
803 }
804 
809 string VuoCompilerNode::getGraphvizDeclaration(bool shouldPrintPosition, double xPositionOffset, double yPositionOffset,
810  VuoPort *manuallyFirableInputPort)
811 {
812  ostringstream declaration;
813 
814  vector<VuoPort *> inputPorts = getBase()->getInputPorts();
815  vector<VuoPort *> outputPorts = getBase()->getOutputPorts();
816 
817  // name
818  declaration << getGraphvizIdentifier();
819 
820  // type
821  declaration << " [type=\"" << getBase()->getNodeClass()->getClassName() << "\"";
822 
823  // version
824  declaration << " version=\"" << getBase()->getNodeClass()->getVersion() << "\"";
825 
826  // label
827  declaration << " label=\"" << VuoStringUtilities::transcodeToGraphvizIdentifier(getBase()->getTitle());
828  for (vector<VuoPort *>::iterator i = inputPorts.begin(); i != inputPorts.end(); ++i)
829  {
830  string portName = VuoStringUtilities::transcodeToGraphvizIdentifier((*i)->getClass()->getName());
831  declaration << "|<" << portName << ">" << portName << "\\l";
832  }
833  for (vector<VuoPort *>::iterator i = outputPorts.begin(); i != outputPorts.end(); ++i)
834  {
835  string portName = VuoStringUtilities::transcodeToGraphvizIdentifier((*i)->getClass()->getName());
836  declaration << "|<" << portName << ">" << portName << "\\r";
837  }
838  declaration << "\"";
839 
840  // position
841  if (shouldPrintPosition)
842  declaration << " pos=\"" << getBase()->getX()+xPositionOffset << "," << getBase()->getY()+yPositionOffset << "\"";
843 
844  // collapsed
845  if (getBase()->isCollapsed())
846  declaration << " collapsed";
847 
848  // tint color
849  if (getBase()->getTintColor() != VuoNode::TintNone)
850  declaration << " fillcolor=\"" << getBase()->getTintColorGraphvizName() << "\"";
851 
852  // constant values
853  for (vector<VuoPort *>::iterator i = inputPorts.begin(); i != inputPorts.end(); ++i)
854  {
855  VuoPort *port = *i;
856  VuoCompilerInputEventPort *eventPort = static_cast<VuoCompilerInputEventPort *>(port->getCompiler());
857  VuoCompilerInputData *data = eventPort->getData();
858  if (data && (! eventPort->hasConnectedDataCable() && ! data->getInitialValue().empty()))
859  {
860  string portConstant = data->getInitialValue();
861  string escapedPortConstant = VuoStringUtilities::transcodeToGraphvizIdentifier(portConstant);
862  declaration << " _" << port->getClass()->getName() << "=\"" << escapedPortConstant << "\"";
863  }
864  }
865 
866  // event throttling
867  for (vector<VuoPort *>::iterator i = outputPorts.begin(); i != outputPorts.end(); ++i)
868  {
869  VuoPort *port = *i;
871  {
872  string eventThrottling = (port->getEventThrottling() == VuoPortClass::EventThrottling_Enqueue ? "enqueue" : "drop");
873  declaration << " _" << port->getClass()->getName() << "_eventThrottling=\"" << eventThrottling << "\"";
874  }
875  }
876 
877  // manually firable input port
878  if (manuallyFirableInputPort)
879  declaration << " _" << manuallyFirableInputPort->getClass()->getName() << "_manuallyFirable=\"yes\"";
880 
881  declaration << "];";
882 
883  return declaration.str();
884 }