Vuo  2.0.0
VuoCompilerBitcodeGenerator.cc
Go to the documentation of this file.
1 
10 #include <sstream>
11 #include "VuoCable.hh"
12 #include "VuoCompiler.hh"
14 #include "VuoCompilerCable.hh"
15 #include "VuoCompilerChain.hh"
18 #include "VuoCompilerGraph.hh"
22 #include "VuoCompilerNode.hh"
23 #include "VuoCompilerNodeClass.hh"
29 #include "VuoCompilerType.hh"
30 #include "VuoComposition.hh"
32 #include "VuoNode.hh"
33 #include "VuoNodeClass.hh"
34 #include "VuoStringUtilities.hh"
35 #include "VuoPublishedPort.hh"
36 #include "VuoType.hh"
37 
42  bool isTopLevelComposition,
43  string moduleKey, VuoCompiler *compiler)
44 {
45  VuoCompilerBitcodeGenerator * cg = new VuoCompilerBitcodeGenerator(composition, isTopLevelComposition, moduleKey, compiler);
46  return cg;
47 }
48 
52 VuoCompilerBitcodeGenerator::VuoCompilerBitcodeGenerator(VuoCompilerComposition *composition,
53  bool isTopLevelComposition,
54  string moduleKey, VuoCompiler *compiler)
55 {
56 #if VUO_PRO
57  VuoCompilerBitcodeGenerator_Pro();
58 #endif
59  module = NULL;
60  debugMode = false;
61 
62  this->composition = composition;
63  this->isTopLevelComposition = isTopLevelComposition;
64  this->moduleKey = moduleKey;
65  this->compiler = compiler;
66 
67  graph = composition->getCachedGraph(compiler);
68 
69  chainsForTrigger = graph->getChains(); // store in a data member, rather than calling getChains() multiple times, to preserve order of chains
70  makeOrderedNodes();
71  makeOrderedTypes();
72  makePortContextInfo();
73  makeSubcompositionModelPorts();
74  makeDependencies();
75 }
76 
81 {
82  for (vector<VuoPort *>::iterator i = modelOutputPorts.begin(); i != modelOutputPorts.end(); ++i)
83  {
84  VuoPort *modelOutputPort = *i;
85  if (modelOutputPort->getClass()->getPortType() == VuoPortClass::triggerPort)
86  {
87  delete modelOutputPort->getClass()->getCompiler();
88  delete modelOutputPort->getCompiler();
89  }
90  }
91 }
92 
96 struct ChainSort
97 {
100  set<VuoCompilerNode *> lastNodeInLoop;
101 
105  bool operator() (const vector<VuoCompilerNode *> &chainNodes1, const vector<VuoCompilerNode *> &chainNodes2)
106  {
107  // If the chains have an upstream-downstream relationship, return whether chainNodes1 is upstream of chainNodes2.
108 
109  vector<VuoCompilerNode *> downstreamOfChain1 = graph->getNodesDownstream(chainNodes1.back(), trigger);
110  vector<VuoCompilerNode *> downstreamOfChain2 = graph->getNodesDownstream(chainNodes2.back(), trigger);
111 
112  bool isNode2DownstreamOfNode1 = find(downstreamOfChain1.begin(), downstreamOfChain1.end(), chainNodes2.front()) != downstreamOfChain1.end();
113  bool isNode1DownstreamOfNode2 = find(downstreamOfChain2.begin(), downstreamOfChain2.end(), chainNodes1.front()) != downstreamOfChain2.end();
114 
115  if (isNode2DownstreamOfNode1 && isNode1DownstreamOfNode2)
116  return (lastNodeInLoop.find(chainNodes1.front()) != lastNodeInLoop.end());
117  else if (isNode2DownstreamOfNode1)
118  return true;
119  else if (isNode1DownstreamOfNode2)
120  return false;
121 
122  // If at least one of the chains contains a trigger port, return the chain containing the trigger port with
123  // the greatest number of downstream nodes.
124 
125  size_t maxNumDownstreamOfTrigger[2] = { 0, 0 };
126  vector<VuoCompilerNode *> chainNodes[2] = { chainNodes1, chainNodes2 };
127  for (int i = 0; i < 2; ++i)
128  {
129  for (vector<VuoCompilerNode *>::const_iterator j = chainNodes[i].begin(); j != chainNodes[i].end(); ++j)
130  {
131  VuoCompilerNode *node = *j;
132  vector<VuoPort *> outputPorts = node->getBase()->getOutputPorts();
133  for (vector<VuoPort *>::iterator k = outputPorts.begin(); k != outputPorts.end(); ++k)
134  {
135  VuoPort *outputPort = *k;
136  if (outputPort->getClass()->getPortType() == VuoPortClass::triggerPort)
137  {
138  VuoCompilerTriggerPort *trigger = dynamic_cast<VuoCompilerTriggerPort *>( outputPort->getCompiler() );
139  size_t numDownstreamOfTrigger = graph->getNodesDownstream(trigger).size();
140  maxNumDownstreamOfTrigger[i] = max(maxNumDownstreamOfTrigger[i], numDownstreamOfTrigger);
141  }
142  }
143  }
144  }
145 
146  if (maxNumDownstreamOfTrigger[0] != maxNumDownstreamOfTrigger[1])
147  return maxNumDownstreamOfTrigger[0] > maxNumDownstreamOfTrigger[1];
148 
149  // Tiebreak: Sort alphabetically.
150 
151  return chainNodes1.front()->getIdentifier() < chainNodes2.front()->getIdentifier();
152  }
153 };
154 
158 void VuoCompilerBitcodeGenerator::makeOrderedNodes(void)
159 {
160  // For each trigger, put its downstream nodes into topological order (optimized with ChainSort so that
161  // orderedNodes will be more likely to match the ordering of the triggers with more downstream nodes).
162  for (VuoCompilerTriggerPort *trigger : graph->getTriggerPorts())
163  {
164  vector<VuoCompilerChain *> chains;
165  map<VuoCompilerTriggerPort *, vector<VuoCompilerChain *> >::iterator chainsIter = chainsForTrigger.find(trigger);
166  if (chainsIter != chainsForTrigger.end())
167  chains = chainsIter->second;
168 
169  vector< vector<VuoCompilerNode *> > chainNodeLists;
170  set<VuoCompilerNode *> lastNodeInLoop;
171  for (VuoCompilerChain *chain : chains)
172  {
173  if (chain->isLastNodeInLoop())
174  lastNodeInLoop.insert( chain->getNodes().front() );
175  else
176  chainNodeLists.push_back( chain->getNodes() );
177  }
178 
179  ChainSort c;
180  c.graph = graph;
181  c.trigger = trigger;
182  c.lastNodeInLoop = lastNodeInLoop;
183  sort(chainNodeLists.begin(), chainNodeLists.end(), c);
184 
185  vector<VuoCompilerNode *> orderedNodeList;
186 
187  VuoCompilerNode *triggerNode = graph->getNodeForTriggerPort(trigger);
188  orderedNodeList.push_back(triggerNode);
189 
190  for (vector<VuoCompilerNode *> chainNodeList : chainNodeLists)
191  {
192  auto triggerNodeIter = std::find(chainNodeList.begin(), chainNodeList.end(), triggerNode);
193  if (triggerNodeIter != chainNodeList.end())
194  chainNodeList.erase(triggerNodeIter);
195 
196  orderedNodeList.insert( orderedNodeList.end(), chainNodeList.begin(), chainNodeList.end() );
197  }
198 
199  downstreamNodesForTrigger[trigger] = orderedNodeList;
200  }
201 
202  vector< vector<VuoCompilerNode *> > orderedNodesPerTrigger;
203  for (const map<VuoCompilerTriggerPort *, vector<VuoCompilerNode *> >::value_type &i : downstreamNodesForTrigger)
204  orderedNodesPerTrigger.push_back(i.second);
205 
206  // For each node that can transmit without an event, put it and its downstream nodes in with the triggers' downstream nodes.
207  for (VuoCompilerNode *node : graph->getNodes())
208  {
209  if (graph->mayTransmitDataOnly(node))
210  {
211  vector<VuoCompilerNode *> downstreamNodes = graph->getNodesDownstreamViaDataOnlyTransmission(node);
212  vector<VuoCompilerNode *> nodesInProgress;
213  nodesInProgress.push_back(node);
214  nodesInProgress.insert(nodesInProgress.end(), downstreamNodes.begin(), downstreamNodes.end());
215  orderedNodesPerTrigger.push_back(nodesInProgress);
216  }
217  }
218 
219  // Put the downstream nodes per trigger in descending order of number of downstream nodes.
220  std::sort(orderedNodesPerTrigger.begin(), orderedNodesPerTrigger.end(),
221  [](const vector<VuoCompilerNode *> &nodes1, const vector<VuoCompilerNode *> &nodes2) {
222  if (nodes1.size() != nodes2.size())
223  return nodes1.size() < nodes2.size();
224 
225  // Tiebreak: Sort alphabetically.
226  ostringstream oss1;
227  ostringstream oss2;
228  for (VuoCompilerNode *n : nodes1)
229  oss1 << n->getIdentifier() << " ";
230  for (VuoCompilerNode *n : nodes2)
231  oss2 << n->getIdentifier() << " ";
232  return oss1.str() < oss2.str();
233  });
234 
235  // Visit each trigger, in descending order of number of downstream nodes (so that orderedNodes will be more likely
236  // to match the ordering of the triggers with more downstream nodes, and thus be more likely to wait on them one at
237  // a time instead of less efficiently having to wait on all initially).
238  int previousTriggerNodeIndex = -1;
239  for (vector< vector<VuoCompilerNode *> >::reverse_iterator i = orderedNodesPerTrigger.rbegin(); i != orderedNodesPerTrigger.rend(); ++i)
240  {
241  // Merge the trigger's downstream nodes into orderedNodes.
242  int previousNodeIndex = previousTriggerNodeIndex;
243  bool isFirstNode = true;
244  for (VuoCompilerNode *node : *i)
245  {
246  vector<VuoCompilerNode *>::iterator nodeIter = find(orderedNodes.begin(), orderedNodes.end(), node);
247  if (nodeIter == orderedNodes.end())
248  nodeIter = orderedNodes.insert(orderedNodes.begin() + previousNodeIndex + 1, node);
249 
250  previousNodeIndex = max(previousNodeIndex, (int)(nodeIter - orderedNodes.begin()));
251  if (isFirstNode)
252  {
253  previousTriggerNodeIndex = previousNodeIndex;
254  isFirstNode = false;
255  }
256  }
257  }
258 
259  // Add (at the end) any remaining nodes in the composition.
260  for (VuoCompilerNode *node : graph->getNodes())
261  if (find(orderedNodes.begin(), orderedNodes.end(), node) == orderedNodes.end())
262  orderedNodes.push_back(node);
263 
264  for (size_t i = 0; i < orderedNodes.size(); ++i)
265  orderedNodes[i]->setIndexInOrderedNodes(i);
266 }
267 
271 void VuoCompilerBitcodeGenerator::sortNodes(vector<VuoCompilerNode *> &nodes)
272 {
273  vector<VuoCompilerNode *> sortedNodes;
274  for (vector<VuoCompilerNode *>::iterator i = orderedNodes.begin(); i != orderedNodes.end(); ++i)
275  {
276  VuoCompilerNode *node = *i;
277  if (find(nodes.begin(), nodes.end(), node) != nodes.end())
278  sortedNodes.push_back(node);
279  }
280  nodes = sortedNodes;
281 }
282 
286 vector<VuoCompilerNode *> VuoCompilerBitcodeGenerator::getNodesToWaitOnBeforeTransmission(VuoCompilerTriggerPort *trigger)
287 {
288  // Does the trigger have a scatter downstream, and another trigger overlaps with some branches of the scatter but
289  // not others? If so, then all downstream nodes will be locked before the event can proceed.
290  // (The analysis is an approximation. It checks if another trigger overlaps *anywhere* downstream, even if the
291  // overlap is after the scatter has been fully gathered back up.)
292  // This prevents deadlocks involving one trigger claiming one branch and the other trigger claiming another
293  // (https://b33p.net/kosada/node/6696, https://b33p.net/kosada/node/12503).
294 
295  bool hasScatterOverlappedByAnotherTrigger = graph->hasScatterPartiallyOverlappedByAnotherTrigger(trigger);
296 
297  // Does the trigger port cause a `Spin Off` node to fire an event that has downstream nodes in common with the trigger?
298  // If so, then all downstream nodes will be locked before the event can proceed.
299  // This prevents the trigger's event from getting stuck behind and having to wait on the `Spin Off` event,
300  // defeating the purpose of the `Spin Off` node (https://b33p.net/kosada/node/11351).
301 
302  bool hasOverlapWithSpinOff = graph->hasOverlapWithSpinOff(trigger);
303 
304  // Would the trigger port wait on nodes in a different order than orderedNodes?
305  // If so, then all downstream nodes will be locked before the event can proceed.
306  // This prevents deadlock where the events from two different trigger ports reach the downstream nodes in a different order
307  // (https://b33p.net/kosada/node/7924).
308 
309  vector<VuoCompilerNode *> sortedDownstreamNodes = downstreamNodesForTrigger[trigger];
310  sortNodes(sortedDownstreamNodes);
311  bool hasOutOfOrderDownstreamNodes = (downstreamNodesForTrigger[trigger] != sortedDownstreamNodes);
312 
313  // Wait for either all nodes downstream of the trigger or the nodes directly connected to the trigger.
314  vector<VuoCompilerNode *> nodesToWaitOn;
315  if (hasScatterOverlappedByAnotherTrigger || hasOverlapWithSpinOff || hasOutOfOrderDownstreamNodes)
316  nodesToWaitOn = downstreamNodesForTrigger[trigger];
317  else
318  {
319  nodesToWaitOn = graph->getNodesImmediatelyDownstream(trigger);
320  VuoCompilerNode *triggerNode = downstreamNodesForTrigger[trigger].front();
321  if (find(nodesToWaitOn.begin(), nodesToWaitOn.end(), triggerNode) == nodesToWaitOn.end())
322  nodesToWaitOn.push_back(triggerNode);
323  }
324 
325  return nodesToWaitOn;
326 }
327 
331 vector<VuoCompilerNode *> VuoCompilerBitcodeGenerator::getNodesToWaitOnBeforeTransmission(VuoCompilerTriggerPort *trigger, VuoCompilerNode *node)
332 {
333  // Does the node have a scatter downstream, and another trigger overlaps with some branches of the scatter but
334  // not others? If so, then all downstream nodes will be locked before the event can proceed.
335  // (The analysis is an approximation. It checks if another trigger overlaps *anywhere* downstream, even if the
336  // overlap is after the scatter has been fully gathered back up.)
337  // This prevents deadlocks involving one trigger claiming one branch and the other trigger claiming another
338  // (https://b33p.net/kosada/node/6696, https://b33p.net/kosada/node/12503, https://b33p.net/kosada/node/16202).
339 
340  bool hasGatherOverlappedByAnotherTrigger = graph->hasScatterPartiallyOverlappedByAnotherTrigger(node, trigger);
341 
342  // Wait for either all nodes downstream of the node or the nodes directly connected to the node.
343  vector<VuoCompilerNode *> nodesToWaitOn =
344  (hasGatherOverlappedByAnotherTrigger ?
345  graph->getNodesDownstream(node, trigger) :
346  graph->getNodesImmediatelyDownstream(node, trigger));
347 
348  return nodesToWaitOn;
349 }
350 
354 void VuoCompilerBitcodeGenerator::makeOrderedTypes(void)
355 {
356  for (VuoCompilerNode *node : graph->getNodes())
357  {
358  vector<VuoPort *> inputPorts = node->getBase()->getInputPorts();
359  vector<VuoPort *> outputPorts = node->getBase()->getOutputPorts();
360  vector<VuoPort *> ports;
361  ports.insert(ports.end(), inputPorts.begin(), inputPorts.end());
362  ports.insert(ports.end(), outputPorts.begin(), outputPorts.end());
363 
364  for (VuoPort *port : ports)
365  {
366  VuoType *dataType = static_cast<VuoCompilerPort *>(port->getCompiler())->getDataVuoType();
367 
368  if (dataType)
369  {
370  vector<VuoCompilerType *>::iterator typeIter = find(orderedTypes.begin(), orderedTypes.end(), dataType->getCompiler());
371  if (typeIter == orderedTypes.end())
372  orderedTypes.push_back(dataType->getCompiler());
373  }
374  }
375  }
376 }
377 
381 void VuoCompilerBitcodeGenerator::makePortContextInfo(void)
382 {
383  for (VuoCompilerNode *node : graph->getNodes())
384  {
385  vector<VuoPort *> inputPorts = node->getBase()->getInputPorts();
386  vector<VuoPort *> outputPorts = node->getBase()->getOutputPorts();
387  vector<VuoPort *> ports;
388  ports.insert(ports.end(), inputPorts.begin(), inputPorts.end());
389  ports.insert(ports.end(), outputPorts.begin(), outputPorts.end());
390  for (size_t i = 0; i < ports.size(); ++i)
391  {
392  VuoCompilerPort *port = static_cast<VuoCompilerPort *>( ports[i]->getCompiler() );
393 
394  port->setNodeIdentifier( node->getIdentifier() );
395  port->setIndexInPortContexts(i);
396  }
397  }
398 }
399 
403 void VuoCompilerBitcodeGenerator::makeSubcompositionModelPorts(void)
404 {
405  Module module("", getGlobalContext());
406 
407  vector<VuoPublishedPort *> publishedInputPorts = composition->getBase()->getPublishedInputPorts();
408  vector<VuoPublishedPort *> publishedOutputPorts = composition->getBase()->getPublishedOutputPorts();
409  modelInputPorts.insert( modelInputPorts.end(), publishedInputPorts.begin(), publishedInputPorts.end() );
410  modelOutputPorts.insert( modelOutputPorts.end(), publishedOutputPorts.begin(), publishedOutputPorts.end() );
411 
412  set<string> publishedOutputTriggerNames = graph->getPublishedOutputTriggers();
413 
414  for (size_t i = 0; i < modelOutputPorts.size(); ++i)
415  {
416  string portName = modelOutputPorts[i]->getClass()->getName();
417  if (publishedOutputTriggerNames.find(portName) != publishedOutputTriggerNames.end())
418  {
419  VuoType *dataType = static_cast<VuoCompilerPortClass *>( modelOutputPorts[i]->getClass()->getCompiler() )->getDataVuoType();
420  FunctionType *functionType = VuoCompilerCodeGenUtilities::getFunctionType(&module, dataType);
421  PointerType *pointerToFunctionType = PointerType::get(functionType, 0);
422  VuoCompilerTriggerPortClass *modelTriggerPortClass = new VuoCompilerTriggerPortClass(portName, pointerToFunctionType);
423  modelTriggerPortClass->setDataVuoType(dataType);
424  VuoCompilerPort *modelTriggerPort = modelTriggerPortClass->newPort();
425  modelOutputPorts[i] = modelTriggerPort->getBase();
426  }
427  }
428 }
429 
433 void VuoCompilerBitcodeGenerator::makeDependencies(void)
434 {
435  // Make sure all loading of dependencies for makeDependencies_Pro() happens before we get on llvmQueue.
436  dependencies = compiler->getDirectDependenciesForComposition(composition);
437 
438 #if VUO_PRO
439  makeDependencies_Pro();
440 #endif
441 
442  // Make sure all subcompositions needed by generateTriggerFunctions() are loaded before we get on llvmQueue.
443  compiler->getDependenciesForComposition(composition);
444 }
445 
454 {
455  bool isStatefulComposition = false;
456  for (VuoCompilerNode *node : graph->getNodes())
457  {
458  if (node->getBase()->getNodeClass()->getCompiler()->isStateful())
459  {
460  isStatefulComposition = true;
461  break;
462  }
463  }
464 
465  constantStrings.clear();
466  for (VuoCompilerNode *node : orderedNodes)
467  node->setConstantStringCache(&constantStrings);
468 
469  module = new Module(moduleKey, getGlobalContext());
470 
471  generateCompositionMetadata();
472 
473  generateTriggerFunctions();
474 
475  if (! isTopLevelComposition)
476  generateNodeEventFunction(isStatefulComposition);
477 
478  if (isStatefulComposition)
479  {
480  generateNodeInstanceInitFunction();
481  generateNodeInstanceFiniFunction();
482  generateNodeInstanceTriggerStartFunction();
483  if (! isTopLevelComposition)
484  generateNodeInstanceTriggerUpdateFunction();
485  }
486 
487  generateNodeInstanceTriggerStopFunction();
488 
489  generateCompositionReleasePortDataFunction();
490 
491  generateCompositionGetPortValueFunction();
492  generateCompositionSetPortValueFunction();
493  generateCompositionFireTriggerPortEventFunction();
494 
495  generateCompositionSetPublishedInputPortValueFunction();
496 
497  generateCompositionCreateContextForNodeFunction();
498  generateCompositionAddNodeMetadataFunction();
499  generateCompositionPerformDataOnlyTransmissionsFunction();
500 
501  generateCompositionWaitForNodeFunction();
502 
503  if (isTopLevelComposition)
504  {
505  generateShouldShowSplashWindowFunction(compiler->shouldShowSplashWindow());
506 
507  generateAllocation();
508  generateSetupFunction(isStatefulComposition);
509  generateCleanupFunction();
510 
511  generateInstanceInitFunction(isStatefulComposition);
512  generateInstanceFiniFunction(isStatefulComposition);
513  generateInstanceTriggerStartFunction(isStatefulComposition);
514  generateInstanceTriggerStopFunction(isStatefulComposition);
515 
516  generateSetInputPortValueFunction();
517 
518  generateGetPublishedPortCountFunction(true);
519  generateGetPublishedPortCountFunction(false);
520  generateGetPublishedPortNamesFunction(true);
521  generateGetPublishedPortNamesFunction(false);
522  generateGetPublishedPortTypesFunction(true);
523  generateGetPublishedPortTypesFunction(false);
524  generateGetPublishedPortDetailsFunction(true);
525  generateGetPublishedPortDetailsFunction(false);
526  generateGetPublishedPortValueFunction(true);
527  generateGetPublishedPortValueFunction(false);
528  generateSetPublishedInputPortValueFunction();
529  generateFirePublishedInputPortEventFunction();
530  }
531 
532  composition->setModule(module);
533 
534  return module;
535 }
536 
540 void VuoCompilerBitcodeGenerator::generateCompositionMetadata(void)
541 {
542  json_object *metadataJson = json_object_new_object();
543  json_object *nodeMetadataJson = json_object_new_object();
544 
545  string title = composition->getBase()->getMetadata()->getCustomizedName();
546  if (title.empty())
547  {
548  string nodeClassNamePart = VuoStringUtilities::split(moduleKey, '.').back();
549  title = VuoStringUtilities::expandCamelCase(nodeClassNamePart);
550  }
551  json_object_object_add(metadataJson, "title", json_object_new_string(title.c_str()));
552 
553  string description = composition->getBase()->getMetadata()->getDescription();
554  json_object_object_add(metadataJson, "description", json_object_new_string(description.c_str()));
555 
556  json_object *keywordsJson = json_object_new_array();
557  for (const string &keyword : composition->getBase()->getMetadata()->getKeywords())
558  json_object_array_add(keywordsJson, json_object_new_string(keyword.c_str()));
559  json_object_object_add(metadataJson, "keywords", keywordsJson);
560 
561  string version = composition->getBase()->getMetadata()->getVersion();
562  if (! version.empty())
563  json_object_object_add(metadataJson, "version", json_object_new_string(version.c_str()));
564 
565  json_object *dependenciesJson = json_object_new_array();
566  for (const string &dependency : dependencies)
567  json_object_array_add(dependenciesJson, json_object_new_string(dependency.c_str()));
568  json_object_object_add(metadataJson, "dependencies", dependenciesJson);
569 
570  if (! isTopLevelComposition)
571  {
572 #if VUO_PRO
573  generateCompositionMetadata_Pro(nodeMetadataJson);
574 #endif
575 
576  json_object *triggersJson = json_object_new_array();
577  for (VuoCompilerTriggerPort *trigger : graph->getTriggerPorts())
578  {
579  VuoCompilerNode *triggerNode = graph->getNodeForTriggerPort(trigger);
580  json_object *t = VuoCompilerTriggerDescription::getJson(triggerNode, trigger, graph);
581  json_object_array_add(triggersJson, t);
582  }
583  for (VuoCompilerNode *node : graph->getNodes())
584  {
585  VuoCompilerNodeClass *nodeClass = node->getBase()->getNodeClass()->getCompiler();
586  vector<VuoCompilerTriggerDescription *> triggersInSubcomposition = nodeClass->getTriggerDescriptions();
587  for (VuoCompilerTriggerDescription *triggerInSubcomposition : triggersInSubcomposition)
588  {
589  json_object *t = triggerInSubcomposition->getJsonWithinSubcomposition(node);
590  json_object_array_add(triggersJson, t);
591  }
592  }
593  json_object_object_add(nodeMetadataJson, "triggers", triggersJson);
594 
595  json_object *nodesJson = json_object_new_object();
596  for (VuoCompilerNode *node : orderedNodes)
597  {
598  json_object *nodeClassNameJson = json_object_new_string(node->getBase()->getNodeClass()->getClassName().c_str());
599  json_object_object_add(nodesJson, node->getIdentifier().c_str(), nodeClassNameJson);
600  }
601  json_object_object_add(nodeMetadataJson, "nodes", nodesJson);
602  }
603 
604  json_object_object_add(metadataJson, "node", nodeMetadataJson);
605 
606  string metadata = json_object_to_json_string_ext(metadataJson, JSON_C_TO_STRING_PLAIN);
607  json_object_put(metadataJson);
608 
609  VuoCompilerCodeGenUtilities::generateModuleMetadata(module, metadata, moduleKey);
610 }
611 
617 void VuoCompilerBitcodeGenerator::generateShouldShowSplashWindowFunction(bool shouldShow)
618 {
619  IntegerType *returnType = IntegerType::get(module->getContext(), 8);
620  FunctionType *functionType = FunctionType::get(returnType, false);
621  Function *function = Function::Create(functionType, GlobalValue::ExternalLinkage, "vuoShouldShowSplashWindow", module);
622  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
623  Value *boolValue = ConstantInt::get(returnType, shouldShow);
624  ReturnInst::Create(module->getContext(), boolValue, block);
625 }
626 
633 void VuoCompilerBitcodeGenerator::generateCompositionAddNodeMetadataFunction(void)
634 {
636  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
637 
638  Function::arg_iterator args = function->arg_begin();
639  Value *compositionStateValue = args++;
640  compositionStateValue->setName("compositionState");
641 
642  Function *compositionCreateContextForNodeFunction = VuoCompilerCodeGenUtilities::getCompositionCreateContextForNodeFunction(module);
643  Function *compositionSetPortValueFunction = VuoCompilerCodeGenUtilities::getCompositionSetPortValueFunction(module);
644  Function *compositionGetPortValueFunction = VuoCompilerCodeGenUtilities::getCompositionGetPortValueFunction(module);
645  Function *compositionFireTriggerPortEventFunction = VuoCompilerCodeGenUtilities::getCompositionFireTriggerPortEventFunction(module);
646  Function *releasePortDataFunction = VuoCompilerCodeGenUtilities::getCompositionReleasePortDataFunction(module);
647 
648  for (vector<VuoCompilerNode *>::iterator i = orderedNodes.begin(); i != orderedNodes.end(); ++i)
649  {
650  VuoCompilerNode *node = *i;
651 
652  node->generateAddMetadata(module, block, compositionStateValue, orderedTypes, compositionCreateContextForNodeFunction,
653  compositionSetPortValueFunction, compositionGetPortValueFunction, compositionFireTriggerPortEventFunction,
654  releasePortDataFunction);
655  }
656 
657  ReturnInst::Create(module->getContext(), block);
658 }
659 
666 void VuoCompilerBitcodeGenerator::generateCompositionCreateContextForNodeFunction(void)
667 {
669  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, NULL);
670  BasicBlock *finalBlock = BasicBlock::Create(module->getContext(), "final", function, NULL);
671 
672  Function::arg_iterator args = function->arg_begin();
673  Value *nodeIndexValue = args++;
674  nodeIndexValue->setName("nodeIndex");
675 
676  PointerType *pointerToNodeContext = PointerType::get(VuoCompilerCodeGenUtilities::getNodeContextType(module), 0);
677  AllocaInst *nodeContextVariable = new AllocaInst(pointerToNodeContext, "nodeContext", initialBlock);
678 
679  vector< pair<BasicBlock *, BasicBlock *> > blocksForIndex;
680 
681  for (size_t i = 0; i < orderedNodes.size(); ++i)
682  {
683  VuoCompilerNode *node = orderedNodes[i];
684 
685  BasicBlock *block = BasicBlock::Create(module->getContext(), node->getIdentifier(), function, NULL);
686  Value *nodeContextValue = node->generateCreateContext(module, block);
687  new StoreInst(nodeContextValue, nodeContextVariable, block);
688 
689  blocksForIndex.push_back(make_pair(block, block));
690  }
691 
692  VuoCompilerCodeGenUtilities::generateIndexMatchingCode(module, function, initialBlock, finalBlock, nodeIndexValue, blocksForIndex);
693 
694  Value *nodeContextValue = new LoadInst(nodeContextVariable, "", false, finalBlock);
695  ReturnInst::Create(module->getContext(), nodeContextValue, finalBlock);
696 }
697 
706 void VuoCompilerBitcodeGenerator::generateCompositionPerformDataOnlyTransmissionsFunction(void)
707 {
709  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
710 
711  Function::arg_iterator args = function->arg_begin();
712  Value *compositionStateValue = args++;
713  compositionStateValue->setName("compositionState");
714 
715  // Copy data along cables supporting data-only transmission at this level of the composition.
716 
718  generateDataOnlyTransmissionFromNode(function, block, compositionStateValue, node, false, false, false);
719 
720  // For each subcomposition node…
721 
722  for (VuoCompilerNode *node : orderedNodes)
723  {
724  Function *subcompositionFunctionSrc = node->getBase()->getNodeClass()->getCompiler()->getCompositionPerformDataOnlyTransmissionsFunction();
725  if (subcompositionFunctionSrc)
726  {
727  Value *runtimeStateValue = VuoCompilerCodeGenUtilities::generateGetCompositionStateRuntimeState(module, block, compositionStateValue);
728  Value *compositionIdentifierValue = VuoCompilerCodeGenUtilities::generateGetCompositionStateCompositionIdentifier(module, block, compositionStateValue);
729  Value *subcompositionIdentifierValue = node->generateSubcompositionIdentifierValue(module, block, compositionIdentifierValue);
730  Value *subcompositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, runtimeStateValue, subcompositionIdentifierValue);
731  Value *subcompositionStateValueDst = VuoCompilerCodeGenUtilities::convertArgumentToParameterType(subcompositionStateValue, subcompositionFunctionSrc, 0, nullptr, module, block);
732 
733  // Copy the subcomposition node's input port values to the subcomposition's published input node's input ports.
734 
735  Function *setPublishedInputPortValueFunctionSrc = node->getBase()->getNodeClass()->getCompiler()->getCompositionSetPublishedInputPortValueFunction();
736  Function *setPublishedInputPortValueFunctionDst = VuoCompilerModule::declareFunctionInModule(module, setPublishedInputPortValueFunctionSrc);
737  Value *falseValue = ConstantInt::get(setPublishedInputPortValueFunctionDst->getFunctionType()->getParamType(3), 0);
738 
739  for (VuoPort *inputPort : node->getBase()->getInputPorts())
740  {
741  VuoCompilerInputEventPort *inputEventPort = static_cast<VuoCompilerInputEventPort *>(inputPort->getCompiler());
742  VuoCompilerInputData *inputData = inputEventPort->getData();
743  if (inputData)
744  {
745  Value *inputPortNameValue = constantStrings.get(module, inputPort->getClass()->getName());
746  Value *dataValue = constantStrings.get(module, inputData->getInitialValue());
747 
748  vector<Value *> args;
749  args.push_back(subcompositionStateValueDst);
750  args.push_back(inputPortNameValue);
751  args.push_back(dataValue);
752  args.push_back(falseValue);
753  CallInst::Create(setPublishedInputPortValueFunctionDst, args, "", block);
754  }
755  }
756 
757  // Call recursively for the subcomposition.
758 
759  Function *subcompositionFunctionDst = VuoCompilerModule::declareFunctionInModule(module, subcompositionFunctionSrc);
760  CallInst::Create(subcompositionFunctionDst, subcompositionStateValueDst, "", block);
761 
762  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, subcompositionStateValue);
763  VuoCompilerCodeGenUtilities::generateFreeCall(module, block, subcompositionIdentifierValue);
764  }
765  }
766 
767  ReturnInst::Create(module->getContext(), block);
768 }
769 
775 void VuoCompilerBitcodeGenerator::generateCompositionReleasePortDataFunction(void)
776 {
778  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, NULL);
779  BasicBlock *finalBlock = BasicBlock::Create(module->getContext(), "final", function, NULL);
780 
781  Function::arg_iterator args = function->arg_begin();
782  Value *portAddressAsVoidPointer = args++;
783  portAddressAsVoidPointer->setName("portData");
784  Value *typeIndexValue = args++;
785  typeIndexValue->setName("typeIndex");
786 
787  vector< pair<BasicBlock *, BasicBlock *> > blocksForIndex;
788 
789  for (vector<VuoCompilerType *>::iterator i = orderedTypes.begin(); i != orderedTypes.end(); ++i)
790  {
791  VuoCompilerType *type = *i;
792 
793  BasicBlock *block = BasicBlock::Create(module->getContext(), type->getBase()->getModuleKey(), function, NULL);
794  Value *portAddress = new BitCastInst(portAddressAsVoidPointer, PointerType::get(type->getType(), 0), "", block);
795  Value *portValue = new LoadInst(portAddress, "", false, block);
796  type->generateReleaseCall(module, block, portValue);
797 
798  blocksForIndex.push_back(make_pair(block, block));
799  }
800 
801  VuoCompilerCodeGenUtilities::generateIndexMatchingCode(module, function, initialBlock, finalBlock, typeIndexValue, blocksForIndex);
802 
803  ReturnInst::Create(module->getContext(), finalBlock);
804 }
805 
809 void VuoCompilerBitcodeGenerator::generateSetInputDataFromNodeFunctionArguments(Function *function, BasicBlock *&block, Value *compositionStateValue,
810  map<VuoPort *, size_t> indexOfParameter,
811  map<VuoPort *, size_t> indexOfEventParameter,
812  bool shouldWaitForDataOnlyDownstreamNodes,
813  bool shouldUpdateTriggers, bool shouldSendTelemetry)
814 {
815  VuoCompilerNode *publishedInputNode = graph->getPublishedInputNode();
816  if (! publishedInputNode)
817  return;
818 
819  Value *publishedNodeContextValue = publishedInputNode->generateGetContext(module, block, compositionStateValue);
820 
821  vector<VuoPublishedPort *> publishedInputPorts = composition->getBase()->getPublishedInputPorts();
822  vector<VuoCompilerInputEventPort *> inputEventPorts;
823 
824  // Copy data from the function arguments to the published input node's input ports.
825 
826  for (size_t i = 0; i < publishedInputPorts.size(); ++i)
827  {
828  VuoPublishedPort *publishedInputPort = publishedInputPorts[i];
829 
830  VuoPort *inputPort = graph->getInputPortOnPublishedInputNode(i);
831  VuoCompilerInputEventPort *inputEventPort = static_cast<VuoCompilerInputEventPort *>( inputPort->getCompiler() );
832  inputEventPorts.push_back(inputEventPort);
833 
834  if (publishedInputPort->getClass()->getPortType() == VuoPortClass::dataAndEventPort)
835  {
836  size_t dataArgIndex = indexOfParameter[ modelInputPorts[i] ];
837  VuoCompilerType *type = static_cast<VuoCompilerPort *>( publishedInputPort->getCompiler() )->getDataVuoType()->getCompiler();
838 
839  // If the argument is a struct that would normally be passed "byval", it's not "byval" here.
840  // Instead, the Vuo compiler has implemented the "byval" semantics in the caller, which
841  // has passed a struct pointer that is effectively passed by value but not marked as such.
842  //
843  // This is a workaround for a bug where LLVM would sometimes give the node function body
844  // an invalid value for a "byval" struct argument. https://b33p.net/kosada/node/11386
845  Value *dataArg;
846  if (type->getType()->isStructTy() &&
847  type->getFunctionParameterAttributes().hasAttrSomewhere(Attribute::ByVal))
848  {
849  Value *argAsPointerToOtherType = VuoCompilerCodeGenUtilities::getArgumentAtIndex(function, dataArgIndex);
850  Value *argAsPointer = new BitCastInst(argAsPointerToOtherType, type->getType()->getPointerTo(), "", block);
851  dataArg = new LoadInst(argAsPointer, "", block);
852  }
853  else
854  {
855  dataArg = VuoCompilerCodeGenUtilities::unlowerArgument(type, function, dataArgIndex, module, block);
856  }
857 
858  inputEventPort->generateReplaceData(module, block, publishedNodeContextValue, dataArg);
859  }
860  }
861 
862  // Transmit data through the published input node and onward through the published input cables.
863  // (This temporarily sets an event on all of the published input node's input ports.)
864 
865  generateDataOnlyTransmissionFromNode(function, block, compositionStateValue, publishedInputNode,
866  shouldWaitForDataOnlyDownstreamNodes, shouldUpdateTriggers, shouldSendTelemetry);
867 
868  // Copy events from the function arguments to the published input node's input ports.
869 
870  for (size_t i = 0; i < publishedInputPorts.size(); ++i)
871  {
872  VuoCompilerInputEventPort *inputEventPort = inputEventPorts[i];
873 
874  map<VuoPort *, size_t> *indexMap = (inputEventPort->getBase()->getClass()->getPortType() == VuoPortClass::dataAndEventPort ?
875  &indexOfEventParameter :
876  &indexOfParameter);
877 
878  auto foundIndex = indexMap->find( modelInputPorts[i] );
879  if (foundIndex != indexMap->end())
880  {
881  size_t eventArgIndex = foundIndex->second;
882  Value *eventArg = VuoCompilerCodeGenUtilities::getArgumentAtIndex(function, eventArgIndex);
883 
884  inputEventPort->generateStoreEvent(module, block, publishedNodeContextValue, eventArg);
885  }
886  }
887 }
888 
897 void VuoCompilerBitcodeGenerator::generateNodeEventFunction(bool isStatefulComposition)
898 {
899  vector<VuoPort *> modelPorts;
900  modelPorts.insert(modelPorts.end(), modelInputPorts.begin(), modelInputPorts.end());
901  modelPorts.insert(modelPorts.end(), modelOutputPorts.begin(), modelOutputPorts.end());
902 
903  vector<VuoPublishedPort *> publishedInputPorts = composition->getBase()->getPublishedInputPorts();
904  vector<VuoPublishedPort *> publishedOutputPorts = composition->getBase()->getPublishedOutputPorts();
905  vector<VuoPublishedPort *> publishedPorts;
906  publishedPorts.insert(publishedPorts.end(), publishedInputPorts.begin(), publishedInputPorts.end());
907  publishedPorts.insert(publishedPorts.end(), publishedOutputPorts.begin(), publishedOutputPorts.end());
908 
909  map<VuoPort *, string> displayNamesForPorts;
910  map<VuoPort *, json_object *> detailsForPorts;
911  for (size_t i = 0; i < modelPorts.size(); ++i)
912  {
913  VuoPort *modelPort = modelPorts[i];
914  VuoPublishedPort *publishedPort = publishedPorts[i];
915 
916  string portName = modelPort->getClass()->getName();
917  bool isAllCaps = true;
918  for (size_t j = 0; j < portName.length(); ++j)
919  if (! isupper(portName[j]))
920  {
921  isAllCaps = false;
922  break;
923  }
924  if (isAllCaps)
925  displayNamesForPorts[modelPort] = portName;
926 
927  detailsForPorts[modelPort] = static_cast<VuoCompilerPortClass *>( publishedPort->getClass()->getCompiler() )->getDetails();
928  }
929 
930  map<VuoPort *, string> defaultValuesForInputPorts;
931  map<VuoPort *, VuoPortClass::EventBlocking> eventBlockingForInputPorts;
932  for (size_t i = 0; i < publishedInputPorts.size(); ++i)
933  {
934  VuoPublishedPort *publishedInputPort = publishedInputPorts[i];
935 
936  string defaultValue = static_cast<VuoCompilerPublishedPort *>( publishedInputPort->getCompiler() )->getInitialValue();
937  if (! defaultValue.empty())
938  defaultValuesForInputPorts[publishedInputPort] = defaultValue;
939 
940  eventBlockingForInputPorts[publishedInputPort] = graph->getPublishedInputEventBlocking(i);
941  }
942 
943  map<VuoPort *, size_t> indexOfParameter;
944  map<VuoPort *, size_t> indexOfEventParameter;
945  Function *function = VuoCompilerCodeGenUtilities::getNodeEventFunction(module, moduleKey, true, isStatefulComposition,
947  modelInputPorts, modelOutputPorts,
948  detailsForPorts, displayNamesForPorts,
949  defaultValuesForInputPorts, eventBlockingForInputPorts,
950  indexOfParameter, indexOfEventParameter, constantStrings);
951  BasicBlock *block = &(function->getEntryBlock());
952 
954  if (! trigger)
955  {
956  ReturnInst::Create(module->getContext(), block);
957  return;
958  }
959 
960  VuoCompilerNode *triggerNode = graph->getNodeForTriggerPort(trigger);
961 
962  Value *compositionStateValue = function->arg_begin();
963  Value *compositionContextValue = VuoCompilerCodeGenUtilities::generateGetCompositionContext(module, block, compositionStateValue);
964 
965  // Get the event ID passed down from the composition containing this subcomposition node.
966 
967  Value *eventIdValue = VuoCompilerCodeGenUtilities::generateGetOneExecutingEvent(module, block, compositionContextValue);
968 
969  // Claim all necessary downstream nodes.
970 
971  vector<VuoCompilerNode *> triggerWaitNodes = getNodesToWaitOnBeforeTransmission(trigger);
972  generateWaitForNodes(module, function, block, compositionStateValue, triggerWaitNodes, eventIdValue);
973 
974  // Set the data and event for each input port on the published input node from the input arguments.
975 
976  bool hasClaimedNodesDownstreamOfPublishedInputNode = (triggerWaitNodes.size() > 2);
977  generateSetInputDataFromNodeFunctionArguments(function, block, compositionStateValue, indexOfParameter, indexOfEventParameter,
978  ! hasClaimedNodesDownstreamOfPublishedInputNode, true, true);
979 
980  // Wait for the event to reach the published output node (if any) and all other leaf nodes — part 1.
981 
982  Value *subcompositionOutputGroupValue = VuoCompilerCodeGenUtilities::generateGetNodeContextExecutingGroup(module, block, compositionContextValue);
983  VuoCompilerCodeGenUtilities::generateEnterDispatchGroup(module, block, subcompositionOutputGroupValue);
984 
985  // Fire an event from the published input trigger.
986 
987  Value *triggerNodeContextValue = triggerNode->generateGetContext(module, block, compositionStateValue);
988  Value *triggerFunctionValue = trigger->generateLoadFunction(module, block, triggerNodeContextValue);
989  CallInst::Create(triggerFunctionValue, "", block);
990 
991  // Wait for the event to reach the published output node (if any) and all other leaf nodes — part 2.
992 
993  VuoCompilerCodeGenUtilities::generateWaitForDispatchGroup(module, block, subcompositionOutputGroupValue);
994 
995  // Set each output argument from the published output port values.
996 
997  VuoCompilerNode *publishedOutputNode = graph->getPublishedOutputNode();
998  Value *publishedOutputNodeContext = publishedOutputNode->generateGetContext(module, block, compositionStateValue);
999  for (size_t i = 0; i < modelOutputPorts.size(); ++i)
1000  {
1001  VuoPort *modelOutputPort = modelOutputPorts[i];
1002  VuoPortClass::PortType portType = modelOutputPort->getClass()->getPortType();
1003 
1004  if (portType == VuoPortClass::dataAndEventPort || portType == VuoPortClass::eventOnlyPort)
1005  {
1006  VuoPort *inputPort = graph->getInputPortOnPublishedOutputNode(i);
1007  bool hasEventParameter = false;
1008  size_t eventIndex = 0;
1009 
1010  if (portType == VuoPortClass::dataAndEventPort)
1011  {
1012  size_t index = indexOfParameter[ modelOutputPort ];
1013  Value *outputArg = VuoCompilerCodeGenUtilities::getArgumentAtIndex(function, index);
1014 
1015  Value *value = static_cast<VuoCompilerEventPort *>( inputPort->getCompiler() )->generateLoadData(module, block, publishedOutputNodeContext);
1016  new StoreInst(value, outputArg, block);
1017 
1018  map<VuoPort *, size_t>::iterator iter = indexOfEventParameter.find(modelOutputPort);
1019  if (iter != indexOfEventParameter.end())
1020  {
1021  hasEventParameter = true;
1022  eventIndex = iter->second;
1023  }
1024  }
1025  else
1026  {
1027  hasEventParameter = true;
1028  eventIndex = indexOfParameter[ modelOutputPort ];
1029  }
1030 
1031  if (hasEventParameter)
1032  {
1033  Value *outputArg = VuoCompilerCodeGenUtilities::getArgumentAtIndex(function, eventIndex);
1034 
1035  Value *eventValue = VuoCompilerCodeGenUtilities::generateGetNodeContextOutputEvent(module, block, compositionContextValue, i);
1036  new StoreInst(eventValue, outputArg, block);
1037  }
1038  }
1039  }
1040 
1041  // Signal the published output node.
1042 
1043  generateSignalForNodes(module, block, compositionStateValue, vector<VuoCompilerNode *>(1, publishedOutputNode));
1044 
1045  ReturnInst::Create(module->getContext(), block);
1046 }
1047 
1053 void VuoCompilerBitcodeGenerator::generateNodeInstanceInitFunction(void)
1054 {
1055  vector<VuoPort *> inputPorts;
1056  if (! isTopLevelComposition)
1057  inputPorts = modelInputPorts;
1058 
1059  map<VuoPort *, size_t> indexOfParameter;
1060  Function *function = VuoCompilerCodeGenUtilities::getNodeInstanceInitFunction(module, moduleKey, true,
1062  inputPorts, indexOfParameter, constantStrings);
1063  BasicBlock *block = &(function->getEntryBlock());
1064 
1065  Value *compositionStateValue = function->arg_begin();
1066 
1067  if (! isTopLevelComposition)
1068  generateSetInputDataFromNodeFunctionArguments(function, block, compositionStateValue, indexOfParameter, map<VuoPort *, size_t>(),
1069  false, false, false);
1070 
1071  for (VuoCompilerNode *node : graph->getNodes())
1072  {
1073  if (node->getBase()->getNodeClass()->getCompiler()->isStateful())
1074  {
1075  BasicBlock *initBlock = NULL;
1076  BasicBlock *nextBlock = NULL;
1077  Value *replacementJsonValue = NULL;
1079  compositionStateValue, block, initBlock, nextBlock,
1080  constantStrings, replacementJsonValue);
1081 
1082  node->generateInitFunctionCall(module, initBlock, compositionStateValue);
1083 
1084  VuoCompilerCodeGenUtilities::generateJsonObjectPut(module, initBlock, replacementJsonValue);
1085 
1086  BranchInst::Create(nextBlock, initBlock);
1087  block = nextBlock;
1088  }
1089  }
1090 
1091  PointerType *instanceDataType = static_cast<PointerType *>( function->getReturnType() );
1092  ConstantPointerNull *nullInstanceDataValue = ConstantPointerNull::get(instanceDataType);
1093  ReturnInst::Create(module->getContext(), nullInstanceDataValue, block);
1094 }
1095 
1102 void VuoCompilerBitcodeGenerator::generateNodeInstanceFiniFunction(void)
1103 {
1104  Function *function = VuoCompilerCodeGenUtilities::getNodeInstanceFiniFunction(module, moduleKey,
1106  constantStrings);
1107  BasicBlock *block = &(function->getEntryBlock());
1108 
1109  Value *compositionStateValue = function->arg_begin();
1110 
1111  for (VuoCompilerNode *node : graph->getNodes())
1112  {
1113  if (node->getBase()->getNodeClass()->getCompiler()->isStateful())
1114  {
1115  BasicBlock *finiBlock = NULL;
1116  BasicBlock *nextBlock = NULL;
1117  Value *replacementJsonValue = NULL;
1119  compositionStateValue, block, finiBlock, nextBlock,
1120  constantStrings, replacementJsonValue);
1121 
1122  node->generateFiniFunctionCall(module, finiBlock, compositionStateValue);
1123 
1124  VuoCompilerCodeGenUtilities::generateJsonObjectPut(module, finiBlock, replacementJsonValue);
1125 
1126  BranchInst::Create(nextBlock, finiBlock);
1127  block = nextBlock;
1128  }
1129  }
1130 
1131  ReturnInst::Create(module->getContext(), block);
1132 }
1133 
1141 void VuoCompilerBitcodeGenerator::generateNodeInstanceTriggerStartFunction(void)
1142 {
1143  vector<VuoPort *> inputPorts;
1144  if (! isTopLevelComposition)
1145  inputPorts = modelInputPorts;
1146 
1147  map<VuoPort *, size_t> indexOfParameter;
1148  Function *function = VuoCompilerCodeGenUtilities::getNodeInstanceTriggerStartFunction(module, moduleKey,
1150  inputPorts, indexOfParameter, constantStrings);
1151  BasicBlock *block = &(function->getEntryBlock());
1152 
1153  Value *compositionStateValue = function->arg_begin();
1154 
1155  if (! isTopLevelComposition)
1156  generateSetInputDataFromNodeFunctionArguments(function, block, compositionStateValue, indexOfParameter, map<VuoPort *, size_t>(),
1157  false, false, false);
1158 
1159  // Since a node's nodeInstanceTriggerStart() function can generate an event,
1160  // make sure trigger functions wait until all nodes' init functions have completed.
1161  generateWaitForNodes(module, function, block, compositionStateValue, orderedNodes);
1162 
1163  for (VuoCompilerNode *node : graph->getNodes())
1164  {
1165  if (node->getBase()->getNodeClass()->getCompiler()->isStateful())
1166  {
1167  // { /* call nodeInstanceTriggerStart() for node */ }
1168  node->generateCallbackStartFunctionCall(module, block, compositionStateValue);
1169  }
1170  }
1171 
1172  generateSignalForNodes(module, block, compositionStateValue, orderedNodes);
1173 
1174  ReturnInst::Create(module->getContext(), block);
1175 }
1176 
1182 void VuoCompilerBitcodeGenerator::generateNodeInstanceTriggerStopFunction(void)
1183 {
1184  Function *function = VuoCompilerCodeGenUtilities::getNodeInstanceTriggerStopFunction(module, moduleKey,
1186  constantStrings);
1187  BasicBlock *block = &(function->getEntryBlock());
1188 
1189  Value *compositionStateValue = function->arg_begin();
1190 
1191  // Stop all triggers from firing events — call nodeInstanceTriggerStop() for each stateful node.
1192  generateWaitForNodes(module, function, block, compositionStateValue, orderedNodes);
1193  for (VuoCompilerNode *node : graph->getNodes())
1194  {
1195  if (node->getBase()->getNodeClass()->getCompiler()->isStateful())
1196  node->generateCallbackStopFunctionCall(module, block, compositionStateValue);
1197  }
1198  generateSignalForNodes(module, block, compositionStateValue, orderedNodes);
1199 
1200  if (isTopLevelComposition)
1201  {
1202  // Wait for any scheduled trigger workers to launch events into the composition.
1203  Value *triggerWorkersScheduledValue = VuoCompilerCodeGenUtilities::getTriggerWorkersScheduledValue(module, block, compositionStateValue);
1204  VuoCompilerCodeGenUtilities::generateWaitForDispatchGroup(module, block, triggerWorkersScheduledValue);
1205 
1206  // Wait for any in-progress events to travel through the composition.
1207  generateWaitForNodes(module, function, block, compositionStateValue, orderedNodes);
1208  generateSignalForNodes(module, block, compositionStateValue, orderedNodes);
1209  }
1210 
1211  ReturnInst::Create(module->getContext(), block);
1212 }
1213 
1219 void VuoCompilerBitcodeGenerator::generateNodeInstanceTriggerUpdateFunction(void)
1220 {
1221  map<VuoPort *, size_t> indexOfParameter;
1222  Function *function = VuoCompilerCodeGenUtilities::getNodeInstanceTriggerUpdateFunction(module, moduleKey,
1224  modelInputPorts, indexOfParameter, constantStrings);
1225  BasicBlock *block = &(function->getEntryBlock());
1226 
1227  Value *compositionStateValue = function->arg_begin();
1228 
1230  if (! trigger)
1231  {
1232  ReturnInst::Create(module->getContext(), block);
1233  return;
1234  }
1235 
1236  vector<VuoCompilerNode *> triggerWaitNodes = getNodesToWaitOnBeforeTransmission(trigger);
1237  generateWaitForNodes(module, function, block, compositionStateValue, triggerWaitNodes);
1238 
1239  bool hasClaimedNodesDownstreamOfPublishedInputNode = (triggerWaitNodes.size() > 2);
1240  generateSetInputDataFromNodeFunctionArguments(function, block, compositionStateValue, indexOfParameter, map<VuoPort *, size_t>(),
1241  ! hasClaimedNodesDownstreamOfPublishedInputNode, true, false);
1242 
1243  generateSignalForNodes(module, block, compositionStateValue, triggerWaitNodes);
1244 
1245  ReturnInst::Create(module->getContext(), block);
1246 }
1247 
1292 Value * VuoCompilerBitcodeGenerator::generateWaitForNodes(Module *module, Function *function, BasicBlock *&block,
1293  Value *compositionStateValue, vector<VuoCompilerNode *> nodes,
1294  Value *eventIdValue, bool shouldBlock)
1295 {
1296  sortNodes(nodes);
1297 
1298  if (! eventIdValue)
1299  eventIdValue = VuoCompilerCodeGenUtilities::generateGetNextEventId(module, block, compositionStateValue);
1300 
1301  Function *waitForNodeFunction = VuoCompilerCodeGenUtilities::getWaitForNodeFunction(module, moduleKey);
1302  Type *unsignedLongType = waitForNodeFunction->getFunctionType()->getParamType(1);
1303  Type *boolType = waitForNodeFunction->getFunctionType()->getParamType(3);
1304  Constant *falseValue = ConstantInt::get(boolType, 0);
1305  Constant *trueValue = ConstantInt::get(boolType, 1);
1306 
1307  if (shouldBlock)
1308  {
1309  vector<VuoCompilerNode *>::iterator prevNodeIter = orderedNodes.begin();
1310 
1311  for (vector<VuoCompilerNode *>::iterator i = nodes.begin(); i != nodes.end(); ++i)
1312  {
1313  VuoCompilerNode *node = *i;
1314 
1315  vector<VuoCompilerNode *>::iterator orderedNodeIter = find(prevNodeIter, orderedNodes.end(), node);
1316  prevNodeIter = orderedNodeIter;
1317  size_t orderedNodeIndex = orderedNodeIter - orderedNodes.begin();
1318  Constant *orderedNodeIndexValue = ConstantInt::get(unsignedLongType, orderedNodeIndex);
1319 
1320  vector<Value *> args;
1321  args.push_back(compositionStateValue);
1322  args.push_back(orderedNodeIndexValue);
1323  args.push_back(eventIdValue);
1324  args.push_back(trueValue);
1325  CallInst::Create(waitForNodeFunction, args, "", block);
1326  }
1327 
1328  return NULL;
1329  }
1330  else
1331  {
1332  AllocaInst *keepTryingVariable = new AllocaInst(IntegerType::get(module->getContext(), 1), "keepTrying", block);
1333  new StoreInst(trueValue, keepTryingVariable, block);
1334 
1335  vector<VuoCompilerNode *>::iterator prevNodeIter = orderedNodes.begin();
1336 
1337  vector<BasicBlock *> signalBlocks;
1338  for (vector<VuoCompilerNode *>::iterator i = nodes.begin(); i != nodes.end(); ++i)
1339  {
1340  VuoCompilerNode *node = *i;
1341 
1342  BasicBlock *waitBlock = block;
1343 
1344  vector<VuoCompilerNode *>::iterator orderedNodeIter = find(prevNodeIter, orderedNodes.end(), node);
1345  prevNodeIter = orderedNodeIter;
1346  size_t orderedNodeIndex = orderedNodeIter - orderedNodes.begin();
1347  Value *orderedNodeIndexValue = ConstantInt::get(unsignedLongType, orderedNodeIndex);
1348 
1349  vector<Value *> args;
1350  args.push_back(compositionStateValue);
1351  args.push_back(orderedNodeIndexValue);
1352  args.push_back(eventIdValue);
1353  args.push_back(falseValue);
1354  CallInst *keepTryingValue = CallInst::Create(waitForNodeFunction, args, "", waitBlock);
1355  new StoreInst(keepTryingValue, keepTryingVariable, waitBlock);
1356 
1357  ICmpInst *keepTryingIsFalse = new ICmpInst(*waitBlock, ICmpInst::ICMP_EQ, keepTryingValue, falseValue);
1358  BasicBlock *signalBlock = BasicBlock::Create(module->getContext(), "signal", function);
1359  BasicBlock *nextNodeBlock = BasicBlock::Create(module->getContext(), "wait", function);
1360  BranchInst::Create(signalBlock, nextNodeBlock, keepTryingIsFalse, waitBlock);
1361 
1362  signalBlocks.push_back(signalBlock);
1363  block = nextNodeBlock;
1364  }
1365 
1366  if (! signalBlocks.empty())
1367  {
1368  BranchInst::Create(signalBlocks[0], block);
1369  block = signalBlocks[0];
1370  }
1371 
1372  for (size_t i = 1; i < signalBlocks.size(); ++i)
1373  {
1374  BasicBlock *signalBlock = signalBlocks[i];
1375  VuoCompilerNode *nodeToSignal = nodes[i-1];
1376 
1377  generateSignalForNodes(module, signalBlock, compositionStateValue, vector<VuoCompilerNode *>(1, nodeToSignal));
1378 
1379  BranchInst::Create(signalBlocks[i-1], signalBlock);
1380  }
1381 
1382  Value *keepTryingValue = new LoadInst(keepTryingVariable, "", false, block);
1383 
1384  return keepTryingValue;
1385  }
1386 }
1387 
1388 
1421 void VuoCompilerBitcodeGenerator::generateCompositionWaitForNodeFunction(void)
1422 {
1423  Function *function = VuoCompilerCodeGenUtilities::getWaitForNodeFunction(module, moduleKey);
1424  Function::arg_iterator args = function->arg_begin();
1425  Value *compositionStateValue = args++;
1426  compositionStateValue->setName("compositionState");
1427  Value *indexInOrderedNodesValue = args++;
1428  indexInOrderedNodesValue->setName("indexInOrderedNodes");
1429  Value *eventIdValue = args++;
1430  eventIdValue->setName("eventId");
1431  Value *shouldBlockValue = args++;
1432  shouldBlockValue->setName("shouldBlock");
1433 
1434 
1435  // bool keepTrying = true;
1436 
1437  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, 0);
1438 
1439  AllocaInst *keepTryingVariable = new AllocaInst(IntegerType::get(module->getContext(), 1), "keepTrying", initialBlock);
1440  ConstantInt *trueValue = ConstantInt::get(module->getContext(), APInt(1, 1));
1441  new StoreInst(trueValue, keepTryingVariable, initialBlock);
1442 
1443 
1444  // int64_t timeoutDelta = (shouldBlock ? ... : 0);
1445  // dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, timeoutDelta);
1446 
1447  Type *timeoutDeltaType = IntegerType::get(module->getContext(), 64);
1448  AllocaInst *timeoutDeltaVariable = new AllocaInst(timeoutDeltaType, "timeoutDelta", initialBlock);
1449  ICmpInst *shouldBlockIsTrue = new ICmpInst(*initialBlock, ICmpInst::ICMP_EQ, shouldBlockValue, trueValue);
1450  BasicBlock *nonZeroTimeoutBlock = BasicBlock::Create(module->getContext(), "nonZeroTimeout", function);
1451  BasicBlock *zeroTimeoutBlock = BasicBlock::Create(module->getContext(), "zeroTimeout", function);
1452  BranchInst::Create(nonZeroTimeoutBlock, zeroTimeoutBlock, shouldBlockIsTrue, initialBlock);
1453 
1454  BasicBlock *checkEventIdBlock = BasicBlock::Create(module->getContext(), "checkEventId", function);
1455 
1456  ConstantInt *nonZeroTimeoutValue = ConstantInt::get(module->getContext(), APInt(64, NSEC_PER_SEC / 1000));
1457  new StoreInst(nonZeroTimeoutValue, timeoutDeltaVariable, false, nonZeroTimeoutBlock);
1458  BranchInst::Create(checkEventIdBlock, nonZeroTimeoutBlock);
1459 
1460  ConstantInt *zeroTimeoutValue = ConstantInt::get(module->getContext(), APInt(64, 0));
1461  new StoreInst(zeroTimeoutValue, timeoutDeltaVariable, false, zeroTimeoutBlock);
1462  BranchInst::Create(checkEventIdBlock, zeroTimeoutBlock);
1463 
1464  Value *timeoutDeltaValue = new LoadInst(timeoutDeltaVariable, "", false, checkEventIdBlock);
1465  Value *timeoutValue = VuoCompilerCodeGenUtilities::generateCreateDispatchTime(module, checkEventIdBlock, timeoutDeltaValue);
1466 
1467 
1468  // NodeContext *nodeContext = vuoGetNodeContext(compositionState, indexInOrderedNodes);
1469 
1470  Value *nodeContextValue = VuoCompilerCodeGenUtilities::generateGetNodeContext(module, checkEventIdBlock,
1471  compositionStateValue, indexInOrderedNodesValue);
1472 
1473 
1474  // while (nodeContext->claimingEventId != eventId && keepTrying)
1475  // {
1476  // int ret = dispatch_semaphore_wait(nodeContext->semaphore, timeout);
1477  // if (ret == 0)
1478  // nodeContext->claimingEventId = eventId;
1479  // else if (! shouldBlock)
1480  // keepTrying = false;
1481  // }
1482 
1483  Value *claimingEventIdValue = VuoCompilerCodeGenUtilities::generateGetNodeContextClaimingEventId(module, checkEventIdBlock, nodeContextValue);
1484  ICmpInst *claimingEventIdNotEqualsEventId = new ICmpInst(*checkEventIdBlock, ICmpInst::ICMP_NE, claimingEventIdValue, eventIdValue, "");
1485  BasicBlock *checkKeepTryingBlock = BasicBlock::Create(module->getContext(), "checkKeepTrying", function);
1486  BasicBlock *finalBlock = BasicBlock::Create(module->getContext(), "doneWaitingNodeSemaphore", function);
1487  BranchInst::Create(checkKeepTryingBlock, finalBlock, claimingEventIdNotEqualsEventId, checkEventIdBlock);
1488 
1489  Value *keepTryingValue = new LoadInst(keepTryingVariable, "", false, checkKeepTryingBlock);
1490  ICmpInst *keepTryingIsTrue = new ICmpInst(*checkKeepTryingBlock, ICmpInst::ICMP_EQ, keepTryingValue, trueValue);
1491  BasicBlock *waitBlock = BasicBlock::Create(module->getContext(), "waitNodeSemaphore", function);
1492  BranchInst::Create(waitBlock, finalBlock, keepTryingIsTrue, checkKeepTryingBlock);
1493 
1494  Value *semaphoreValue = VuoCompilerCodeGenUtilities::generateGetNodeContextSemaphore(module, waitBlock, nodeContextValue);
1495  Value *retValue = VuoCompilerCodeGenUtilities::generateWaitForSemaphore(module, waitBlock, semaphoreValue, timeoutValue);
1496 
1497  Value *zeroValue = ConstantInt::get(retValue->getType(), 0);
1498  ICmpInst *retEqualsZero = new ICmpInst(*waitBlock, ICmpInst::ICMP_EQ, retValue, zeroValue, "");
1499  BasicBlock *setEventIdBlock = BasicBlock::Create(module->getContext(), "setEventId", function);
1500  BasicBlock *checkShouldBlockBlock = BasicBlock::Create(module->getContext(), "checkShouldBlock", function);
1501  BasicBlock *endWhileBlock = BasicBlock::Create(module->getContext(), "endWhile", function);
1502  BranchInst::Create(setEventIdBlock, checkShouldBlockBlock, retEqualsZero, waitBlock);
1503 
1504  VuoCompilerCodeGenUtilities::generateSetNodeContextClaimingEventId(module, setEventIdBlock, nodeContextValue, eventIdValue);
1505  BranchInst::Create(endWhileBlock, setEventIdBlock);
1506 
1507  BasicBlock *setKeepTryingBlock = BasicBlock::Create(module->getContext(), "setKeepTrying", function);
1508  BranchInst::Create(endWhileBlock, setKeepTryingBlock, shouldBlockIsTrue, checkShouldBlockBlock);
1509 
1510  Value *falseValue = ConstantInt::get(keepTryingValue->getType(), 0);
1511  new StoreInst(falseValue, keepTryingVariable, setKeepTryingBlock);
1512  BranchInst::Create(endWhileBlock, setKeepTryingBlock);
1513 
1514  BranchInst::Create(checkEventIdBlock, endWhileBlock);
1515 
1516 
1517  // return keepTrying;
1518 
1519  keepTryingValue = new LoadInst(keepTryingVariable, "", false, finalBlock);
1520  ReturnInst::Create(module->getContext(), keepTryingValue, finalBlock);
1521 }
1522 
1532 void VuoCompilerBitcodeGenerator::generateSignalForNodes(Module *module, BasicBlock *block, Value *compositionStateValue,
1533  vector<VuoCompilerNode *> nodes)
1534 {
1535  for (vector<VuoCompilerNode *>::iterator i = nodes.begin(); i != nodes.end(); ++i)
1536  {
1537  VuoCompilerNode *node = *i;
1538 
1539  Value *nodeContextValue = node->generateGetContext(module, block, compositionStateValue);
1540 
1541  ConstantInt *noEventIdConstant = VuoCompilerCodeGenUtilities::generateNoEventIdConstant(module);
1542  VuoCompilerCodeGenUtilities::generateSetNodeContextClaimingEventId(module, block, nodeContextValue, noEventIdConstant);
1543 
1544  Value *semaphoreValue = VuoCompilerCodeGenUtilities::generateGetNodeContextSemaphore(module, block, nodeContextValue);
1545  VuoCompilerCodeGenUtilities::generateSignalForSemaphore(module, block, semaphoreValue);
1546  }
1547 }
1548 
1610 void VuoCompilerBitcodeGenerator::generateCompositionGetPortValueFunction(void)
1611 {
1613 
1614  Function::arg_iterator args = function->arg_begin();
1615  Value *compositionStateValue = args++;
1616  compositionStateValue->setName("compositionState");
1617  Value *portIdentifierValue = args++;
1618  portIdentifierValue->setName("portIdentifier");
1619  Value *serializationTypeValue = args++;
1620  serializationTypeValue->setName("serializationType");
1621  Value *isThreadSafeValue = args++;
1622  isThreadSafeValue->setName("isThreadSafe");
1623 
1624 
1625  // char *ret = NULL;
1626 
1627  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, 0);
1628  PointerType *pointerToCharType = PointerType::get(IntegerType::get(module->getContext(), 8), 0);
1629 
1630  AllocaInst *retVariable = new AllocaInst(pointerToCharType, "ret", initialBlock);
1631  ConstantPointerNull *nullPointerToChar = ConstantPointerNull::get(pointerToCharType);
1632  new StoreInst(nullPointerToChar, retVariable, false, initialBlock);
1633 
1634  // void *portAddress = vuoGetDataForPort(compositionState, portIdentifier);
1635 
1636  Value *portAddressAsVoidPointer = VuoCompilerCodeGenUtilities::generateGetDataForPort(module, initialBlock, compositionStateValue, portIdentifierValue);
1637 
1638  // if (portAddress != NULL)
1639 
1640  BasicBlock *checkWaitBlock = BasicBlock::Create(module->getContext(), "checkWait", function, 0);
1641  BasicBlock *finalBlock = BasicBlock::Create(module->getContext(), "final", function, 0);
1642 
1643  ConstantPointerNull *nullPortAddress = ConstantPointerNull::get(static_cast<PointerType *>(portAddressAsVoidPointer->getType()));
1644  ICmpInst *portAddressNotEqualsNull = new ICmpInst(*initialBlock, ICmpInst::ICMP_NE, portAddressAsVoidPointer, nullPortAddress, "");
1645  BranchInst::Create(checkWaitBlock, finalBlock, portAddressNotEqualsNull, initialBlock);
1646 
1647  // dispatch_semaphore_t nodeSemaphore = vuoGetNodeSemaphoreForPort(compositionState, portIdentifier);
1648  // unsigned long typeIndex = vuoGetTypeIndexForPort(compositionState, portIdentifier);
1649 
1650  Value *nodeSemaphoreValue = VuoCompilerCodeGenUtilities::generateGetNodeSemaphoreForPort(module, checkWaitBlock, compositionStateValue, portIdentifierValue);
1651  Value *typeIndexValue = VuoCompilerCodeGenUtilities::generateGetTypeIndexForPort(module, checkWaitBlock, compositionStateValue, portIdentifierValue);
1652 
1653  // if (isThreadSafe)
1654  // dispatch_semaphore_wait(nodeSemaphore, DISPATCH_TIME_FOREVER);
1655 
1656  BasicBlock *waitBlock = BasicBlock::Create(module->getContext(), "wait", function, 0);
1657  BasicBlock *checkTypeIndexBlock = BasicBlock::Create(module->getContext(), "checkTypeIndex", function, 0);
1658  ConstantInt *falseValue = ConstantInt::get(static_cast<IntegerType *>(isThreadSafeValue->getType()), 0);
1659  ICmpInst *isThreadSafeEqualsTrue = new ICmpInst(*checkWaitBlock, ICmpInst::ICMP_NE, isThreadSafeValue, falseValue, "");
1660  BranchInst::Create(waitBlock, checkTypeIndexBlock, isThreadSafeEqualsTrue, checkWaitBlock);
1661 
1662  VuoCompilerCodeGenUtilities::generateWaitForSemaphore(module, waitBlock, nodeSemaphoreValue);
1663  BranchInst::Create(checkTypeIndexBlock, waitBlock);
1664 
1665 
1666  // if (typeIndex == 0)
1667  // {
1668  // VuoImage portValue = (VuoImage)(*portAddress);
1669  // if (serializationType == 0)
1670  // ret = VuoImage_getSummary(portValue);
1671  // else if (serializationType == 1)
1672  // ret = VuoImage_getString(portValue);
1673  // else
1674  // ret = VuoImage_getInterprocessString(portValue);
1675  // }
1676  // else if (typeIndex == 3)
1677  // {
1678  // VuoReal portValue = (VuoReal)(*portAddress);
1679  // if (serializationType == 0)
1680  // ret = VuoReal_getSummary(portValue);
1681  // else
1682  // ret = VuoReal_getString(portValue);
1683  // }
1684  // else if ...
1685 
1686  vector< pair<BasicBlock *, BasicBlock *> > blocksForIndex;
1687  for (size_t i = 0; i < orderedTypes.size(); ++i)
1688  {
1689  VuoCompilerType *type = orderedTypes[i];
1690 
1691  string typeName = type->getBase()->getModuleKey();
1692  bool hasInterprocess = type->hasInterprocessStringFunction();
1693 
1694  BasicBlock *checkSummaryBlock = BasicBlock::Create(module->getContext(), typeName + "_checkSummary", function, 0);
1695  BasicBlock *summaryBlock = BasicBlock::Create(module->getContext(), typeName + "_summary", function, 0);
1696  BasicBlock *checkStringBlock = NULL;
1697  BasicBlock *stringBlock = BasicBlock::Create(module->getContext(), typeName + "_string", function, 0);
1698  BasicBlock *interprocessBlock = NULL;
1699  BasicBlock *typeFinalBlock = BasicBlock::Create(module->getContext(), typeName + "_final", function, 0);
1700 
1701  BasicBlock *firstStringBlock = NULL;
1702  if (hasInterprocess)
1703  {
1704  checkStringBlock = BasicBlock::Create(module->getContext(), typeName + "_checkString", function, 0);
1705  interprocessBlock = BasicBlock::Create(module->getContext(), typeName + "_interprocess", function, 0);
1706  firstStringBlock = checkStringBlock;
1707  }
1708  else
1709  {
1710  firstStringBlock = stringBlock;
1711  }
1712 
1713  PointerType *pointerToType = PointerType::get(type->getType(), 0);
1714  Value *portAddress = new BitCastInst(portAddressAsVoidPointer, pointerToType, "", checkSummaryBlock);
1715  Value *portValue = new LoadInst(portAddress, "", false, checkSummaryBlock);
1716 
1717  ConstantInt *zeroValue = ConstantInt::get(static_cast<IntegerType *>(serializationTypeValue->getType()), 0);
1718  ICmpInst *serializationTypeEqualsZero = new ICmpInst(*checkSummaryBlock, ICmpInst::ICMP_EQ, serializationTypeValue, zeroValue, "");
1719  BranchInst::Create(summaryBlock, firstStringBlock, serializationTypeEqualsZero, checkSummaryBlock);
1720 
1721  Value *summaryValue = type->generateSummaryFromValueFunctionCall(module, summaryBlock, portValue);
1722  new StoreInst(summaryValue, retVariable, summaryBlock);
1723  BranchInst::Create(typeFinalBlock, summaryBlock);
1724 
1725  if (hasInterprocess)
1726  {
1727  ConstantInt *oneValue = ConstantInt::get(static_cast<IntegerType *>(serializationTypeValue->getType()), 1);
1728  ICmpInst *serializationTypeEqualsOne = new ICmpInst(*checkStringBlock, ICmpInst::ICMP_EQ, serializationTypeValue, oneValue, "");
1729  BranchInst::Create(stringBlock, interprocessBlock, serializationTypeEqualsOne, checkStringBlock);
1730  }
1731 
1732  Value *stringValue = type->generateStringFromValueFunctionCall(module, stringBlock, portValue);
1733  new StoreInst(stringValue, retVariable, stringBlock);
1734  BranchInst::Create(typeFinalBlock, stringBlock);
1735 
1736  if (hasInterprocess)
1737  {
1738  Value *interprocessValue = type->generateInterprocessStringFromValueFunctionCall(module, interprocessBlock, portValue);
1739  new StoreInst(interprocessValue, retVariable, interprocessBlock);
1740  BranchInst::Create(typeFinalBlock, interprocessBlock);
1741  }
1742 
1743  blocksForIndex.push_back( make_pair(checkSummaryBlock, typeFinalBlock) );
1744  }
1745 
1746  BasicBlock *checkSignalBlock = BasicBlock::Create(module->getContext(), "checkSignal", function, 0);
1747  VuoCompilerCodeGenUtilities::generateIndexMatchingCode(module, function, checkTypeIndexBlock, checkSignalBlock, typeIndexValue, blocksForIndex);
1748 
1749 
1750  // if (isThreadSafe)
1751  // dispatch_semaphore_signal(nodeSemaphore);
1752 
1753  BasicBlock *signalBlock = BasicBlock::Create(module->getContext(), "signal", function, 0);
1754  BranchInst::Create(signalBlock, finalBlock, isThreadSafeEqualsTrue, checkSignalBlock);
1755 
1756  VuoCompilerCodeGenUtilities::generateSignalForSemaphore(module, signalBlock, nodeSemaphoreValue);
1757  BranchInst::Create(finalBlock, signalBlock);
1758 
1759 
1760  // return ret;
1761 
1762  LoadInst *retValue = new LoadInst(retVariable, "", false, finalBlock);
1763  ReturnInst::Create(module->getContext(), retValue, finalBlock);
1764 }
1765 
1841 void VuoCompilerBitcodeGenerator::generateCompositionSetPortValueFunction(void)
1842 {
1844 
1845  Function::arg_iterator args = function->arg_begin();
1846  Value *compositionStateValue = args++;
1847  compositionStateValue->setName("compositionState");
1848  Value *portIdentifierValue = args++;
1849  portIdentifierValue->setName("portIdentifier");
1850  Value *valueAsStringValue = args++;
1851  valueAsStringValue->setName("valueAsString");
1852  Value *isThreadSafeValue = args++;
1853  isThreadSafeValue->setName("isThreadSafe");
1854  Value *shouldUpdateTriggersValue = args++;
1855  shouldUpdateTriggersValue->setName("shouldUpdateTriggers");
1856  Value *shouldSendTelemetryValue = args++;
1857  shouldSendTelemetryValue->setName("shouldSendTelemetry");
1858  Value *hasOldValue = args++;
1859  hasOldValue->setName("hasOldValue");
1860  Value *hasNewValue = args++;
1861  hasNewValue->setName("hasNewValue");
1862 
1863 
1864  // void *portAddress = vuoGetDataForPort(compositionState, portIdentifier);
1865 
1866  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, 0);
1867  Value *portAddressAsVoidPointer = VuoCompilerCodeGenUtilities::generateGetDataForPort(module, initialBlock, compositionStateValue, portIdentifierValue);
1868 
1869  // if (portAddress != NULL)
1870 
1871  BasicBlock *checkWaitBlock = BasicBlock::Create(module->getContext(), "checkWait", function, 0);
1872  BasicBlock *finalBlock = BasicBlock::Create(module->getContext(), "final", function, 0);
1873 
1874  ConstantPointerNull *nullPortAddress = ConstantPointerNull::get(static_cast<PointerType *>(portAddressAsVoidPointer->getType()));
1875  ICmpInst *portAddressNotEqualsNull = new ICmpInst(*initialBlock, ICmpInst::ICMP_NE, portAddressAsVoidPointer, nullPortAddress, "");
1876  BranchInst::Create(checkWaitBlock, finalBlock, portAddressNotEqualsNull, initialBlock);
1877 
1878  // dispatch_semaphore_t nodeSemaphore = vuoGetNodeSemaphoreForPort(compositionState, portIdentifier);
1879  // unsigned long typeIndex = vuoGetTypeIndexForPort(compositionState, portIdentifier);
1880  // unsigned long nodeIndex = vuoGetNodeIndexForPort(compositionState, portIdentifier);
1881  // char *summary = NULL;
1882 
1883  Value *nodeSemaphoreValue = VuoCompilerCodeGenUtilities::generateGetNodeSemaphoreForPort(module, checkWaitBlock, compositionStateValue, portIdentifierValue);
1884  Value *typeIndexValue = VuoCompilerCodeGenUtilities::generateGetTypeIndexForPort(module, checkWaitBlock, compositionStateValue, portIdentifierValue);
1885  Value *nodeIndexValue = VuoCompilerCodeGenUtilities::generateGetNodeIndexForPort(module, checkWaitBlock, compositionStateValue, portIdentifierValue);
1886 
1887  PointerType *pointerToCharType = PointerType::get(IntegerType::get(module->getContext(), 8), 0);
1888  AllocaInst *summaryVariable = new AllocaInst(pointerToCharType, "summary", checkWaitBlock);
1889  ConstantPointerNull *nullSummary = ConstantPointerNull::get(pointerToCharType);
1890  new StoreInst(nullSummary, summaryVariable, false, checkWaitBlock);
1891 
1892  // if (isThreadSafe)
1893  // dispatch_semaphore_wait(nodeSemaphore, DISPATCH_TIME_FOREVER);
1894 
1895  BasicBlock *waitBlock = BasicBlock::Create(module->getContext(), "wait", function, 0);
1896  BasicBlock *checkTypeIndexBlock = BasicBlock::Create(module->getContext(), "checkTypeIndex", function, 0);
1897  ConstantInt *falseArgValue = ConstantInt::get(static_cast<IntegerType *>(isThreadSafeValue->getType()), 0);
1898  ICmpInst *isThreadSafeEqualsTrue = new ICmpInst(*checkWaitBlock, ICmpInst::ICMP_NE, isThreadSafeValue, falseArgValue, "");
1899  BranchInst::Create(waitBlock, checkTypeIndexBlock, isThreadSafeEqualsTrue, checkWaitBlock);
1900 
1901  VuoCompilerCodeGenUtilities::generateWaitForSemaphore(module, waitBlock, nodeSemaphoreValue);
1902  BranchInst::Create(checkTypeIndexBlock, waitBlock);
1903 
1904 
1905  // if (typeIndex == 0)
1906  // {
1907  // VuoText oldPortValue;
1908  // if (hasOldValue)
1909  // oldPortValue = *((VuoText *)portAddress);
1910  // if (hasNewValue)
1911  // {
1912  // VuoText portValue = VuoText_makeFromString(valueAsString);
1913  // *((VuoText *)portAddress) = portValue;
1914  // VuoRetain(portValue);
1915  // if (shouldSendTelemetry)
1916  // summary = VuoText_getSummary(portValue);
1917  // }
1918  // if (hasOldValue)
1919  // VuoRelease(oldPortValue);
1920  // }
1921  // else if (typeIndex == 1)
1922  // {
1923  // if (hasNewValue)
1924  // {
1925  // VuoReal portValue = VuoReal_makeFromString(valueAsString);
1926  // *((VuoReal *)portAddress) = portValue;
1927  // if (shouldSendTelemetry)
1928  // summary = VuoReal_getSummary(portValue);
1929  // }
1930  // }
1931  // else if ...
1932 
1933  ICmpInst *hasOldValueIsTrue = new ICmpInst(*checkTypeIndexBlock, ICmpInst::ICMP_NE, hasOldValue, falseArgValue, "");
1934  ICmpInst *hasNewValueIsTrue = new ICmpInst(*checkTypeIndexBlock, ICmpInst::ICMP_NE, hasNewValue, falseArgValue, "");
1935  ICmpInst *shouldSendTelemetryIsTrue = new ICmpInst(*checkTypeIndexBlock, ICmpInst::ICMP_NE, shouldSendTelemetryValue, falseArgValue, "");
1936 
1937  vector< pair<BasicBlock *, BasicBlock *> > blocksForTypeIndex;
1938  for (size_t i = 0; i < orderedTypes.size(); ++i)
1939  {
1940  VuoCompilerType *type = orderedTypes[i];
1941 
1942  BasicBlock *typeInitialBlock = BasicBlock::Create(module->getContext(), type->getBase()->getModuleKey() + "_initial", function, 0);
1943  Value *portAddress = new BitCastInst(portAddressAsVoidPointer, PointerType::get(type->getType(), 0), "", typeInitialBlock);
1944 
1945  BasicBlock *typeFinalBlock = BasicBlock::Create(module->getContext(), type->getBase()->getModuleKey() + "_final", function, 0);
1946 
1947  BasicBlock *setNewValueBlock = BasicBlock::Create(module->getContext(), "setNewValue", function, 0);
1948  Value *portValue = type->generateValueFromStringFunctionCall(module, setNewValueBlock, valueAsStringValue);
1949  new StoreInst(portValue, portAddress, false, setNewValueBlock);
1950  type->generateRetainCall(module, setNewValueBlock, portValue);
1951 
1952  BasicBlock *summaryBlock = BasicBlock::Create(module->getContext(), "summary", function, 0);
1953  Value *summaryValue = type->generateSummaryFromValueFunctionCall(module, summaryBlock, portValue);
1954  new StoreInst(summaryValue, summaryVariable, false, summaryBlock);
1955 
1957  {
1958  BasicBlock *saveOldValueBlock = BasicBlock::Create(module->getContext(), "saveOldValue", function, 0);
1959  BasicBlock *checkNewValueBlock = BasicBlock::Create(module->getContext(), "checkNewValue", function, 0);
1960  BasicBlock *checkOldValueBlock = BasicBlock::Create(module->getContext(), "checkOldValue", function, 0);
1961  BasicBlock *releaseOldValueBlock = BasicBlock::Create(module->getContext(), "releaseOldValue", function, 0);
1962 
1963  AllocaInst *oldPortValueVariable = new AllocaInst(type->getType(), "oldPortValue", typeInitialBlock);
1964  BranchInst::Create(saveOldValueBlock, checkNewValueBlock, hasOldValueIsTrue, typeInitialBlock);
1965 
1966  Value *oldPortValue = new LoadInst(portAddress, "", false, saveOldValueBlock);
1967  new StoreInst(oldPortValue, oldPortValueVariable, false, saveOldValueBlock);
1968  BranchInst::Create(checkNewValueBlock, saveOldValueBlock);
1969 
1970  BranchInst::Create(setNewValueBlock, checkOldValueBlock, hasNewValueIsTrue, checkNewValueBlock);
1971 
1972  BranchInst::Create(summaryBlock, checkOldValueBlock, shouldSendTelemetryIsTrue, setNewValueBlock);
1973 
1974  BranchInst::Create(checkOldValueBlock, summaryBlock);
1975 
1976  BranchInst::Create(releaseOldValueBlock, typeFinalBlock, hasOldValueIsTrue, checkOldValueBlock);
1977 
1978  oldPortValue = new LoadInst(oldPortValueVariable, "", false, releaseOldValueBlock);
1979  type->generateReleaseCall(module, releaseOldValueBlock, oldPortValue);
1980  BranchInst::Create(typeFinalBlock, releaseOldValueBlock);
1981  }
1982  else
1983  {
1984  BranchInst::Create(setNewValueBlock, typeFinalBlock, hasNewValueIsTrue, typeInitialBlock);
1985 
1986  BranchInst::Create(summaryBlock, typeFinalBlock, shouldSendTelemetryIsTrue, setNewValueBlock);
1987 
1988  BranchInst::Create(typeFinalBlock, summaryBlock);
1989  }
1990 
1991  blocksForTypeIndex.push_back( make_pair(typeInitialBlock, typeFinalBlock) );
1992  }
1993 
1994  BasicBlock *checkUpdateBlock = BasicBlock::Create(module->getContext(), "checkUpdate", function, 0);
1995  VuoCompilerCodeGenUtilities::generateIndexMatchingCode(module, function, checkTypeIndexBlock, checkUpdateBlock, typeIndexValue, blocksForTypeIndex);
1996 
1997 
1998  // if (shouldUpdateTriggers)
1999  // {
2000  // if (nodeIndex == 0)
2001  // {
2002  // Top__FirePeriodically2__fired(...);
2003  // }
2004  // else if ...
2005  // }
2006 
2007  Constant *zeroValue = ConstantInt::get(shouldUpdateTriggersValue->getType(), 0);
2008  ICmpInst *shouldUpdateTriggersIsTrue = new ICmpInst(*checkUpdateBlock, ICmpInst::ICMP_NE, shouldUpdateTriggersValue, zeroValue, "");
2009  BasicBlock *updateTriggersBlock = BasicBlock::Create(module->getContext(), "updateTriggers", function, 0);
2010  BasicBlock *checkSendBlock = BasicBlock::Create(module->getContext(), "checkSend", function, 0);
2011  BranchInst::Create(updateTriggersBlock, checkSendBlock, shouldUpdateTriggersIsTrue, checkUpdateBlock);
2012 
2013  vector< pair<BasicBlock *, BasicBlock *> > blocksForNodeIndex;
2014  for (size_t i = 0; i < orderedNodes.size(); ++i)
2015  {
2016  VuoCompilerNode *node = orderedNodes[i];
2017  BasicBlock *currentBlock = BasicBlock::Create(module->getContext(), node->getIdentifier(), function, 0);
2018  BasicBlock *origCurrentBlock = currentBlock;
2019 
2020  node->generateCallbackUpdateFunctionCall(module, currentBlock, compositionStateValue);
2021 
2022  generateDataOnlyTransmissionFromNode(function, currentBlock, compositionStateValue, node, true, true, true);
2023 
2024  blocksForNodeIndex.push_back( make_pair(origCurrentBlock, currentBlock) );
2025  }
2026 
2027  BasicBlock *checkSignalBlock = BasicBlock::Create(module->getContext(), "checkSignal", function, 0);
2028  VuoCompilerCodeGenUtilities::generateIndexMatchingCode(module, function, updateTriggersBlock, checkSignalBlock, nodeIndexValue, blocksForNodeIndex);
2029 
2030 
2031  // if (isThreadSafe)
2032  // dispatch_semaphore_signal(nodeSemaphore);
2033 
2034  BasicBlock *signalBlock = BasicBlock::Create(module->getContext(), "signal", function, 0);
2035  BranchInst::Create(signalBlock, checkSendBlock, isThreadSafeEqualsTrue, checkSignalBlock);
2036 
2037  VuoCompilerCodeGenUtilities::generateSignalForSemaphore(module, signalBlock, nodeSemaphoreValue);
2038  BranchInst::Create(checkSendBlock, signalBlock);
2039 
2040 
2041  // if (shouldSendTelemetry)
2042  // {
2043  // sendInputPortsUpdated(portIdentifier, false, true, summary);
2044  // free(summary);
2045  // }
2046 
2047  BasicBlock *sendBlock = BasicBlock::Create(module->getContext(), "send", function, 0);
2048  BranchInst::Create(sendBlock, finalBlock, shouldSendTelemetryIsTrue, checkSendBlock);
2049 
2050  Value *summaryValue = new LoadInst(summaryVariable, "", false, sendBlock);
2051 
2052  VuoCompilerCodeGenUtilities::generateSendInputPortsUpdated(module, sendBlock, compositionStateValue, portIdentifierValue,
2053  false, true, summaryValue);
2054 
2055  VuoCompilerCodeGenUtilities::generateFreeCall(module, sendBlock, summaryValue);
2056  BranchInst::Create(finalBlock, sendBlock);
2057 
2058  ReturnInst::Create(module->getContext(), finalBlock);
2059 }
2060 
2066 void VuoCompilerBitcodeGenerator::generateSetInputPortValueFunction(void)
2067 {
2068  Function *function = VuoCompilerCodeGenUtilities::getSetInputPortValueFunction(module);
2069  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
2070 
2071  Function::arg_iterator args = function->arg_begin();
2072  Value *portIdentifierValue = args++;
2073  portIdentifierValue->setName("portIdentifier");
2074  Value *valueAsStringValue = args++;
2075  valueAsStringValue->setName("valueAsString");
2076 
2077  Function *compositionSetPortValueFunction = VuoCompilerCodeGenUtilities::getCompositionSetPortValueFunction(module);
2078 
2079  Value *topLevelRuntimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, block);
2080  Value *topLevelCompositionIdentifierValue = constantStrings.get(module, VuoCompilerComposition::topLevelCompositionIdentifier);
2081  Value *compositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, topLevelRuntimeStateValue, topLevelCompositionIdentifierValue);
2082 
2083  Value *trueValue = ConstantInt::get(compositionSetPortValueFunction->getFunctionType()->getParamType(3), 1);
2084 
2085  vector<Value *> compositionArgs;
2086  compositionArgs.push_back(compositionStateValue);
2087  compositionArgs.push_back(portIdentifierValue);
2088  compositionArgs.push_back(valueAsStringValue);
2089  compositionArgs.push_back(trueValue);
2090  compositionArgs.push_back(trueValue);
2091  compositionArgs.push_back(trueValue);
2092  compositionArgs.push_back(trueValue);
2093  compositionArgs.push_back(trueValue);
2094  CallInst::Create(compositionSetPortValueFunction, compositionArgs, "", block);
2095 
2096  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, compositionStateValue);
2097 
2098  ReturnInst::Create(module->getContext(), block);
2099 }
2100 
2120 void VuoCompilerBitcodeGenerator::generateCompositionFireTriggerPortEventFunction(void)
2121 {
2123 
2124  Function::arg_iterator args = function->arg_begin();
2125  Value *compositionStateValue = args++;
2126  compositionStateValue->setName("compositionState");
2127  Value *portIdentifierValue = args++;
2128  portIdentifierValue->setName("portIdentifier");
2129 
2130  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, 0);
2131 
2132  map<string, pair<BasicBlock *, BasicBlock *> > blocksForString;
2133  for (VuoCompilerTriggerPort *trigger : graph->getTriggerPorts())
2134  {
2135  VuoCompilerNode *triggerNode = graph->getNodeForTriggerPort(trigger);
2136 
2137  string currentPortIdentifier = trigger->getIdentifier();
2138 
2139  BasicBlock *currentBlock = BasicBlock::Create(module->getContext(), currentPortIdentifier, function, 0);
2140  BasicBlock *origCurrentBlock = currentBlock;
2141 
2142  Value *nodeContextValue = triggerNode->generateGetContext(module, currentBlock, compositionStateValue);
2143  Value *triggerFunctionValue = trigger->generateLoadFunction(module, currentBlock, nodeContextValue);
2144 
2145  vector<Value *> triggerArgs;
2146  AttributeSet triggerParamAttributes;
2147  VuoType *dataType = trigger->getDataVuoType();
2148  if (dataType)
2149  {
2150  generateWaitForNodes(module, function, currentBlock, compositionStateValue, vector<VuoCompilerNode *>(1, triggerNode));
2151 
2152  Value *arg = trigger->generateLoadPreviousData(module, currentBlock, nodeContextValue);
2153 
2154  FunctionType *triggerFunctionType = trigger->getClass()->getFunctionType();
2155 
2156  Type *secondParam = NULL;
2157  dataType->getCompiler()->getFunctionParameterType(&secondParam);
2158 
2159  triggerParamAttributes = dataType->getCompiler()->getFunctionParameterAttributes();
2160  bool isByVal = triggerParamAttributes.hasAttrSomewhere(Attribute::ByVal);
2161 
2162  Value *secondArg = NULL;
2163  Value **secondArgIfNeeded = (secondParam ? &secondArg : NULL);
2164  arg = VuoCompilerCodeGenUtilities::convertArgumentToParameterType(arg, triggerFunctionType, 0, isByVal, secondArgIfNeeded, module, currentBlock);
2165 
2166  triggerArgs.push_back(arg);
2167  if (secondParam)
2168  triggerArgs.push_back(secondArg);
2169  }
2170 
2171  CallInst *call = CallInst::Create(triggerFunctionValue, triggerArgs, "", currentBlock);
2172  if (dataType)
2173  call->setAttributes(VuoCompilerCodeGenUtilities::copyAttributesToIndex(triggerParamAttributes, 1));
2174 
2175  if (dataType)
2176  generateSignalForNodes(module, currentBlock, compositionStateValue, vector<VuoCompilerNode *>(1, triggerNode));
2177 
2178  blocksForString[currentPortIdentifier] = make_pair(origCurrentBlock, currentBlock);
2179  }
2180 
2181  BasicBlock *finalBlock = BasicBlock::Create(module->getContext(), "final", function, 0);
2182 
2183  ReturnInst::Create(module->getContext(), finalBlock);
2184 
2185  VuoCompilerCodeGenUtilities::generateStringMatchingCode(module, function, initialBlock, finalBlock, portIdentifierValue, blocksForString, constantStrings);
2186 }
2187 
2203 void VuoCompilerBitcodeGenerator::generateGetPublishedPortCountFunction(bool input)
2204 {
2205  size_t count;
2206  string functionName;
2207  if (input)
2208  {
2209  count = composition->getBase()->getPublishedInputPorts().size();
2210  functionName = "getPublishedInputPortCount";
2211  }
2212  else
2213  {
2214  count = composition->getBase()->getPublishedOutputPorts().size();
2215  functionName = "getPublishedOutputPortCount";
2216  }
2217 
2218  Function *function = module->getFunction(functionName);
2219  if (! function)
2220  {
2221  vector<Type *> functionParams;
2222  FunctionType *functionType = FunctionType::get(IntegerType::get(module->getContext(), 32), functionParams, false);
2223  function = Function::Create(functionType, GlobalValue::ExternalLinkage, functionName, module);
2224  }
2225 
2226  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, 0);
2227  ConstantInt *countConstant = ConstantInt::get(module->getContext(), APInt(32, count));
2228  ReturnInst::Create(module->getContext(), countConstant, block);
2229 }
2230 
2246 void VuoCompilerBitcodeGenerator::generateGetPublishedPortNamesFunction(bool input)
2247 {
2248  string functionName;
2249  vector<VuoPublishedPort *> publishedPorts;
2250  if (input)
2251  {
2252  functionName = "getPublishedInputPortNames";
2253  publishedPorts = composition->getBase()->getPublishedInputPorts();
2254  }
2255  else
2256  {
2257  functionName = "getPublishedOutputPortNames";
2258  publishedPorts = composition->getBase()->getPublishedOutputPorts();
2259  }
2260 
2261  vector<string> names;
2262  for (vector<VuoPublishedPort *>::iterator i = publishedPorts.begin(); i != publishedPorts.end(); ++i)
2263  {
2264  names.push_back( (*i)->getClass()->getName() );
2265  }
2266 
2267  generateFunctionReturningStringArray(functionName, names);
2268 }
2269 
2285 void VuoCompilerBitcodeGenerator::generateGetPublishedPortTypesFunction(bool input)
2286 {
2287  string functionName;
2288  vector<VuoPublishedPort *> publishedPorts;
2289  if (input)
2290  {
2291  functionName = "getPublishedInputPortTypes";
2292  publishedPorts = composition->getBase()->getPublishedInputPorts();
2293  }
2294  else
2295  {
2296  functionName = "getPublishedOutputPortTypes";
2297  publishedPorts = composition->getBase()->getPublishedOutputPorts();
2298  }
2299 
2300  vector<string> types;
2301  for (vector<VuoPublishedPort *>::iterator i = publishedPorts.begin(); i != publishedPorts.end(); ++i)
2302  {
2303  VuoCompilerPublishedPort *publishedPort = static_cast<VuoCompilerPublishedPort *>((*i)->getCompiler());
2304 
2305  VuoType *type = publishedPort->getDataVuoType();
2306  string typeName = type ? type->getModuleKey() : "";
2307  types.push_back(typeName);
2308  }
2309 
2310  generateFunctionReturningStringArray(functionName, types);
2311 }
2312 
2328 void VuoCompilerBitcodeGenerator::generateGetPublishedPortDetailsFunction(bool input)
2329 {
2330  string functionName;
2331  vector<VuoPublishedPort *> publishedPorts;
2332  if (input)
2333  {
2334  functionName = "getPublishedInputPortDetails";
2335  publishedPorts = composition->getBase()->getPublishedInputPorts();
2336  }
2337  else
2338  {
2339  functionName = "getPublishedOutputPortDetails";
2340  publishedPorts = composition->getBase()->getPublishedOutputPorts();
2341  }
2342 
2343  vector<string> details;
2344  for (vector<VuoPublishedPort *>::iterator i = publishedPorts.begin(); i != publishedPorts.end(); ++i)
2345  {
2346  VuoCompilerPublishedPort *publishedPort = static_cast<VuoCompilerPublishedPort *>((*i)->getCompiler());
2347 
2348  json_object *detailsObj = publishedPort->getDetails(input);
2349  string detailsSerialized = json_object_to_json_string_ext(detailsObj, JSON_C_TO_STRING_PLAIN);
2350  details.push_back(detailsSerialized);
2351 
2352  json_object_put(detailsObj);
2353  }
2354 
2355  generateFunctionReturningStringArray(functionName, details);
2356 }
2357 
2364 void VuoCompilerBitcodeGenerator::generateFunctionReturningStringArray(string functionName, vector<string> stringValues)
2365 {
2366  Function *function = module->getFunction(functionName);
2367  if (! function)
2368  {
2369  PointerType *pointerToChar = PointerType::get(IntegerType::get(module->getContext(), 8), 0);
2370  PointerType *pointerToPointerToChar = PointerType::get(pointerToChar, 0);
2371  vector<Type *> functionParams;
2372  FunctionType *functionType = FunctionType::get(pointerToPointerToChar, functionParams, false);
2373  function = Function::Create(functionType, GlobalValue::ExternalLinkage, functionName, module);
2374  }
2375 
2376  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, 0);
2377 
2378  Constant *stringArrayGlobalPointer = VuoCompilerCodeGenUtilities::generatePointerToConstantArrayOfStrings(module, stringValues);
2379  ReturnInst::Create(module->getContext(), stringArrayGlobalPointer, block);
2380 }
2381 
2391 void VuoCompilerBitcodeGenerator::generateFirePublishedInputPortEventFunction(void)
2392 {
2393  string functionName = "firePublishedInputPortEvent";
2394  Function *function = module->getFunction(functionName);
2395  if (! function)
2396  {
2397  PointerType *pointerToChar = PointerType::get(IntegerType::get(module->getContext(), 8), 0);
2398  PointerType *pointerToPointerToChar = PointerType::get(pointerToChar, 0);
2399  Type *countType = IntegerType::get(module->getContext(), 32);
2400 
2401  vector<Type *> functionParams;
2402  functionParams.push_back(pointerToPointerToChar);
2403  functionParams.push_back(countType);
2404  FunctionType *functionType = FunctionType::get(Type::getVoidTy(module->getContext()), functionParams, false);
2405  function = Function::Create(functionType, GlobalValue::ExternalLinkage, functionName, module);
2406  }
2407 
2408  Function::arg_iterator args = function->arg_begin();
2409  Value *namesValue = args++;
2410  namesValue->setName("names");
2411  Value *countValue = args++;
2412  countValue->setName("count");
2413 
2414  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, 0);
2415 
2417  if (! trigger)
2418  {
2419  ReturnInst::Create(module->getContext(), initialBlock);
2420  return;
2421  }
2422 
2423  VuoCompilerNode *triggerNode = graph->getNodeForTriggerPort(trigger);
2424 
2425  Value *runtimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, initialBlock);
2426  Value *compositionIdentifierValue = constantStrings.get(module, VuoCompilerComposition::topLevelCompositionIdentifier);
2427  Value *compositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, initialBlock, runtimeStateValue,
2428  compositionIdentifierValue);
2429 
2430  // Create an event ID so the nodes claimed by this function can be used (re-claimed) by the trigger worker.
2431 
2432  Value *eventIdValue = VuoCompilerCodeGenUtilities::generateGetNextEventId(module, initialBlock, compositionStateValue);
2433 
2434  // Claim all necessary downstream nodes —
2435  // including the published output node to synchronize access to the composition's node context when tracking events started/finished.
2436 
2437  vector<VuoCompilerNode *> triggerWaitNodes = getNodesToWaitOnBeforeTransmission(trigger);
2438 
2439  VuoCompilerNode *publishedOutputNode = graph->getPublishedOutputNode();
2440  if (find(triggerWaitNodes.begin(), triggerWaitNodes.end(), publishedOutputNode) == triggerWaitNodes.end())
2441  triggerWaitNodes.push_back(publishedOutputNode);
2442 
2443  generateWaitForNodes(module, function, initialBlock, compositionStateValue, triggerWaitNodes, eventIdValue);
2444 
2445  // Start tracking the event so we can later notify the runner when the event is finished.
2446 
2447  Value *compositionContextValue = VuoCompilerCodeGenUtilities::generateGetCompositionContext(module, initialBlock, compositionStateValue);
2448  VuoCompilerCodeGenUtilities::generateStartedExecutingEvent(module, initialBlock, compositionContextValue, eventIdValue);
2449 
2450  // Mark the selected input ports on the published input node as hit by an event.
2451  //
2452  // int i = 0;
2453  // while (i < count)
2454  // {
2455  // if (! strcmp(names[i], "firstPort"))
2456  // {
2457  // ...
2458  // }
2459  // else if (! strcmp(names[i], "secondPort"))
2460  // {
2461  // ...
2462  // }
2463  // i = i + 1;
2464  // }
2465  //
2466 
2467  VuoCompilerNode *publishedInputNode = graph->getPublishedInputNode();
2468  Value *publishedInputNodeContextValue = publishedInputNode->generateGetContext(module, initialBlock, compositionStateValue);
2469 
2470  Value *zeroValue = ConstantInt::get(static_cast<IntegerType *>(countValue->getType()), 0);
2471  AllocaInst *iterVariable = new AllocaInst(countValue->getType(), "i", initialBlock);
2472  new StoreInst(zeroValue, iterVariable, false, initialBlock);
2473 
2474  BasicBlock *loopConditionBlock = BasicBlock::Create(module->getContext(), "loopCondition", function, 0);
2475  BasicBlock *loopBeginBlock = BasicBlock::Create(module->getContext(), "loopBegin", function, 0);
2476  BasicBlock *loopEndBlock = BasicBlock::Create(module->getContext(), "loopEnd", function, 0);
2477  BasicBlock *fireBlock = BasicBlock::Create(module->getContext(), "fire", function, 0);
2478 
2479  BranchInst::Create(loopConditionBlock, initialBlock);
2480 
2481  Value *iterValue = new LoadInst(iterVariable, "", false, loopConditionBlock);
2482  ICmpInst *iterLessThanCount = new ICmpInst(*loopConditionBlock, ICmpInst::ICMP_ULT, iterValue, countValue, "");
2483  BranchInst::Create(loopBeginBlock, fireBlock, iterLessThanCount, loopConditionBlock);
2484 
2485  Value *iterNameValue = VuoCompilerCodeGenUtilities::generateGetArrayElement(module, loopBeginBlock, namesValue, iterValue);
2486 
2487  map<string, pair<BasicBlock *, BasicBlock *> > blocksForString;
2488 
2489  vector<VuoPublishedPort *> publishedInputPorts = composition->getBase()->getPublishedInputPorts();
2490  for (size_t i = 0; i < publishedInputPorts.size(); ++i)
2491  {
2492  string currentName = publishedInputPorts[i]->getClass()->getName();
2493  BasicBlock *currentBlock = BasicBlock::Create(module->getContext(), currentName, function, 0);
2494 
2495  VuoPort *port = graph->getInputPortOnPublishedInputNode(i);
2496  VuoCompilerInputEventPort *inputEventPort = static_cast<VuoCompilerInputEventPort *>(port->getCompiler());
2497  inputEventPort->generateStoreEvent(module, currentBlock, publishedInputNodeContextValue, true);
2498 
2499  blocksForString[currentName] = make_pair(currentBlock, currentBlock);
2500  }
2501 
2502  VuoCompilerCodeGenUtilities::generateStringMatchingCode(module, function, loopBeginBlock, loopEndBlock, iterNameValue, blocksForString, constantStrings);
2503 
2504  Value *oneValue = ConstantInt::get(static_cast<IntegerType *>(countValue->getType()), 1);
2505  Value *iterPlusOneValue = BinaryOperator::Create(Instruction::Add, iterValue, oneValue, "", loopEndBlock);
2506  new StoreInst(iterPlusOneValue, iterVariable, false, loopEndBlock);
2507 
2508  BranchInst::Create(loopConditionBlock, loopEndBlock);
2509 
2510  // Fire an event from the published input trigger.
2511 
2512  Value *triggerNodeContextValue = triggerNode->generateGetContext(module, fireBlock, compositionStateValue);
2513  Value *triggerFunctionValue = trigger->generateLoadFunction(module, fireBlock, triggerNodeContextValue);
2514  CallInst::Create(triggerFunctionValue, "", fireBlock);
2515 
2516  ReturnInst::Create(module->getContext(), fireBlock);
2517 }
2518 
2558 void VuoCompilerBitcodeGenerator::generateGetPublishedPortValueFunction(bool input)
2559 {
2560  Function *function = (input ?
2562  VuoCompilerCodeGenUtilities::getGetPublishedOutputPortValueFunction(module));
2563 
2564  Function::arg_iterator args = function->arg_begin();
2565  Value *portIdentifierValue = args++;
2566  portIdentifierValue->setName("portIdentifier");
2567  Value *shouldUseInterprocessSerializationValue = args++;
2568  shouldUseInterprocessSerializationValue->setName("shouldUseInterprocessSerialization");
2569 
2570  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, 0);
2571  PointerType *pointerToChar = PointerType::get(IntegerType::get(module->getContext(), 8), 0);
2572  AllocaInst *retVariable = new AllocaInst(pointerToChar, "ret", initialBlock);
2573  ConstantPointerNull *nullValue = ConstantPointerNull::get(pointerToChar);
2574  new StoreInst(nullValue, retVariable, false, initialBlock);
2575 
2576  Value *runtimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, initialBlock);
2577  Value *compositionIdentifierValue = constantStrings.get(module, VuoCompilerComposition::topLevelCompositionIdentifier);
2578  Value *compositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, initialBlock, runtimeStateValue,
2579  compositionIdentifierValue);
2580 
2581  vector<VuoPort *> inputPortsOnPublishedNode;
2582  if (input)
2583  {
2584  vector<VuoPublishedPort *> publishedPorts = composition->getBase()->getPublishedInputPorts();
2585  for (size_t i = 0; i < publishedPorts.size(); ++i)
2586  {
2587  VuoPort *port = graph->getInputPortOnPublishedInputNode(i);
2588  inputPortsOnPublishedNode.push_back(port);
2589  }
2590  }
2591  else
2592  {
2593  vector<VuoPublishedPort *> publishedPorts = composition->getBase()->getPublishedOutputPorts();
2594  for (size_t i = 0; i < publishedPorts.size(); ++i)
2595  {
2596  VuoPort *port = graph->getInputPortOnPublishedOutputNode(i);
2597  inputPortsOnPublishedNode.push_back(port);
2598  }
2599  }
2600 
2601  map<string, pair<BasicBlock *, BasicBlock *> > blocksForString;
2602  for (VuoPort *port : inputPortsOnPublishedNode)
2603  {
2604  string currentName = port->getClass()->getName();
2605  BasicBlock *currentBlock = BasicBlock::Create(module->getContext(), currentName, function, 0);
2606 
2607  string currentIdentifier = static_cast<VuoCompilerEventPort *>(port->getCompiler())->getIdentifier();
2608  Constant *currentIdentifierValue = constantStrings.get(module, currentIdentifier);
2609 
2610  Value *retValue = VuoCompilerCodeGenUtilities::generateGetInputPortString(module, currentBlock, compositionStateValue,
2611  currentIdentifierValue, shouldUseInterprocessSerializationValue);
2612  new StoreInst(retValue, retVariable, currentBlock);
2613 
2614  blocksForString[currentName] = make_pair(currentBlock, currentBlock);
2615  }
2616 
2617  BasicBlock *finalBlock = BasicBlock::Create(module->getContext(), "final", function, 0);
2618 
2619  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, finalBlock, compositionStateValue);
2620 
2621  LoadInst *retValue = new LoadInst(retVariable, "", false, finalBlock);
2622  ReturnInst::Create(module->getContext(), retValue, finalBlock);
2623 
2624  VuoCompilerCodeGenUtilities::generateStringMatchingCode(module, function, initialBlock, finalBlock, portIdentifierValue, blocksForString, constantStrings);
2625 }
2626 
2638 void VuoCompilerBitcodeGenerator::generateCompositionSetPublishedInputPortValueFunction(void)
2639 {
2641 
2642  Function::arg_iterator args = function->arg_begin();
2643  Value *compositionStateValue = args++;
2644  compositionStateValue->setName("compositionState");
2645  Value *publishedInputPortNameValue = args++;
2646  publishedInputPortNameValue->setName("publishedInputPortName");
2647  Value *valueAsStringValue = args++;
2648  valueAsStringValue->setName("valueAsString");
2649  Value *isCompositionRunningValue = args++;
2650  isCompositionRunningValue->setName("isCompositionRunning");
2651 
2652  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, 0);
2653 
2655  if (! trigger)
2656  {
2657  ReturnInst::Create(module->getContext(), initialBlock);
2658  return;
2659  }
2660 
2661  // const char *inputPortIdentifier = NULL;
2662 
2663  PointerType *pointerToCharType = PointerType::get(IntegerType::get(module->getContext(), 8), 0);
2664  AllocaInst *inputPortIdentifierVariable = new AllocaInst(pointerToCharType, "inputPortIdentifier", initialBlock);
2665  ConstantPointerNull *nullInputPortIdentifier = ConstantPointerNull::get(pointerToCharType);
2666  new StoreInst(nullInputPortIdentifier, inputPortIdentifierVariable, false, initialBlock);
2667 
2668  // if (! strcmp(publishedInputPortName, "firstName"))
2669  // inputPortIdentifier = "PublishedInputs__firstName";
2670  // else if (! strcmp(publishedInputPortName, "secondName"))
2671  // inputPortIdentifier = "PublishedInputs__secondName";
2672  // ...
2673 
2674  map<string, pair<BasicBlock *, BasicBlock *> > blocksForString;
2675  vector<VuoPublishedPort *> publishedInputPorts = composition->getBase()->getPublishedInputPorts();
2676  for (size_t i = 0; i < publishedInputPorts.size(); ++i)
2677  {
2678  string currPublishedInputPortName = publishedInputPorts[i]->getClass()->getName();
2679  BasicBlock *currBlock = BasicBlock::Create(module->getContext(), currPublishedInputPortName, function, 0);
2680 
2681  VuoPort *inputPort = graph->getInputPortOnPublishedInputNode(i);
2682  string inputPortIdentifier = static_cast<VuoCompilerPort *>(inputPort->getCompiler())->getIdentifier();
2683  Value *inputPortIdentifierValue = constantStrings.get(module, inputPortIdentifier);
2684 
2685  new StoreInst(inputPortIdentifierValue, inputPortIdentifierVariable, false, currBlock);
2686 
2687  blocksForString[currPublishedInputPortName] = make_pair(currBlock, currBlock);
2688  }
2689 
2690  BasicBlock *checkBlock = BasicBlock::Create(module->getContext(), "check", function, 0);
2691  BasicBlock *scheduleBlock = BasicBlock::Create(module->getContext(), "schedule", function, 0);
2692  BasicBlock *finalBlock = BasicBlock::Create(module->getContext(), "final", function, 0);
2693 
2694  VuoCompilerCodeGenUtilities::generateStringMatchingCode(module, function, initialBlock, checkBlock, publishedInputPortNameValue, blocksForString, constantStrings);
2695 
2696  // if (inputPortIdentifier != NULL)
2697  // {
2698 
2699  Value *inputPortIdentifierValue = new LoadInst(inputPortIdentifierVariable, "", false, checkBlock);
2700  ICmpInst *portIdentifierNotEqualsNull = new ICmpInst(*checkBlock, ICmpInst::ICMP_NE, inputPortIdentifierValue, nullInputPortIdentifier, "");
2701  BranchInst::Create(scheduleBlock, finalBlock, portIdentifierNotEqualsNull, checkBlock);
2702 
2703  // void **context = (void **)malloc(4 * sizeof(void *));
2704  // context[0] = (void *)compositionState;
2705  // context[1] = (void *)inputPortIdentifier;
2706  // context[2] = (void *)valueAsString;
2707  // context[3] = (void *)isCompositionRunning;
2708 
2709  Value *contextValue = VuoCompilerCodeGenUtilities::generateCreatePublishedInputWorkerContext(module, scheduleBlock, compositionStateValue,
2710  inputPortIdentifierValue, valueAsStringValue,
2711  isCompositionRunningValue);
2712 
2713  // dispatch_sync(PublishedInputsTrigger__queue, context, PublishedInputPorts__setWorker);
2714  // }
2715 
2716  VuoCompilerNode *triggerNode = graph->getNodeForTriggerPort(trigger);
2717  Value *nodeContextValue = triggerNode->generateGetContext(module, scheduleBlock, compositionStateValue);
2718  string workerFunctionName = VuoStringUtilities::transcodeToIdentifier(VuoNodeClass::publishedInputNodeClassName) + "__setWorker";
2719 
2720  Function *workerFunction = trigger->generateSynchronousSubmissionToDispatchQueue(module, scheduleBlock, nodeContextValue,
2721  workerFunctionName, contextValue);
2722 
2723  BranchInst::Create(finalBlock, scheduleBlock);
2724  ReturnInst::Create(module->getContext(), finalBlock);
2725 
2726  // void PublishedInputPorts__firstName__worker(void *context)
2727  // {
2728 
2729  Function *compositionSetPortValueFunction = VuoCompilerCodeGenUtilities::getCompositionSetPortValueFunction(module);
2730 
2731  Function::arg_iterator workerArgs = workerFunction->arg_begin();
2732  Value *contextValueInWorker = workerArgs++;
2733  contextValueInWorker->setName("context");
2734 
2735  BasicBlock *workerBlock = BasicBlock::Create(module->getContext(), "", workerFunction, 0);
2736 
2737  // VuoCompositionState *compositionState = (VuoCompositionState *)((void **)context)[0];
2738  // char *inputPortIdentifier = (char *)((void **)context)[1];
2739  // char *valueAsString = (char *)((void **)context)[2];
2740  // bool isCompositionRunning = (bool)((void **)context)[3];
2741 
2742  Type *voidPointerType = contextValueInWorker->getType();
2743  Type *voidPointerPointerType = PointerType::get(voidPointerType, 0);
2744  Type *compositionStatePointerType = PointerType::get(VuoCompilerCodeGenUtilities::getCompositionStateType(module), 0);
2745  Type *boolType = compositionSetPortValueFunction->getFunctionType()->getParamType(3);
2746 
2747  Value *contextValueAsVoidPointerArray = new BitCastInst(contextValueInWorker, voidPointerPointerType, "", workerBlock);
2748  Value *compositionStateAsVoidPointer = VuoCompilerCodeGenUtilities::generateGetArrayElement(module, workerBlock, contextValueAsVoidPointerArray, (size_t)0);
2749  Value *compositionStateValueInWorker = new BitCastInst(compositionStateAsVoidPointer, compositionStatePointerType, "", workerBlock);
2750 
2751  Value *inputPortIdentifierAsVoidPointer = VuoCompilerCodeGenUtilities::generateGetArrayElement(module, workerBlock, contextValueAsVoidPointerArray, 1);
2752  Value *inputPortIdentifierValueInWorker = new BitCastInst(inputPortIdentifierAsVoidPointer, pointerToCharType, "", workerBlock);
2753 
2754  Value *valueAsStringValueAsVoidPointer = VuoCompilerCodeGenUtilities::generateGetArrayElement(module, workerBlock, contextValueAsVoidPointerArray, 2);
2755  Value *valueAsStringValueInWorker = new BitCastInst(valueAsStringValueAsVoidPointer, pointerToCharType, "", workerBlock);
2756 
2757  Value *isCompositionRunningValueAsVoidPointer = VuoCompilerCodeGenUtilities::generateGetArrayElement(module, workerBlock, contextValueAsVoidPointerArray, 3);
2758  Value *isCompositionRunningValueInWorker = new PtrToIntInst(isCompositionRunningValueAsVoidPointer, boolType, "", workerBlock);
2759 
2760  // free(context);
2761 
2762  VuoCompilerCodeGenUtilities::generateFreeCall(module, workerBlock, contextValueInWorker);
2763 
2764  // compositionSetPortValue(compositionState, portIdentifier, valueAsString, isCompositionRunning, isCompositionRunning, isCompositionRunning, true, true);
2765  // }
2766 
2767  Value *trueValue = ConstantInt::get(boolType, 1);
2768 
2769  vector<Value *> setValueArgs;
2770  setValueArgs.push_back(compositionStateValueInWorker);
2771  setValueArgs.push_back(inputPortIdentifierValueInWorker);
2772  setValueArgs.push_back(valueAsStringValueInWorker);
2773  setValueArgs.push_back(isCompositionRunningValueInWorker);
2774  setValueArgs.push_back(isCompositionRunningValueInWorker);
2775  setValueArgs.push_back(isCompositionRunningValueInWorker);
2776  setValueArgs.push_back(trueValue);
2777  setValueArgs.push_back(trueValue);
2778  CallInst::Create(compositionSetPortValueFunction, setValueArgs, "", workerBlock);
2779 
2780  ReturnInst::Create(module->getContext(), workerBlock);
2781 }
2782 
2790 void VuoCompilerBitcodeGenerator::generateSetPublishedInputPortValueFunction(void)
2791 {
2793 
2794  Function::arg_iterator args = function->arg_begin();
2795  Value *publishedInputPortNameValue = args++;
2796  publishedInputPortNameValue->setName("publishedInputPortName");
2797  Value *valueAsStringValue = args++;
2798  valueAsStringValue->setName("valueAsString");
2799 
2800  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
2801 
2803 
2804  Value *topLevelRuntimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, block);
2805  Value *topLevelCompositionIdentifierValue = constantStrings.get(module, VuoCompilerComposition::topLevelCompositionIdentifier);
2806  Value *compositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, topLevelRuntimeStateValue, topLevelCompositionIdentifierValue);
2807  Value *trueValue = ConstantInt::get(compositionFunction->getFunctionType()->getParamType(3), 1);
2808 
2809  vector<Value *> compositionArgs;
2810  compositionArgs.push_back(compositionStateValue);
2811  compositionArgs.push_back(publishedInputPortNameValue);
2812  compositionArgs.push_back(valueAsStringValue);
2813  compositionArgs.push_back(trueValue);
2814  CallInst::Create(compositionFunction, compositionArgs, "", block);
2815 
2816  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, compositionStateValue);
2817 
2818  ReturnInst::Create(module->getContext(), block);
2819 }
2820 
2825 void VuoCompilerBitcodeGenerator::generateTransmissionFromOutputPort(Function *function, BasicBlock *&currentBlock,
2826  Value *compositionStateValue, VuoCompilerPort *outputPort,
2827  Value *eventValue, Value *dataValue,
2828  bool requiresEvent, bool shouldSendTelemetry)
2829 {
2830  IntegerType *boolType = IntegerType::get(module->getContext(), 1);
2831  PointerType *pointerToCharType = PointerType::get(IntegerType::get(module->getContext(), 8), 0);
2832 
2833  set<VuoCompilerCable *> outgoingCables = graph->getOutgoingCables(outputPort);
2834 
2835  Constant *trueValue = ConstantInt::get(boolType, 1);
2836  Constant *falseValue = ConstantInt::get(boolType, 0);
2837  Constant *transmittedEventValue = (requiresEvent ? trueValue : falseValue);
2838 
2839  // char *dataSummary = NULL;
2840  AllocaInst *dataSummaryVariable = new AllocaInst(pointerToCharType, "dataSummary", currentBlock);
2841  new StoreInst(ConstantPointerNull::get(pointerToCharType), dataSummaryVariable, currentBlock);
2842 
2843  map<VuoCompilerPort *, ICmpInst *> shouldSummarizeInput;
2844  if (shouldSendTelemetry)
2845  {
2846  // bool sentData = false;
2847  AllocaInst *sentDataVariable = new AllocaInst(boolType, "sentData", currentBlock);
2848  new StoreInst(falseValue, sentDataVariable, currentBlock);
2849 
2850  for (set<VuoCompilerCable *>::iterator i = outgoingCables.begin(); i != outgoingCables.end(); ++i)
2851  {
2852  VuoCompilerCable *cable = *i;
2853 
2854  VuoCompilerPort *inputPort = static_cast<VuoCompilerPort *>(cable->getBase()->getToPort()->getCompiler());
2855  ICmpInst *shouldSendDataForInput = VuoCompilerCodeGenUtilities::generateShouldSendDataTelemetryComparison(module, currentBlock,
2856  inputPort->getIdentifier(),
2857  compositionStateValue,
2858  constantStrings);
2859  shouldSummarizeInput[inputPort] = shouldSendDataForInput;
2860  }
2861 
2862  if (dataValue)
2863  {
2864  Value *shouldSummarizeOutput = VuoCompilerCodeGenUtilities::generateShouldSendDataTelemetryComparison(module, currentBlock,
2865  outputPort->getIdentifier(),
2866  compositionStateValue,
2867  constantStrings);
2868 
2869  for (set<VuoCompilerCable *>::iterator i = outgoingCables.begin(); i != outgoingCables.end(); ++i)
2870  {
2871  VuoCompilerCable *cable = *i;
2872 
2873  if (cable->carriesData())
2874  {
2875  VuoCompilerPort *inputPort = static_cast<VuoCompilerPort *>(cable->getBase()->getToPort()->getCompiler());
2876  shouldSummarizeOutput = BinaryOperator::Create(Instruction::Or, shouldSummarizeOutput, shouldSummarizeInput[inputPort], "", currentBlock);
2877  }
2878  }
2879 
2880  BasicBlock *summaryBlock = BasicBlock::Create(module->getContext(), "outputSummary", function, NULL);
2881  BasicBlock *sendOutputBlock = BasicBlock::Create(module->getContext(), "sendOutput", function, NULL);
2882  BranchInst::Create(summaryBlock, sendOutputBlock, shouldSummarizeOutput, currentBlock);
2883 
2884  // sentData = true;
2885  new StoreInst(trueValue, sentDataVariable, summaryBlock);
2886 
2887  // dataSummary = <type>_getSummary(portValue);
2888  VuoCompilerType *type = outputPort->getDataVuoType()->getCompiler();
2889  Value *dataSummaryValue = type->generateSummaryFromValueFunctionCall(module, summaryBlock, dataValue);
2890  new StoreInst(dataSummaryValue, dataSummaryVariable, summaryBlock);
2891 
2892  BranchInst::Create(sendOutputBlock, summaryBlock);
2893  currentBlock = sendOutputBlock;
2894  }
2895 
2896  Value *sentDataValue = new LoadInst(sentDataVariable, "", false, currentBlock);
2897  Value *dataSummaryValue = new LoadInst(dataSummaryVariable, "", false, currentBlock);
2898 
2899  Constant *outputPortIdentifierValue = constantStrings.get(module, outputPort->getIdentifier());
2900 
2901  VuoCompilerCodeGenUtilities::generateSendOutputPortsUpdated(module, currentBlock, compositionStateValue, outputPortIdentifierValue,
2902  transmittedEventValue, sentDataValue, dataSummaryValue);
2903  }
2904 
2905  // If the output port should transmit an event...
2906  bool alwaysTransmitsEvent = (dynamic_cast<VuoCompilerTriggerPort *>(outputPort) || ! requiresEvent);
2907  BasicBlock *transmissionBlock = NULL;
2908  BasicBlock *noTransmissionBlock = NULL;
2909  if (alwaysTransmitsEvent)
2910  {
2911  transmissionBlock = currentBlock;
2912  }
2913  else
2914  {
2915  transmissionBlock = BasicBlock::Create(module->getContext(), "transmission", function, NULL);
2916  noTransmissionBlock = BasicBlock::Create(module->getContext(), "noTransmission", function, NULL);
2917 
2918  ConstantInt *zeroValue = ConstantInt::get(static_cast<IntegerType *>(eventValue->getType()), 0);
2919  ICmpInst *eventValueIsTrue = new ICmpInst(*currentBlock, ICmpInst::ICMP_NE, eventValue, zeroValue, "");
2920  BranchInst::Create(transmissionBlock, noTransmissionBlock, eventValueIsTrue, currentBlock);
2921  }
2922 
2923  // ... then transmit the event and data (if any) to each connected input port.
2924  for (set<VuoCompilerCable *>::iterator i = outgoingCables.begin(); i != outgoingCables.end(); ++i)
2925  {
2926  VuoCompilerCable *cable = *i;
2927 
2928  VuoCompilerNode *inputNode = cable->getBase()->getToNode()->getCompiler();
2929  Value *inputNodeContextValue = inputNode->generateGetContext(module, transmissionBlock, compositionStateValue);
2930  VuoCompilerInputEventPort *inputPort = static_cast<VuoCompilerInputEventPort *>( cable->getBase()->getToPort()->getCompiler() );
2931  Value *inputPortContextValue = inputPort->generateGetPortContext(module, transmissionBlock, inputNodeContextValue);
2932 
2933  Value *transmittedDataValue = (cable->carriesData() ? dataValue : NULL);
2934 
2935  cable->generateTransmission(module, transmissionBlock, inputNodeContextValue, inputPortContextValue, transmittedDataValue, requiresEvent);
2936 
2937  if (shouldSendTelemetry)
2938  {
2939  // char *inputDataSummary = NULL;
2940  AllocaInst *inputDataSummaryVariable = new AllocaInst(pointerToCharType, "inputDataSummary", transmissionBlock);
2941  new StoreInst(ConstantPointerNull::get(pointerToCharType), inputDataSummaryVariable, transmissionBlock);
2942 
2943  // bool receivedData = false;
2944  AllocaInst *receivedDataVariable = new AllocaInst(boolType, "receivedData", transmissionBlock);
2945  new StoreInst(falseValue, receivedDataVariable, transmissionBlock);
2946 
2947  VuoType *inputDataType = inputPort->getDataVuoType();
2948  if (inputDataType)
2949  {
2950  BasicBlock *summaryBlock = BasicBlock::Create(module->getContext(), "inputSummary", function, NULL);
2951  BasicBlock *sendInputBlock = BasicBlock::Create(module->getContext(), "sendInput", function, NULL);
2952  BranchInst::Create(summaryBlock, sendInputBlock, shouldSummarizeInput[inputPort], transmissionBlock);
2953 
2954  Value *inputDataSummaryValue;
2955  if (transmittedDataValue)
2956  {
2957  // receivedData = true;
2958  new StoreInst(trueValue, receivedDataVariable, summaryBlock);
2959 
2960  // inputDataSummary = dataSummary;
2961  inputDataSummaryValue = new LoadInst(dataSummaryVariable, "", false, summaryBlock);
2962  }
2963  else
2964  {
2965  // inputDataSummary = <Type>_getSummary(inputData);
2966  Value *inputDataValue = inputPort->generateLoadData(module, summaryBlock, inputNodeContextValue, inputPortContextValue);
2967  inputDataSummaryValue = inputDataType->getCompiler()->generateSummaryFromValueFunctionCall(module, summaryBlock, inputDataValue);
2968  }
2969  new StoreInst(inputDataSummaryValue, inputDataSummaryVariable, summaryBlock);
2970 
2971  BranchInst::Create(sendInputBlock, summaryBlock);
2972  transmissionBlock = sendInputBlock;
2973  }
2974 
2975  Value *receivedDataValue = new LoadInst(receivedDataVariable, "", false, transmissionBlock);
2976  Value *inputDataSummaryValue = new LoadInst(inputDataSummaryVariable, "", false, transmissionBlock);
2977 
2978  Constant *inputPortIdentifierValue = constantStrings.get(module, inputPort->getIdentifier());
2979 
2980  VuoCompilerCodeGenUtilities::generateSendInputPortsUpdated(module, transmissionBlock, compositionStateValue, inputPortIdentifierValue,
2981  transmittedEventValue, receivedDataValue, inputDataSummaryValue);
2982 
2983  if (inputDataType && ! transmittedDataValue)
2984  {
2985  // free(inputDataSummary);
2986  VuoCompilerCodeGenUtilities::generateFreeCall(module, transmissionBlock, inputDataSummaryValue);
2987  }
2988  }
2989  }
2990 
2991  if (alwaysTransmitsEvent)
2992  {
2993  currentBlock = transmissionBlock;
2994  }
2995  else
2996  {
2997  BranchInst::Create(noTransmissionBlock, transmissionBlock);
2998  currentBlock = noTransmissionBlock;
2999  }
3000 
3001  if (shouldSendTelemetry && dataValue)
3002  {
3003  // free(dataSummary)
3004  Function *freeFunction = VuoCompilerCodeGenUtilities::getFreeFunction(module);
3005  LoadInst *dataSummaryValue = new LoadInst(dataSummaryVariable, "", false, currentBlock);
3006  CallInst::Create(freeFunction, dataSummaryValue, "", currentBlock);
3007  }
3008 }
3009 
3014 void VuoCompilerBitcodeGenerator::generateTransmissionFromNode(Function *function, BasicBlock *&currentBlock,
3015  Value *compositionStateValue, Value *nodeContextValue,
3016  VuoCompilerNode *node, bool requiresEvent, bool shouldSendTelemetry)
3017 {
3018  vector<VuoPort *> outputPorts = node->getBase()->getOutputPorts();
3019  for (vector<VuoPort *>::iterator i = outputPorts.begin(); i != outputPorts.end(); ++i)
3020  {
3021  // If the output port is a trigger port, do nothing.
3022  VuoCompilerOutputEventPort *outputEventPort = dynamic_cast<VuoCompilerOutputEventPort *>((*i)->getCompiler());
3023  if (! outputEventPort)
3024  continue;
3025 
3026  Value *portContextValue = outputEventPort->generateGetPortContext(module, currentBlock, nodeContextValue);
3027  Value *outputEventValue = outputEventPort->generateLoadEvent(module, currentBlock, nodeContextValue, portContextValue);
3028 
3029  BasicBlock *telemetryBlock = NULL;
3030  BasicBlock *noTelemetryBlock = NULL;
3031  if (requiresEvent)
3032  {
3033  telemetryBlock = BasicBlock::Create(module->getContext(), "", function, NULL);
3034  noTelemetryBlock = BasicBlock::Create(module->getContext(), "", function, NULL);
3035 
3036  // If the output port isn't transmitting an event, do nothing.
3037  ConstantInt *zeroValue = ConstantInt::get(static_cast<IntegerType *>(outputEventValue->getType()), 0);
3038  ICmpInst *eventValueIsTrue = new ICmpInst(*currentBlock, ICmpInst::ICMP_NE, outputEventValue, zeroValue, "");
3039  BranchInst::Create(telemetryBlock, noTelemetryBlock, eventValueIsTrue, currentBlock);
3040  }
3041  else
3042  {
3043  telemetryBlock = currentBlock;
3044  }
3045 
3046  // Transmit the data through the output port to each connected input port.
3047  VuoCompilerOutputData *outputData = outputEventPort->getData();
3048  Value *outputDataValue = (outputData ?
3049  outputEventPort->generateLoadData(module, telemetryBlock, nodeContextValue, portContextValue) :
3050  NULL);
3051  generateTransmissionFromOutputPort(function, telemetryBlock, compositionStateValue,
3052  outputEventPort, outputEventValue, outputDataValue, requiresEvent, shouldSendTelemetry);
3053 
3054  if (requiresEvent)
3055  {
3056  BranchInst::Create(noTelemetryBlock, telemetryBlock);
3057  currentBlock = noTelemetryBlock;
3058  }
3059  else
3060  {
3061  currentBlock = telemetryBlock;
3062  }
3063  }
3064 }
3065 
3070 void VuoCompilerBitcodeGenerator::generateTelemetryFromPublishedOutputNode(Function *function, BasicBlock *&currentBlock, Value *compositionStateValue,
3071  Value *nodeContextValue, VuoCompilerNode *node)
3072 {
3073  IntegerType *boolType = IntegerType::get(module->getContext(), 1);
3074  PointerType *pointerToCharType = PointerType::get(IntegerType::get(module->getContext(), 8), 0);
3075 
3076  vector<VuoPort *> inputPorts = node->getBase()->getInputPorts();
3077  for (vector<VuoPort *>::iterator i = inputPorts.begin(); i != inputPorts.end(); ++i)
3078  {
3079  VuoCompilerInputEventPort *inputEventPort = dynamic_cast<VuoCompilerInputEventPort *>((*i)->getCompiler());
3080 
3081  BasicBlock *telemetryBlock = BasicBlock::Create(module->getContext(), "", function, NULL);
3082  BasicBlock *noTelemetryBlock = BasicBlock::Create(module->getContext(), "", function, NULL);
3083 
3084  // If the published output port isn't transmitting an event, do nothing.
3085  Value *eventValue = inputEventPort->generateLoadEvent(module, currentBlock, nodeContextValue);
3086  ConstantInt *zeroValue = ConstantInt::get(static_cast<IntegerType *>(eventValue->getType()), 0);
3087  ICmpInst *eventValueIsTrue = new ICmpInst(*currentBlock, ICmpInst::ICMP_NE, eventValue, zeroValue, "");
3088  BranchInst::Create(telemetryBlock, noTelemetryBlock, eventValueIsTrue, currentBlock);
3089 
3090  VuoCompilerInputData *data = inputEventPort->getData();
3091  Value *dataValue = data ? inputEventPort->generateLoadData(module, telemetryBlock, nodeContextValue) : NULL;
3092  Constant *trueValue = ConstantInt::get(boolType, 1);
3093  Constant *falseValue = ConstantInt::get(boolType, 0);
3094 
3095  Value *sentDataValue = NULL;
3096  Value *dataSummaryValue = NULL;
3097  if (dataValue)
3098  {
3099  // sentData = true;
3100  sentDataValue = trueValue;
3101 
3102  // dataSummary = <type>_getSummary(portValue);
3103  VuoCompilerType *type = inputEventPort->getDataVuoType()->getCompiler();
3104  dataSummaryValue = type->generateSummaryFromValueFunctionCall(module, telemetryBlock, dataValue);
3105  }
3106  else
3107  {
3108  // sentData = false;
3109  sentDataValue = falseValue;
3110 
3111  // dataSummary = NULL;
3112  dataSummaryValue = ConstantPointerNull::get(pointerToCharType);
3113  }
3114 
3115  Constant *portIdentifierValue = constantStrings.get(module, inputEventPort->getBase()->getClass()->getName());
3116  VuoCompilerCodeGenUtilities::generateSendPublishedOutputPortsUpdated(module, telemetryBlock, compositionStateValue, portIdentifierValue,
3117  sentDataValue, dataSummaryValue);
3118 
3119  BranchInst::Create(noTelemetryBlock, telemetryBlock);
3120  currentBlock = noTelemetryBlock;
3121  }
3122 }
3123 
3130 void VuoCompilerBitcodeGenerator::generateDataOnlyTransmissionFromNode(Function *function, BasicBlock *&currentBlock, Value *compositionStateValue,
3131  VuoCompilerNode *node, bool shouldWaitForDownstreamNodes,
3132  bool shouldUpdateTriggers, bool shouldSendTelemetry)
3133 {
3134  vector<VuoCompilerNode *> downstreamNodes = graph->getNodesDownstreamViaDataOnlyTransmission(node);
3135  if (downstreamNodes.empty())
3136  return;
3137 
3138  if (shouldWaitForDownstreamNodes)
3139  {
3140  // Claim the nodes downstream via data-only transmission.
3141  generateWaitForNodes(module, function, currentBlock, compositionStateValue, downstreamNodes, NULL, true);
3142  }
3143 
3144  // For this node and each node downstream via data-only transmission...
3145  vector<VuoCompilerNode *> nodesToVisit = downstreamNodes;
3146  nodesToVisit.insert(nodesToVisit.begin(), node);
3147  for (VuoCompilerNode *visitedNode : nodesToVisit)
3148  {
3149  if (graph->mayTransmitDataOnly(visitedNode))
3150  {
3151  Value *nodeContextValue = visitedNode->generateGetContext(module, currentBlock, compositionStateValue);
3152 
3153  // Simulate an event having just hit all input ports of the node (necessary due to published input node's doors).
3154  vector<VuoPort *> inputPorts = visitedNode->getBase()->getInputPorts();
3155  for (size_t i = VuoNodeClass::unreservedInputPortStartIndex; i < inputPorts.size(); ++i)
3156  {
3157  VuoCompilerInputEventPort *inputEventPort = static_cast<VuoCompilerInputEventPort *>(inputPorts[i]->getCompiler());
3158  inputEventPort->generateStoreEvent(module, currentBlock, nodeContextValue, true);
3159  }
3160 
3161  // Call the node's event function, and send telemetry if needed.
3162  generateNodeExecution(function, currentBlock, compositionStateValue, visitedNode, false);
3163 
3164  // Transmit data through the node's outgoing cables, and send telemetry for port updates if needed.
3165  bool shouldSendTelemetryForNode = (shouldSendTelemetry && visitedNode != graph->getPublishedInputNode());
3166  generateTransmissionFromNode(function, currentBlock, compositionStateValue, nodeContextValue, visitedNode, false, shouldSendTelemetryForNode);
3167 
3168  // Reset the node's event inputs and outputs.
3169  VuoCompilerCodeGenUtilities::generateResetNodeContextEvents(module, currentBlock, nodeContextValue);
3170  }
3171 
3172  if (visitedNode != node)
3173  {
3174  if (shouldUpdateTriggers)
3175  {
3176  // Call the downstream node's trigger update function.
3177  visitedNode->generateCallbackUpdateFunctionCall(module, currentBlock, compositionStateValue);
3178  }
3179 
3180  if (shouldWaitForDownstreamNodes)
3181  {
3182  // Signal the downstream node.
3183  generateSignalForNodes(module, currentBlock, compositionStateValue, vector<VuoCompilerNode *>(1, visitedNode));
3184  }
3185  }
3186  }
3187 }
3188 
3192 void VuoCompilerBitcodeGenerator::generateNodeExecution(Function *function, BasicBlock *&currentBlock,
3193  Value *compositionStateValue, VuoCompilerNode *node,
3194  bool shouldSendTelemetry)
3195 {
3196  Value *nodeIdentifierValue = constantStrings.get(module, node->getIdentifier());
3197 
3198  if (shouldSendTelemetry)
3199  {
3200  // Send telemetry indicating that the node's execution has started.
3201  VuoCompilerCodeGenUtilities::generateSendNodeExecutionStarted(module, currentBlock, compositionStateValue, nodeIdentifierValue);
3202  }
3203 
3204  // Call the node's event function.
3205  if (debugMode)
3206  VuoCompilerCodeGenUtilities::generatePrint(module, currentBlock, node->getBase()->getTitle() + "\n");
3207  node->generateEventFunctionCall(module, function, currentBlock, compositionStateValue);
3208 
3209  if (shouldSendTelemetry)
3210  {
3211  // Send telemetry indicating that the node's execution has finished.
3212  VuoCompilerCodeGenUtilities::generateSendNodeExecutionFinished(module, currentBlock, compositionStateValue, nodeIdentifierValue);
3213  }
3214 }
3215 
3219 void VuoCompilerBitcodeGenerator::generateAllocation(void)
3220 {
3221 #ifdef VUO_PRO
3222  generateAllocation_Pro();
3223 #endif
3224 
3225  {
3226  Constant *value = constantStrings.get(module, VuoCompilerComposition::topLevelCompositionIdentifier);
3227  new GlobalVariable(*module, value->getType(), true, GlobalValue::ExternalLinkage, value, "vuoTopLevelCompositionIdentifier");
3228  }
3229 }
3230 
3238 void VuoCompilerBitcodeGenerator::generateSetupFunction(bool isStatefulComposition)
3239 {
3240  Function *function = VuoCompilerCodeGenUtilities::getSetupFunction(module);
3241  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
3242 
3243  Value *topLevelRuntimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, block);
3244  Value *topLevelCompositionIdentifierValue = constantStrings.get(module, VuoCompilerComposition::topLevelCompositionIdentifier);
3245  Value *topLevelCompositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, topLevelRuntimeStateValue, topLevelCompositionIdentifierValue);
3246 
3247  // Top__compositionAddNodeMetadata(compositionState);
3248 
3249  Function *compositionCreateAndRegisterMetadataFunction = VuoCompilerCodeGenUtilities::getCompositionAddNodeMetadataFunction(module);
3250  CallInst::Create(compositionCreateAndRegisterMetadataFunction, topLevelCompositionStateValue, "", block);
3251 
3252  // vuoInitContextForTopLevelComposition(compositionState, hasInstanceData, publishedOutputPortCount);
3253 
3254  size_t publishedOutputPortCount = composition->getBase()->getPublishedOutputPorts().size();
3255  VuoCompilerCodeGenUtilities::generateInitContextForTopLevelComposition(module, block, topLevelCompositionStateValue,
3256  isStatefulComposition, publishedOutputPortCount);
3257 
3258  // Set each published input port to its initial value.
3259 
3260  Function *compositionSetPublishedInputPortValueFunction = VuoCompilerCodeGenUtilities::getCompositionSetPublishedInputPortValueFunction(module);
3261  Value *falseValue = ConstantInt::get(compositionSetPublishedInputPortValueFunction->getFunctionType()->getParamType(3), 0);
3262 
3263  for (VuoPublishedPort *publishedInputPort : composition->getBase()->getPublishedInputPorts())
3264  {
3265  string name = publishedInputPort->getClass()->getName();
3266  string initialValue = static_cast<VuoCompilerPublishedPort *>(publishedInputPort->getCompiler())->getInitialValue();
3267 
3268  vector<Value *> args;
3269  args.push_back(topLevelCompositionStateValue);
3270  args.push_back( constantStrings.get(module, name) );
3271  args.push_back( constantStrings.get(module, initialValue) );
3272  args.push_back(falseValue);
3273  CallInst::Create(compositionSetPublishedInputPortValueFunction, args, "", block);
3274  }
3275 
3276  // Top__compositionPerformDataOnlyTransmissions(compositionState);
3277 
3278  Function *compositionPerformDataOnlyTransmissionsFunction = VuoCompilerCodeGenUtilities::getCompositionPerformDataOnlyTransmissionsFunction(module);
3279  CallInst::Create(compositionPerformDataOnlyTransmissionsFunction, topLevelCompositionStateValue, "", block);
3280 
3281  // Update the function pointers for all trigger functions in the top-level composition.
3282 
3283  for (map<VuoCompilerTriggerPort *, Function *>::iterator i = topLevelTriggerFunctions.begin(); i != topLevelTriggerFunctions.end(); ++i)
3284  {
3285  VuoCompilerTriggerPort *trigger = i->first;
3286  Function *function = i->second;
3287 
3288  VuoCompilerNode *node = graph->getNodeForTriggerPort(trigger);
3289  Value *nodeContextValue = node->generateGetContext(module, block, topLevelCompositionStateValue);
3290  trigger->generateStoreFunction(module, block, nodeContextValue, function);
3291  }
3292 
3293  // Update the function pointers for all trigger functions in subcompositions.
3294 
3295  for (map<string, map<size_t, map<VuoCompilerTriggerDescription *, Function *> > >::iterator i = subcompositionTriggerFunctions.begin(); i != subcompositionTriggerFunctions.end(); ++i)
3296  {
3297  string compositionIdentifier = i->first;
3298 
3299  for (map<size_t, map<VuoCompilerTriggerDescription *, Function *> >::iterator j = i->second.begin(); j != i->second.end(); ++j)
3300  {
3301  size_t nodeIndex = j->first;
3302 
3303  for (map<VuoCompilerTriggerDescription *, Function *>::iterator k = j->second.begin(); k != j->second.end(); ++k)
3304  {
3305  VuoCompilerTriggerDescription *trigger = k->first;
3306  Function *function = k->second;
3307 
3308  Value *compositionIdentifierValue = constantStrings.get(module, compositionIdentifier);
3309  Value *compositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, topLevelRuntimeStateValue, compositionIdentifierValue);
3310 
3311  int portContextIndex = trigger->getPortContextIndex();
3312  Value *nodeContextValue = VuoCompilerCodeGenUtilities::generateGetNodeContext(module, block, compositionStateValue, nodeIndex);
3313  Value *portContextValue = VuoCompilerCodeGenUtilities::generateGetNodeContextPortContext(module, block, nodeContextValue, portContextIndex);
3314  VuoCompilerCodeGenUtilities::generateSetPortContextTriggerFunction(module, block, portContextValue, function);
3315 
3316  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, compositionStateValue);
3317  }
3318  }
3319  }
3320 
3321  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, topLevelCompositionStateValue);
3322 
3323  ReturnInst::Create(module->getContext(), block);
3324 }
3325 
3332 void VuoCompilerBitcodeGenerator::generateCleanupFunction(void)
3333 {
3334  Function *function = VuoCompilerCodeGenUtilities::getCleanupFunction(module);
3335  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
3336 
3337  Value *topLevelRuntimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, block);
3338  Value *topLevelCompositionIdentifierValue = constantStrings.get(module, VuoCompilerComposition::topLevelCompositionIdentifier);
3339  Value *topLevelCompositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, topLevelRuntimeStateValue, topLevelCompositionIdentifierValue);
3340 
3341  VuoCompilerCodeGenUtilities::generateFiniContextForTopLevelComposition(module, block, topLevelCompositionStateValue);
3342 
3343  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, topLevelCompositionStateValue);
3344 
3345  ReturnInst::Create(module->getContext(), block);
3346 }
3347 
3353 void VuoCompilerBitcodeGenerator::generateInstanceInitFunction(bool isStatefulComposition)
3354 {
3355  Function *function = VuoCompilerCodeGenUtilities::getInstanceInitFunction(module);
3356  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
3357 
3358  if (isStatefulComposition)
3359  {
3360  map<VuoPort *, size_t> indexOfParameter;
3361  Function *nodeInstanceInitFunction = VuoCompilerCodeGenUtilities::getNodeInstanceInitFunction(module, moduleKey, true,
3363  vector<VuoPort *>(),
3364  indexOfParameter, constantStrings);
3365 
3366  Value *topLevelRuntimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, block);
3367  Value *topLevelCompositionIdentifierValue = constantStrings.get(module, VuoCompilerComposition::topLevelCompositionIdentifier);
3368  Value *topLevelCompositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, topLevelRuntimeStateValue, topLevelCompositionIdentifierValue);
3369 
3370  CallInst::Create(nodeInstanceInitFunction, topLevelCompositionStateValue, "", block);
3371 
3372  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, topLevelCompositionStateValue);
3373  }
3374 
3375  ReturnInst::Create(module->getContext(), block);
3376 }
3377 
3383 void VuoCompilerBitcodeGenerator::generateInstanceFiniFunction(bool isStatefulComposition)
3384 {
3385  Function *function = VuoCompilerCodeGenUtilities::getInstanceFiniFunction(module);
3386  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
3387 
3388  if (isStatefulComposition)
3389  {
3390  Function *nodeInstanceFiniFunction = VuoCompilerCodeGenUtilities::getNodeInstanceFiniFunction(module, moduleKey,
3392  constantStrings);
3393 
3394  Value *topLevelRuntimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, block);
3395  Value *topLevelCompositionIdentifierValue = constantStrings.get(module, VuoCompilerComposition::topLevelCompositionIdentifier);
3396  Value *topLevelCompositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, topLevelRuntimeStateValue, topLevelCompositionIdentifierValue);
3397 
3398  PointerType *instanceDataType = static_cast<PointerType *>( nodeInstanceFiniFunction->getFunctionType()->getParamType(1) );
3399  ConstantPointerNull *nullInstanceDataValue = ConstantPointerNull::get(instanceDataType);
3400 
3401  vector<Value *> args;
3402  args.push_back(topLevelCompositionStateValue);
3403  args.push_back(nullInstanceDataValue);
3404  CallInst::Create(nodeInstanceFiniFunction, args, "", block);
3405 
3406  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, topLevelCompositionStateValue);
3407  }
3408 
3409  ReturnInst::Create(module->getContext(), block);
3410 }
3411 
3417 void VuoCompilerBitcodeGenerator::generateInstanceTriggerStartFunction(bool isStatefulComposition)
3418 {
3420  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
3421 
3422  if (isStatefulComposition)
3423  {
3424  map<VuoPort *, size_t> indexOfParameter;
3425  Function *nodeInstanceTriggerStartFunction = VuoCompilerCodeGenUtilities::getNodeInstanceTriggerStartFunction(module, moduleKey,
3427  vector<VuoPort *>(),
3428  indexOfParameter,
3429  constantStrings);
3430 
3431  Value *topLevelRuntimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, block);
3432  Value *topLevelCompositionIdentifierValue = constantStrings.get(module, VuoCompilerComposition::topLevelCompositionIdentifier);
3433  Value *topLevelCompositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, topLevelRuntimeStateValue, topLevelCompositionIdentifierValue);
3434 
3435  PointerType *instanceDataType = static_cast<PointerType *>( nodeInstanceTriggerStartFunction->getFunctionType()->getParamType(1) );
3436  ConstantPointerNull *nullInstanceDataValue = ConstantPointerNull::get(instanceDataType);
3437 
3438  vector<Value *> args;
3439  args.push_back(topLevelCompositionStateValue);
3440  args.push_back(nullInstanceDataValue);
3441  CallInst::Create(nodeInstanceTriggerStartFunction, args, "", block);
3442 
3443  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, topLevelCompositionStateValue);
3444  }
3445 
3446  ReturnInst::Create(module->getContext(), block);
3447 }
3448 
3454 void VuoCompilerBitcodeGenerator::generateInstanceTriggerStopFunction(bool isStatefulComposition)
3455 {
3457  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
3458 
3459  {
3460  Function *nodeInstanceTriggerStopFunction = VuoCompilerCodeGenUtilities::getNodeInstanceTriggerStopFunction(module, moduleKey,
3462  constantStrings);
3463 
3464  Value *topLevelRuntimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, block);
3465  Value *topLevelCompositionIdentifierValue = constantStrings.get(module, VuoCompilerComposition::topLevelCompositionIdentifier);
3466  Value *topLevelCompositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, topLevelRuntimeStateValue, topLevelCompositionIdentifierValue);
3467 
3468  PointerType *instanceDataType = static_cast<PointerType *>( nodeInstanceTriggerStopFunction->getFunctionType()->getParamType(1) );
3469  ConstantPointerNull *nullInstanceDataValue = ConstantPointerNull::get(instanceDataType);
3470 
3471  vector<Value *> args;
3472  args.push_back(topLevelCompositionStateValue);
3473  args.push_back(nullInstanceDataValue);
3474  CallInst::Create(nodeInstanceTriggerStopFunction, args, "", block);
3475 
3476  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, topLevelCompositionStateValue);
3477  }
3478 
3479  ReturnInst::Create(module->getContext(), block);
3480 }
3481 
3487 void VuoCompilerBitcodeGenerator::generateTriggerFunctions(void)
3488 {
3489  auto isSpinOffTrigger = [] (const string &nodeClassName)
3490  {
3491  return (VuoStringUtilities::beginsWith(nodeClassName, "vuo.event.spinOff") ||
3492  VuoStringUtilities::beginsWith(nodeClassName, "vuo.list.build") ||
3493  VuoStringUtilities::beginsWith(nodeClassName, "vuo.list.process"));
3494  };
3495 
3496  map<VuoCompilerTriggerPort *, Function *> workerFunctionForTrigger;
3497  for (VuoCompilerTriggerPort *trigger : graph->getTriggerPorts())
3498  {
3499  Function *workerFunction = generateTriggerWorkerFunction(trigger);
3500  workerFunctionForTrigger[trigger] = workerFunction;
3501  }
3502 
3503  if (isTopLevelComposition)
3504  {
3505  for (map<VuoCompilerTriggerPort *, Function *>::iterator i = workerFunctionForTrigger.begin(); i != workerFunctionForTrigger.end(); ++i)
3506  {
3507  VuoCompilerTriggerPort *trigger = i->first;
3508  Function *workerFunction = i->second;
3509 
3510  VuoType *dataType = trigger->getDataVuoType();
3511 
3512  VuoCompilerNode *node = graph->getNodeForTriggerPort(trigger);
3513  size_t triggerNodeIndex = node->getIndexInOrderedNodes();
3514 
3515  string portIdentifier = trigger->getIdentifier();
3516 
3517  int portContextIndex = trigger->getIndexInPortContexts();
3518 
3519  bool canDropEvents = (trigger->getBase()->getEventThrottling() == VuoPortClass::EventThrottling_Drop);
3520 
3521  bool isPublishedTrigger = (trigger == graph->getPublishedInputTrigger());
3522 
3523  bool isSpinOff = isSpinOffTrigger(node->getBase()->getNodeClass()->getClassName());
3524 
3525  int minThreadsNeeded, maxThreadsNeeded;
3526  graph->getWorkerThreadsNeeded(trigger, minThreadsNeeded, maxThreadsNeeded);
3527 
3528  int chainCount = (int)graph->getChains()[trigger].size();
3529 
3530  Function *function = generateTriggerSchedulerFunction(dataType, VuoCompilerComposition::topLevelCompositionIdentifier, triggerNodeIndex,
3531  portIdentifier, portContextIndex, canDropEvents, isPublishedTrigger, isSpinOff,
3532  minThreadsNeeded, maxThreadsNeeded, chainCount, workerFunction);
3533  topLevelTriggerFunctions[trigger] = function;
3534  }
3535 
3536  for (VuoCompilerNode *node : graph->getNodes())
3537  {
3538  VuoCompilerNodeClass *nodeClass = node->getBase()->getNodeClass()->getCompiler();
3539 
3541  node->getGraphvizIdentifier());
3542 
3543  vector<VuoCompilerTriggerDescription *> triggers = nodeClass->getTriggerDescriptions();
3544  for (vector<VuoCompilerTriggerDescription *>::iterator j = triggers.begin(); j != triggers.end(); ++j)
3545  {
3546  VuoCompilerTriggerDescription *trigger = *j;
3547 
3548  size_t triggerNodeIndex = trigger->getNodeIndex();
3549  string triggerNodeIdentifier = trigger->getNodeIdentifier();
3550  string portIdentifier = VuoStringUtilities::buildPortIdentifier(triggerNodeIdentifier, trigger->getPortName());
3551  int portContextIndex = trigger->getPortContextIndex();
3552  bool canDropEvents = (trigger->getEventThrottling() == VuoPortClass::EventThrottling_Drop);
3553  VuoType *dataType = trigger->getDataType();
3554  string subcompositionNodeClassName = trigger->getSubcompositionNodeClassName();
3555  VuoCompilerNodeClass *subcompositionNodeClass = (subcompositionNodeClassName.empty() ?
3556  nodeClass :
3557  compiler->getNodeClass(subcompositionNodeClassName));
3558  string subcompositionNodeIdentifier = trigger->getSubcompositionNodeIdentifier();
3559  string fullSubcompositionNodeIdentifier = (subcompositionNodeIdentifier.empty() ?
3560  nodeIdentifier :
3561  VuoStringUtilities::buildCompositionIdentifier(nodeIdentifier, subcompositionNodeIdentifier));
3562  bool isPublishedTrigger = (triggerNodeIdentifier == graph->getPublishedInputTriggerNodeIdentifier());
3563 
3564  bool isSpinOff = isSpinOffTrigger(trigger->getNodeClassName());
3565 
3566  int minThreadsNeeded, maxThreadsNeeded;
3567  if (isPublishedTrigger)
3568  minThreadsNeeded = maxThreadsNeeded = -1;
3569  else
3570  trigger->getWorkerThreadsNeeded(minThreadsNeeded, maxThreadsNeeded);
3571 
3572  int chainCount = trigger->getChainCount();
3573 
3574  Function *workerFunctionSrc = subcompositionNodeClass->getTriggerWorkerFunction(portIdentifier);
3575  Function *workerFunction = VuoCompilerModule::declareFunctionInModule(module, workerFunctionSrc);
3576 
3577  Function *function = generateTriggerSchedulerFunction(dataType, fullSubcompositionNodeIdentifier, triggerNodeIndex,
3578  portIdentifier, portContextIndex, canDropEvents, isPublishedTrigger, isSpinOff,
3579  minThreadsNeeded, maxThreadsNeeded, chainCount, workerFunction);
3580 
3581  subcompositionTriggerFunctions[fullSubcompositionNodeIdentifier][triggerNodeIndex][trigger] = function;
3582  }
3583  }
3584  }
3585 }
3586 
3630 Function * VuoCompilerBitcodeGenerator::generateTriggerSchedulerFunction(VuoType *dataType,
3631  string compositionIdentifier, size_t nodeIndex,
3632  string portIdentifier, int portContextIndex,
3633  bool canDropEvents, bool isPublishedInputTrigger, bool isSpinOff,
3634  int minThreadsNeeded, int maxThreadsNeeded, int chainCount,
3635  Function *workerFunction)
3636 {
3637  string functionName = VuoStringUtilities::prefixSymbolName(workerFunction->getName().str(),
3638  VuoStringUtilities::transcodeToIdentifier(compositionIdentifier));
3639  FunctionType *functionType = VuoCompilerCodeGenUtilities::getFunctionType(module, dataType);
3640  Function *function = Function::Create(functionType, GlobalValue::InternalLinkage, functionName, module);
3641 
3642  if (dataType)
3643  {
3644  AttributeSet paramAttributes = dataType->getCompiler()->getFunctionParameterAttributes();
3645  function->setAttributes(paramAttributes);
3646  }
3647 
3648  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, NULL);
3649  BasicBlock *finalBlock = BasicBlock::Create(module->getContext(), "final", function, NULL);
3650  BasicBlock *scheduleBlock = BasicBlock::Create(module->getContext(), "schedule", function, NULL);
3651 
3652  Value *runtimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, initialBlock);
3653  Value *compositionIdentifierValue = constantStrings.get(module, compositionIdentifier);
3654 
3655  Value *compositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, initialBlock, runtimeStateValue, compositionIdentifierValue);
3656  VuoCompilerCodeGenUtilities::generateRegisterCall(module, initialBlock, compositionStateValue, VuoCompilerCodeGenUtilities::getFreeFunction(module));
3657  VuoCompilerCodeGenUtilities::generateRetainCall(module, initialBlock, compositionStateValue);
3658 
3659  Value *nodeContextValue = VuoCompilerCodeGenUtilities::generateGetNodeContext(module, initialBlock, compositionStateValue, nodeIndex);
3660  Value *portContextValue = VuoCompilerCodeGenUtilities::generateGetNodeContextPortContext(module, initialBlock, nodeContextValue, portContextIndex);
3661 
3662  if (canDropEvents)
3663  {
3664  BasicBlock *checkEventDropBlock = BasicBlock::Create(module->getContext(), "checkEventDrop", function, NULL);
3665  BranchInst::Create(checkEventDropBlock, initialBlock);
3666 
3667  // Do a non-blocking wait on the trigger's semaphore to check if it's already claimed. If so...
3668  Value *retValue = VuoCompilerTriggerPort::generateNonBlockingWaitForSemaphore(module, checkEventDropBlock, portContextValue);
3669  Constant *zeroValue = ConstantInt::get(retValue->getType(), 0);
3670  ICmpInst *isTriggerAvailableValue = new ICmpInst(*checkEventDropBlock, ICmpInst::ICMP_EQ, retValue, zeroValue, "");
3671  BasicBlock *dropEventBlock = BasicBlock::Create(module->getContext(), "dropEvent", function, NULL);
3672  BranchInst::Create(scheduleBlock, dropEventBlock, isTriggerAvailableValue, checkEventDropBlock);
3673 
3674  // Release the data value.
3675  if (dataType)
3676  VuoCompilerTriggerPort::generateDataValueDiscardFromScheduler(module, function, dropEventBlock, dataType);
3677 
3678  // Send telemetry that the event has been dropped.
3679  Constant *portIdentifierValue = constantStrings.get(module, portIdentifier);
3680  VuoCompilerCodeGenUtilities::generateSendEventDropped(module, dropEventBlock, compositionStateValue, portIdentifierValue);
3681 
3682  VuoCompilerCodeGenUtilities::generateReleaseCall(module, dropEventBlock, compositionStateValue);
3683 
3684  BranchInst::Create(finalBlock, dropEventBlock);
3685  }
3686  else
3687  {
3688  BranchInst::Create(scheduleBlock, initialBlock);
3689  }
3690 
3691  // Enter the trigger's dispatch group for tracking workers scheduled.
3692  Value *triggerWorkersScheduledValue = VuoCompilerCodeGenUtilities::getTriggerWorkersScheduledValue(module, scheduleBlock, compositionStateValue);
3693  VuoCompilerCodeGenUtilities::generateEnterDispatchGroup(module, scheduleBlock, triggerWorkersScheduledValue);
3694 
3695  Value *eventIdValue;
3696  if (! isPublishedInputTrigger)
3697  {
3698  // Get a unique ID for this event.
3699  eventIdValue = VuoCompilerCodeGenUtilities::generateGetNextEventId(module, scheduleBlock, compositionStateValue);
3700 
3701  // If this trigger fires in response to an input event, and the original event came from the published input trigger,
3702  // associate the new (spun off) event's ID with the original event.
3703  if (isSpinOff)
3704  {
3705  Value *compositionContextValue = VuoCompilerCodeGenUtilities::generateGetCompositionContext(module, scheduleBlock, compositionStateValue);
3706  VuoCompilerCodeGenUtilities::generateSpunOffExecutingEvent(module, scheduleBlock, compositionContextValue, eventIdValue);
3707  }
3708  }
3709  else
3710  {
3711  // Use the event ID from the parent composition or `firePublishedInputTrigger()`.
3712  Value *compositionContextValue = VuoCompilerCodeGenUtilities::generateGetCompositionContext(module, scheduleBlock, compositionStateValue);
3713  eventIdValue = VuoCompilerCodeGenUtilities::generateGetOneExecutingEvent(module, scheduleBlock, compositionContextValue);
3714  }
3715 
3716  // Schedule the trigger's worker function via `vuoScheduleTriggerWorker()`.
3717  VuoCompilerTriggerPort::generateScheduleWorker(module, function, scheduleBlock,
3718  compositionStateValue, eventIdValue, portContextValue, dataType,
3719  minThreadsNeeded, maxThreadsNeeded, chainCount, workerFunction);
3720  BranchInst::Create(finalBlock, scheduleBlock);
3721 
3722  ReturnInst::Create(module->getContext(), finalBlock);
3723 
3724  return function;
3725 }
3726 
3871 Function * VuoCompilerBitcodeGenerator::generateTriggerWorkerFunction(VuoCompilerTriggerPort *trigger)
3872 {
3874  Function *function = trigger->getWorkerFunction(module, functionName, true);
3875 
3876  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, NULL);
3877  BasicBlock *triggerBlock = BasicBlock::Create(module->getContext(), "trigger", function, NULL);
3878  BasicBlock *finalBlock = BasicBlock::Create(module->getContext(), "final", function, NULL);
3879 
3880  Value *compositionStateValue = trigger->generateCompositionStateValue(module, initialBlock, function);
3881  Value *compositionContextValue = VuoCompilerCodeGenUtilities::generateGetCompositionContext(module, initialBlock, compositionStateValue);
3882  Value *eventIdValue = trigger->generateEventIdValue(module, initialBlock, function);
3883 
3884  VuoCompilerNode *triggerNode = graph->getNodeForTriggerPort(trigger);
3885  Value *triggerNodeContextValue = triggerNode->generateGetContext(module, initialBlock, compositionStateValue);
3886  Value *triggerWorkersScheduledValue = VuoCompilerCodeGenUtilities::getTriggerWorkersScheduledValue(module, initialBlock, compositionStateValue);
3887  bool canDropEvents = (trigger->getBase()->getEventThrottling() == VuoPortClass::EventThrottling_Drop);
3888 
3889  bool isPublishedInputTrigger = (trigger == graph->getPublishedInputTrigger());
3890  bool isNodeEventForSubcomposition = (! isTopLevelComposition && isPublishedInputTrigger);
3891 
3892  if (! isNodeEventForSubcomposition)
3893  {
3894  // Check if `isPaused` is true. If so...
3895  BasicBlock *isPausedBlock = BasicBlock::Create(module->getContext(), "isPaused", function, NULL);
3896  ICmpInst *isPausedValueIsTrue = VuoCompilerCodeGenUtilities::generateIsPausedComparison(module, initialBlock, compositionStateValue);
3897  BranchInst::Create(isPausedBlock, triggerBlock, isPausedValueIsTrue, initialBlock);
3898 
3899  // Release the data value.
3900  trigger->generateDataValueDiscardFromWorker(module, isPausedBlock, function);
3901 
3902  // Wait for the published output node's semaphore, if not already claimed in `firePublishedInputPortEvent()`.
3903  VuoCompilerNode *publishedOutputNode = graph->getPublishedOutputNode();
3904  vector<VuoCompilerNode *> publishedOutputNodeVector(1, publishedOutputNode);
3905  if (publishedOutputNode && ! isPublishedInputTrigger)
3906  generateWaitForNodes(module, function, isPausedBlock, compositionStateValue, publishedOutputNodeVector);
3907 
3908  // Call `vuoSendEventFinished()`.
3909  VuoCompilerCodeGenUtilities::generateSendEventFinished(module, isPausedBlock, compositionStateValue, eventIdValue);
3910 
3911  if (isPublishedInputTrigger)
3912  {
3913  // Signal the semaphores claimed in `firePublishedInputPortEvent()`.
3914  vector<VuoCompilerNode *> triggerWaitNodes = getNodesToWaitOnBeforeTransmission(trigger);
3915  generateSignalForNodes(module, isPausedBlock, compositionStateValue, triggerWaitNodes);
3916  }
3917 
3918  // Signal the published output node's semaphore.
3919  if (publishedOutputNode)
3920  generateSignalForNodes(module, isPausedBlock, compositionStateValue, publishedOutputNodeVector);
3921 
3922  if (canDropEvents)
3923  // Signal the trigger's semaphore for event dropping.
3924  trigger->generateSignalForSemaphore(module, isPausedBlock, triggerNodeContextValue);
3925 
3926  // Leave the trigger's dispatch group for tracking workers scheduled.
3927  VuoCompilerCodeGenUtilities::generateLeaveDispatchGroup(module, isPausedBlock, triggerWorkersScheduledValue);
3928 
3929  // Call `vuoReturnThreadsForTriggerWorker()`.
3930  VuoCompilerCodeGenUtilities::generateReturnThreadsForTriggerWorker(module, isPausedBlock, eventIdValue, compositionStateValue);
3931 
3932  BranchInst::Create(finalBlock, isPausedBlock);
3933  // Otherwise...
3934  }
3935  else
3936  {
3937  BranchInst::Create(triggerBlock, initialBlock);
3938  }
3939 
3940  if (isPublishedInputTrigger)
3941  {
3942  if (! isNodeEventForSubcomposition)
3943  {
3944  // Signal the published output node if it was waited on in `firePublishedInputPortEvent()` just to track event start/finished.
3945  vector<VuoCompilerNode *> triggerWaitNodes = getNodesToWaitOnBeforeTransmission(trigger);
3946  VuoCompilerNode *publishedOutputNode = graph->getPublishedOutputNode();
3947  if (find(triggerWaitNodes.begin(), triggerWaitNodes.end(), publishedOutputNode) == triggerWaitNodes.end())
3948  {
3949  vector<VuoCompilerNode *> publishedOutputNodeVector(1, publishedOutputNode);
3950  generateSignalForNodes(module, triggerBlock, compositionStateValue, publishedOutputNodeVector);
3951  }
3952  }
3953  }
3954  else
3955  {
3956  // Claim the semaphores of all necessary downstream nodes.
3957  vector<VuoCompilerNode *> triggerWaitNodes = getNodesToWaitOnBeforeTransmission(trigger);
3958  generateWaitForNodes(module, function, triggerBlock, compositionStateValue, triggerWaitNodes, eventIdValue);
3959 
3960  // Update the trigger's data value.
3961  Value *triggerDataValue = trigger->generateDataValueUpdate(module, triggerBlock, function, triggerNodeContextValue);
3962 
3963  // Transmit events and data (if any) out of the trigger port, and send telemetry for port updates.
3964  generateTransmissionFromOutputPort(function, triggerBlock, compositionStateValue, trigger, NULL, triggerDataValue);
3965  }
3966 
3967  // If the trigger node isn't downstream of the trigger, signal the trigger node's semaphore.
3968  vector<VuoCompilerNode *> downstreamNodes = graph->getNodesDownstream(trigger);
3969  if (find(downstreamNodes.begin(), downstreamNodes.end(), triggerNode) == downstreamNodes.end())
3970  generateSignalForNodes(module, triggerBlock, compositionStateValue, vector<VuoCompilerNode *>(1, triggerNode));
3971 
3972  if (canDropEvents)
3973  // Signal the trigger's semaphore for event dropping.
3974  trigger->generateSignalForSemaphore(module, triggerBlock, triggerNodeContextValue);
3975 
3976  // Leave the trigger's dispatch group for tracking workers scheduled.
3977  VuoCompilerCodeGenUtilities::generateLeaveDispatchGroup(module, triggerBlock, triggerWorkersScheduledValue);
3978 
3979 
3980  // Schedule the chain worker function for each chain immediately downstream of the trigger.
3981 
3982  map<VuoCompilerChain *, vector<VuoCompilerChain *> > chainsImmediatelyDownstream;
3983  map<VuoCompilerChain *, vector<VuoCompilerChain *> > chainsImmediatelyUpstream;
3984  set<VuoCompilerChain *> chainsScheduled;
3985 
3986  vector<VuoCompilerChain *> allChains = chainsForTrigger[trigger];
3987 
3988  if (! allChains.empty())
3989  {
3990  // Organize the chains so it's easy to look up what's downstream/upstream of what.
3991  for (vector<VuoCompilerChain *>::iterator i = allChains.begin(); i != allChains.end(); ++i)
3992  {
3993  VuoCompilerChain *chain = *i;
3994  VuoCompilerNode *firstNodeInThisChain = chain->getNodes().front();
3995 
3996  for (vector<VuoCompilerChain *>::iterator j = allChains.begin(); j != allChains.end(); ++j)
3997  {
3998  VuoCompilerChain *otherChain = *j;
3999 
4000  if (chain == otherChain)
4001  break; // Any chains after this are downstream.
4002 
4003  VuoCompilerNode *lastNodeInOtherChain = otherChain->getNodes().back();
4004 
4005  if (graph->mayTransmit(lastNodeInOtherChain, firstNodeInThisChain, trigger))
4006  {
4007  chainsImmediatelyUpstream[chain].push_back(otherChain);
4008  chainsImmediatelyDownstream[otherChain].push_back(chain);
4009  }
4010  }
4011  }
4012 
4013  // Create the context to pass to the chain workers.
4014  Value *contextValue = VuoCompilerChain::generateMakeContext(module, triggerBlock, compositionStateValue, eventIdValue);
4015 
4016  // Find all chains immediately downstream of the trigger (i.e., chains that have no other chains upstream).
4017  vector<VuoCompilerChain *> firstChains;
4018  for (vector<VuoCompilerChain *>::iterator i = allChains.begin(); i != allChains.end(); ++i)
4019  {
4020  VuoCompilerChain *chain = *i;
4021  map<VuoCompilerChain *, vector<VuoCompilerChain *> >::iterator upstreamIter = chainsImmediatelyUpstream.find(chain);
4022  if (upstreamIter == chainsImmediatelyUpstream.end())
4023  firstChains.push_back(chain);
4024  }
4025 
4026  // Choose one chain to execute in the trigger worker, to reduce overhead creating/destroying threads.
4027  VuoCompilerChain *chainToExecute = firstChains.back();
4028  firstChains.pop_back();
4029  chainsScheduled.insert(chainToExecute);
4030  size_t chainIndex = find(allChains.begin(), allChains.end(), chainToExecute) - allChains.begin();
4031  VuoCompilerCodeGenUtilities::generateRetainCall(module, triggerBlock, contextValue);
4032 
4033  // Call `vuoGrantThreadsToChain()` for the chosen chain.
4034  int minThreadsNeeded, maxThreadsNeeded;
4035  graph->getWorkerThreadsNeeded(chainToExecute, minThreadsNeeded, maxThreadsNeeded);
4036  VuoCompilerCodeGenUtilities::generateGrantThreadsToChain(module, triggerBlock, minThreadsNeeded, maxThreadsNeeded,
4037  eventIdValue, compositionStateValue, chainIndex);
4038 
4039  // Schedule the rest of the chains immediately downstream of the trigger.
4040  generateAndScheduleChainWorkerFunctions(triggerBlock, compositionStateValue, contextValue, firstChains, trigger,
4041  allChains, chainsImmediatelyDownstream, chainsImmediatelyUpstream, chainsScheduled);
4042 
4043  // Execute the chosen chain.
4044  generateChainExecution(function, triggerBlock, compositionStateValue, contextValue, eventIdValue, chainToExecute, trigger,
4045  allChains, chainsImmediatelyDownstream, chainsImmediatelyUpstream, chainsScheduled);
4046  VuoCompilerCodeGenUtilities::generateReleaseCall(module, triggerBlock, contextValue);
4047  }
4048  else
4049  {
4050  // Call `vuoReturnThreadsForTriggerWorker()`.
4051  VuoCompilerCodeGenUtilities::generateReturnThreadsForTriggerWorker(module, triggerBlock, eventIdValue, compositionStateValue);
4052 
4053  if (isNodeEventForSubcomposition)
4054  {
4055  // Leave the dispatch group waited on by `nodeEvent()`/`nodeInstanceEvent()`.
4056  Value *subcompositionOutputGroupValue = VuoCompilerCodeGenUtilities::generateGetNodeContextExecutingGroup(module, triggerBlock, compositionContextValue);
4057  VuoCompilerCodeGenUtilities::generateLeaveDispatchGroup(module, triggerBlock, subcompositionOutputGroupValue);
4058  }
4059  }
4060 
4061  BranchInst::Create(finalBlock, triggerBlock);
4062 
4063  // Free the trigger worker's context.
4064  trigger->generateFreeContext(module, finalBlock, function);
4065  VuoCompilerCodeGenUtilities::generateReleaseCall(module, finalBlock, compositionStateValue);
4066 
4067  ReturnInst::Create(module->getContext(), finalBlock);
4068 
4069  return function;
4070 }
4071 
4075 void VuoCompilerBitcodeGenerator::generateAndScheduleChainWorkerFunctions(BasicBlock *schedulerBlock,
4076  Value *compositionStateValueInScheduler, Value *contextValueInScheduler,
4077  const vector<VuoCompilerChain *> &chainsToSchedule, VuoCompilerTriggerPort *trigger,
4078  const vector<VuoCompilerChain *> &allChains,
4079  const map<VuoCompilerChain *, vector<VuoCompilerChain *> > &chainsImmediatelyDownstream,
4080  const map<VuoCompilerChain *, vector<VuoCompilerChain *> > &chainsImmediatelyUpstream,
4081  set<VuoCompilerChain *> &chainsScheduled)
4082 {
4083  // Find the chains in chainsToSchedule that haven't already been scheduled.
4084  vector<VuoCompilerChain *> uniqueChainsToSchedule;
4085  for (vector<VuoCompilerChain *>::const_iterator i = chainsToSchedule.begin(); i != chainsToSchedule.end(); ++i)
4086  {
4087  VuoCompilerChain *chain = *i;
4088  if (chainsScheduled.find(chain) == chainsScheduled.end())
4089  {
4090  uniqueChainsToSchedule.push_back(chain);
4091  chainsScheduled.insert(chain);
4092  }
4093  }
4094 
4095  // Retain the context once for each chain to be scheduled.
4096  for (vector<VuoCompilerChain *>::const_iterator i = uniqueChainsToSchedule.begin(); i != uniqueChainsToSchedule.end(); ++i)
4097  VuoCompilerCodeGenUtilities::generateRetainCall(module, schedulerBlock, contextValueInScheduler);
4098 
4099  // Schedule each chain.
4100  for (vector<VuoCompilerChain *>::const_iterator i = uniqueChainsToSchedule.begin(); i != uniqueChainsToSchedule.end(); ++i)
4101  {
4102  VuoCompilerChain *chain = *i;
4103  generateAndScheduleChainWorkerFunction(schedulerBlock, compositionStateValueInScheduler, contextValueInScheduler,
4104  chain, trigger, allChains, chainsImmediatelyDownstream, chainsImmediatelyUpstream,
4105  chainsScheduled);
4106  }
4107 }
4108 
4112 void VuoCompilerBitcodeGenerator::generateAndScheduleChainWorkerFunction(BasicBlock *schedulerBlock,
4113  Value *compositionStateValueInScheduler, Value *contextValueInScheduler,
4114  VuoCompilerChain *chain, VuoCompilerTriggerPort *trigger,
4115  const vector<VuoCompilerChain *> &allChains,
4116  const map<VuoCompilerChain *, vector<VuoCompilerChain *> > &chainsImmediatelyDownstream,
4117  const map<VuoCompilerChain *, vector<VuoCompilerChain *> > &chainsImmediatelyUpstream,
4118  set<VuoCompilerChain *> &chainsScheduled)
4119 {
4120  int minThreadsNeeded, maxThreadsNeeded;
4121  graph->getWorkerThreadsNeeded(chain, minThreadsNeeded, maxThreadsNeeded);
4122 
4123  size_t chainIndex = find(allChains.begin(), allChains.end(), chain) - allChains.begin();
4124 
4125  vector<VuoCompilerChain *> upstreamChains;
4126  map<VuoCompilerChain *, vector<VuoCompilerChain *> >::const_iterator upstreamChainsIter = chainsImmediatelyUpstream.find(chain);
4127  if (upstreamChainsIter != chainsImmediatelyUpstream.end())
4128  upstreamChains = upstreamChainsIter->second;
4129 
4130  vector<size_t> upstreamChainIndices;
4131  for (vector<VuoCompilerChain *>::iterator i = upstreamChains.begin(); i != upstreamChains.end(); ++i)
4132  upstreamChainIndices.push_back( find(allChains.begin(), allChains.end(), *i) - allChains.begin() );
4133 
4134  // Call `vuoScheduleChainWorker` for the worker function implemented below.
4135  Function *chainWorker = chain->generateScheduleWorker(module, schedulerBlock, compositionStateValueInScheduler, contextValueInScheduler,
4136  trigger->getIdentifier(), minThreadsNeeded, maxThreadsNeeded, chainIndex,
4137  upstreamChainIndices);
4138 
4139  BasicBlock *chainBlock = BasicBlock::Create(module->getContext(), "", chainWorker, 0);
4140  Value *contextValueInChainWorker = chainWorker->arg_begin();
4141  Value *compositionStateValueInChainWorker = chain->generateCompositionStateValue(module, chainBlock, contextValueInChainWorker);
4142  Value *eventIdValue = chain->generateEventIdValue(module, chainBlock, contextValueInChainWorker);
4143 
4144  // Execute the chain.
4145  generateChainExecution(chainWorker, chainBlock, compositionStateValueInChainWorker, contextValueInChainWorker, eventIdValue, chain, trigger,
4146  allChains, chainsImmediatelyDownstream, chainsImmediatelyUpstream, chainsScheduled);
4147 
4148  // Release the chain worker's context.
4149  VuoCompilerCodeGenUtilities::generateReleaseCall(module, chainBlock, contextValueInChainWorker);
4150 
4151  ReturnInst::Create(module->getContext(), chainBlock);
4152 }
4153 
4157 void VuoCompilerBitcodeGenerator::generateChainExecution(Function *function, BasicBlock *&block,
4158  Value *compositionStateValue, Value *contextValue,
4159  Value *eventIdValue, VuoCompilerChain *chain, VuoCompilerTriggerPort *trigger,
4160  const vector<VuoCompilerChain *> &allChains,
4161  const map<VuoCompilerChain *, vector<VuoCompilerChain *> > &chainsImmediatelyDownstream,
4162  const map<VuoCompilerChain *, vector<VuoCompilerChain *> > &chainsImmediatelyUpstream,
4163  set<VuoCompilerChain *> &chainsScheduled)
4164 {
4165  size_t chainIndex = find(allChains.begin(), allChains.end(), chain) - allChains.begin();
4166  Value *chainIndexValue = ConstantInt::get(eventIdValue->getType(), chainIndex);
4167 
4168  // For each node in the chain...
4169  vector<VuoCompilerNode *> chainNodes = chain->getNodes();
4170  for (vector<VuoCompilerNode *>::iterator i = chainNodes.begin(); i != chainNodes.end(); ++i)
4171  {
4172  VuoCompilerNode *node = *i;
4173 
4174  Function *nodeExecutionFunction = executionFunctionForNode[node];
4175  if (! nodeExecutionFunction)
4176  {
4177  nodeExecutionFunction = generateNodeExecutionFunction(module, node);
4178  executionFunctionForNode[node] = nodeExecutionFunction;
4179  }
4180 
4181  Function *nodeTransmissionFunction = transmissionFunctionForNode[node];
4182  if (! nodeTransmissionFunction)
4183  {
4184  nodeTransmissionFunction = generateNodeTransmissionFunction(module, node);
4185  transmissionFunctionForNode[node] = nodeTransmissionFunction;
4186  }
4187 
4188  // If the event hit the node, call its event function and send telemetry.
4189  vector<Value *> nodeExecutionArgs;
4190  nodeExecutionArgs.push_back(compositionStateValue);
4191  nodeExecutionArgs.push_back(eventIdValue);
4192  nodeExecutionArgs.push_back(chainIndexValue);
4193  CallInst *isHitValue = CallInst::Create(nodeExecutionFunction, nodeExecutionArgs, "", block);
4194 
4195  // Whether or not the event hit the node, wait on any necessary downstream nodes.
4196  if (! (graph->isRepeatedInFeedbackLoop(node, trigger) && chain->isLastNodeInLoop()))
4197  {
4198  vector<VuoCompilerNode *> outputNodes = getNodesToWaitOnBeforeTransmission(trigger, node);
4199  generateWaitForNodes(module, function, block, compositionStateValue, outputNodes, eventIdValue);
4200  }
4201 
4202  // If the event hit the node, transmit events and data through its output cables and send telemetry.
4203  vector<Value *> nodeTransmissionArgs;
4204  nodeTransmissionArgs.push_back(compositionStateValue);
4205  nodeTransmissionArgs.push_back(isHitValue);
4206  CallInst::Create(nodeTransmissionFunction, nodeTransmissionArgs, "", block);
4207 
4208  // Whether or not the event hit the node, if this was the last time this event could reach the node,
4209  // signal the node's semaphore.
4210  if (! (graph->isRepeatedInFeedbackLoop(node, trigger) && ! chain->isLastNodeInLoop()))
4211  {
4212  // Special case: If this is the published output node in a subcomposition,
4213  // the node's semaphore is signaled in the node's execution function or the subcomposition's nodeEvent()/nodeInstanceEvent().
4214  if (! (! isTopLevelComposition && node == graph->getPublishedOutputNode()))
4215  generateSignalForNodes(module, block, compositionStateValue, vector<VuoCompilerNode *>(1, node));
4216  }
4217  }
4218 
4219  // Schedule any chains immediately downstream, if this chain is the one responsible for doing so.
4220  vector<VuoCompilerChain *> downstreamChains;
4221  map<VuoCompilerChain *, vector<VuoCompilerChain *> >::const_iterator downstreamChainsIter = chainsImmediatelyDownstream.find(chain);
4222  if (downstreamChainsIter != chainsImmediatelyDownstream.end())
4223  downstreamChains = downstreamChainsIter->second;
4224  if (! downstreamChains.empty())
4225  {
4226  vector<size_t> downstreamChainIndices;
4227  for (vector<VuoCompilerChain *>::iterator i = downstreamChains.begin(); i != downstreamChains.end(); ++i)
4228  downstreamChainIndices.push_back( find(allChains.begin(), allChains.end(), *i) - allChains.begin() );
4229 
4230  vector<VuoCompilerChain *> nextChains;
4231  for (vector<VuoCompilerChain *>::iterator i = downstreamChains.begin(); i != downstreamChains.end(); ++i)
4232  {
4233  VuoCompilerChain *downstreamChain = *i;
4234  nextChains.push_back(downstreamChain);
4235  }
4236 
4237  generateAndScheduleChainWorkerFunctions(block, compositionStateValue, contextValue, nextChains, trigger, allChains,
4238  chainsImmediatelyDownstream, chainsImmediatelyUpstream, chainsScheduled);
4239  }
4240 
4241  // Return the threads used by this chain to the thread pool.
4242  VuoCompilerCodeGenUtilities::generateReturnThreadsForChainWorker(module, block, eventIdValue, compositionStateValue, chainIndexValue);
4243 }
4244 
4290 Function * VuoCompilerBitcodeGenerator::generateNodeExecutionFunction(Module *module, VuoCompilerNode *node)
4291 {
4292  string functionName = node->getIdentifier() + "__execute";
4293  PointerType *pointerToCompositionStateType = PointerType::get(VuoCompilerCodeGenUtilities::getCompositionStateType(module), 0);
4294  Type *boolType = IntegerType::get(module->getContext(), 1);
4295  Type *eventIdType = VuoCompilerCodeGenUtilities::generateNoEventIdConstant(module)->getType();
4296  vector<Type *> params;
4297  params.push_back(pointerToCompositionStateType);
4298  params.push_back(eventIdType);
4299  params.push_back(eventIdType);
4300  FunctionType *functionType = FunctionType::get(boolType, params, false);
4301  Function *function = Function::Create(functionType, GlobalValue::InternalLinkage, functionName, module);
4302 
4303  Function::arg_iterator args = function->arg_begin();
4304  Value *compositionStateValue = args++;
4305  compositionStateValue->setName("compositionState");
4306  Value *eventIdValue = args++;
4307  eventIdValue->setName("eventId");
4308  Value *chainIndexValue = args++;
4309  chainIndexValue->setName("chainIndex");
4310 
4311  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, NULL);
4312  BasicBlock *finalBlock = BasicBlock::Create(module->getContext(), "final", function, NULL);
4313 
4314  Value *nodeContextValue = node->generateGetContext(module, initialBlock, compositionStateValue);
4315  Value *isHitValue = node->generateReceivedEventCondition(module, initialBlock, nodeContextValue);
4316 
4317  if (node == graph->getPublishedOutputNode())
4318  {
4319  if (isTopLevelComposition)
4320  {
4321  VuoCompilerCodeGenUtilities::generateSendEventFinished(module, initialBlock, compositionStateValue, eventIdValue);
4322 
4323  BranchInst::Create(finalBlock, initialBlock);
4324  }
4325  else
4326  {
4327  // Call the trigger functions for any published trigger ports that the event has hit.
4328 
4329  BasicBlock *currBlock = initialBlock;
4330 
4331  Value *compositionContextValue = VuoCompilerCodeGenUtilities::generateGetCompositionContext(module, currBlock, compositionStateValue);
4332 
4333  vector<VuoPublishedPort *> publishedInputPorts = composition->getBase()->getPublishedInputPorts();
4334  vector<VuoPublishedPort *> publishedOutputPorts = composition->getBase()->getPublishedOutputPorts();
4335 
4336  set<string> publishedOutputTriggerNames = graph->getPublishedOutputTriggers();
4337 
4338  for (size_t publishedPortIndex = 0; publishedPortIndex < publishedOutputPorts.size(); ++publishedPortIndex)
4339  {
4340  VuoPort *port = graph->getInputPortOnPublishedOutputNode(publishedPortIndex);
4341 
4342  Value *isPortHitValue = node->generateReceivedEventCondition(module, currBlock, nodeContextValue, vector<VuoPort *>(1, port));
4343 
4344  if (publishedOutputTriggerNames.find( port->getClass()->getName() ) != publishedOutputTriggerNames.end())
4345  {
4346  BasicBlock *triggerBlock = BasicBlock::Create(module->getContext(), "trigger", function, NULL);
4347  BasicBlock *nextBlock = BasicBlock::Create(module->getContext(), "next", function, NULL);
4348  BranchInst::Create(triggerBlock, nextBlock, isPortHitValue, currBlock);
4349 
4350  VuoCompilerInputEventPort *eventPort = static_cast<VuoCompilerInputEventPort *>( port->getCompiler() );
4351  VuoCompilerInputEventPortClass *eventPortClass = static_cast<VuoCompilerInputEventPortClass *>( port->getClass()->getCompiler() );
4352  VuoType *dataType = eventPort->getDataVuoType();
4353 
4354  FunctionType *triggerFunctionType = VuoCompilerCodeGenUtilities::getFunctionType(module, dataType);
4355 
4356  vector<Value *> args;
4357  if (dataType)
4358  {
4359  Value *dataValue = eventPort->generateLoadData(module, triggerBlock, nodeContextValue);
4360  bool isPassedByValue = dataType->getCompiler()->getFunctionParameterAttributes().hasAttrSomewhere(Attribute::ByVal);
4361  bool isLoweredToTwoParameters = eventPortClass->getDataClass()->isLoweredToTwoParameters();
4362  Value *secondArg = NULL;
4363  Value **secondArgIfNeeded = (isLoweredToTwoParameters ? &secondArg : NULL);
4364  Value *arg = VuoCompilerCodeGenUtilities::convertArgumentToParameterType(dataValue, triggerFunctionType, 0, isPassedByValue,
4365  secondArgIfNeeded, module, triggerBlock);
4366  args.push_back(arg);
4367  if (secondArg)
4368  args.push_back(secondArg);
4369  }
4370 
4371  int indexInSubcompositionPorts = VuoNodeClass::unreservedInputPortStartIndex + publishedInputPorts.size() +
4372  VuoNodeClass::unreservedOutputPortStartIndex + publishedPortIndex;
4373 
4374  Value *portContextValue = VuoCompilerCodeGenUtilities::generateGetNodeContextPortContext(module, triggerBlock, compositionContextValue, indexInSubcompositionPorts);
4375  Value *triggerFunction = VuoCompilerCodeGenUtilities::generateGetPortContextTriggerFunction(module, triggerBlock, portContextValue, triggerFunctionType);
4376 
4377  CallInst::Create(triggerFunction, args, "", triggerBlock);
4378  BranchInst::Create(nextBlock, triggerBlock);
4379 
4380  currBlock = nextBlock;
4381  }
4382  else
4383  {
4384  VuoCompilerCodeGenUtilities::generateSetNodeContextOutputEvent(module, currBlock, compositionContextValue, publishedPortIndex, isPortHitValue);
4385  }
4386  }
4387 
4388  // If this event (which may or may not have actually hit the published output node) is from
4389  // nodeEvent()/nodeInstanceEvent() or an event spun off of it, and is the final one to complete, then...
4390 
4391  Value *subcompositionFinishedValue = VuoCompilerCodeGenUtilities::generateFinishedExecutingEvent(module, currBlock, compositionContextValue, eventIdValue);
4392  ConstantInt *falseValue = ConstantInt::get(static_cast<IntegerType *>(subcompositionFinishedValue->getType()), 0);
4393  ICmpInst *subcompositionFinishedIsTrue = new ICmpInst(*currBlock, ICmpInst::ICMP_NE, subcompositionFinishedValue, falseValue, "");
4394  BasicBlock *leaveBlock = BasicBlock::Create(module->getContext(), "leave", function, NULL);
4395  BasicBlock *signalBlock = BasicBlock::Create(module->getContext(), "signal", function, NULL);
4396  BranchInst::Create(leaveBlock, signalBlock, subcompositionFinishedIsTrue, currBlock);
4397 
4398  // Leave the dispatch group waited on by nodeEvent()/nodeInstanceEvent().
4399 
4400  Value *subcompositionOutputGroupValue = VuoCompilerCodeGenUtilities::generateGetNodeContextExecutingGroup(module, leaveBlock, compositionContextValue);
4401  VuoCompilerCodeGenUtilities::generateLeaveDispatchGroup(module, leaveBlock, subcompositionOutputGroupValue);
4402  BranchInst::Create(finalBlock, leaveBlock);
4403 
4404  // Otherwise, signal the published output node's semaphore so that the remaining events can claim it.
4405  // (For the final event, the published output node's semaphore is signaled in nodeEvent()/nodeInstanceEvent().)
4406 
4407  generateSignalForNodes(module, signalBlock, compositionStateValue, vector<VuoCompilerNode *>(1, node));
4408  BranchInst::Create(finalBlock, signalBlock);
4409  }
4410  }
4411  else
4412  {
4413  // If the node received an event, then...
4414  BasicBlock *executeBlock = BasicBlock::Create(module->getContext(), "execute", function, NULL);
4415  BranchInst::Create(executeBlock, finalBlock, isHitValue, initialBlock);
4416 
4417  if (node->getBase()->getNodeClass()->getCompiler()->isSubcomposition())
4418  {
4419  // Pass the event ID to the subcomposition.
4420  VuoCompilerCodeGenUtilities::generateStartedExecutingEvent(module, executeBlock, nodeContextValue, eventIdValue);
4421 
4422  // Pass the chain's reserved threads to the subcomposition.
4423  Value *compositionIdentifierValue = VuoCompilerCodeGenUtilities::generateGetCompositionStateCompositionIdentifier(module, executeBlock, compositionStateValue);
4424  Value *subcompositionIdentifierValue = node->generateSubcompositionIdentifierValue(module, executeBlock, compositionIdentifierValue);
4426  eventIdValue, compositionStateValue, chainIndexValue,
4427  subcompositionIdentifierValue);
4428  VuoCompilerCodeGenUtilities::generateFreeCall(module, executeBlock, subcompositionIdentifierValue);
4429  }
4430 
4431  // Call the node's event function, and send telemetry that the node's execution has started and finished.
4432  bool shouldSendTelemetry = (node != graph->getPublishedInputNode());
4433  generateNodeExecution(function, executeBlock, compositionStateValue, node, shouldSendTelemetry);
4434  BranchInst::Create(finalBlock, executeBlock);
4435  }
4436 
4437  ReturnInst::Create(module->getContext(), isHitValue, finalBlock);
4438 
4439  return function;
4440 }
4441 
4466 Function * VuoCompilerBitcodeGenerator::generateNodeTransmissionFunction(Module *module, VuoCompilerNode *node)
4467 {
4468  string functionName = node->getIdentifier() + "__transmit";
4469  PointerType *pointerToCompositionStateType = PointerType::get(VuoCompilerCodeGenUtilities::getCompositionStateType(module), 0);
4470  Type *boolType = IntegerType::get(module->getContext(), 1);
4471  vector<Type *> params;
4472  params.push_back(pointerToCompositionStateType);
4473  params.push_back(boolType);
4474  FunctionType *functionType = FunctionType::get(Type::getVoidTy(module->getContext()), params, false);
4475  Function *function = Function::Create(functionType, GlobalValue::InternalLinkage, functionName, module);
4476 
4477  Function::arg_iterator args = function->arg_begin();
4478  Value *compositionStateValue = args++;
4479  compositionStateValue->setName("compositionState");
4480  Value *isHitValue = args++;
4481  isHitValue->setName("isHit");
4482 
4483  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, NULL);
4484  BasicBlock *transmitBlock = BasicBlock::Create(module->getContext(), "transmit", function, NULL);
4485  BasicBlock *finalBlock = BasicBlock::Create(module->getContext(), "final", function, NULL);
4486 
4487  // If the node received an event, then...
4488  BranchInst::Create(transmitBlock, finalBlock, isHitValue, initialBlock);
4489 
4490  Value *nodeContextValue = node->generateGetContext(module, transmitBlock, compositionStateValue);
4491 
4492  if (node == graph->getPublishedOutputNode())
4493  {
4494  if (isTopLevelComposition)
4495  generateTelemetryFromPublishedOutputNode(function, transmitBlock, compositionStateValue, nodeContextValue, node);
4496  }
4497  else
4498  {
4499  // Transmit events and data through the node's outgoing cables, and send telemetry for port updates.
4500  generateTransmissionFromNode(function, transmitBlock, compositionStateValue, nodeContextValue, node);
4501  }
4502 
4503  // Reset the node's event inputs and outputs.
4504  VuoCompilerCodeGenUtilities::generateResetNodeContextEvents(module, transmitBlock, nodeContextValue);
4505 
4506  BranchInst::Create(finalBlock, transmitBlock);
4507  ReturnInst::Create(module->getContext(), finalBlock);
4508 
4509  return function;
4510 }
4511 
4516 {
4517  this->debugMode = debugMode;
4518 }