Vuo  2.1.2
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, true);
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,
2827  VuoCompilerNode *outputNode, VuoCompilerPort *outputPort,
2828  Value *eventValue, Value *dataValue,
2829  bool requiresEvent, bool shouldSendTelemetry)
2830 {
2831  IntegerType *boolType = IntegerType::get(module->getContext(), 1);
2832  PointerType *pointerToCharType = PointerType::get(IntegerType::get(module->getContext(), 8), 0);
2833 
2834  set<VuoCompilerCable *> outgoingCables = graph->getOutgoingCables(outputPort);
2835 
2836  Constant *trueValue = ConstantInt::get(boolType, 1);
2837  Constant *falseValue = ConstantInt::get(boolType, 0);
2838  Constant *transmittedEventValue = (requiresEvent ? trueValue : falseValue);
2839 
2840  // char *dataSummary = NULL;
2841  AllocaInst *dataSummaryVariable = new AllocaInst(pointerToCharType, "dataSummary", currentBlock);
2842  new StoreInst(ConstantPointerNull::get(pointerToCharType), dataSummaryVariable, currentBlock);
2843 
2844  map<VuoCompilerPort *, ICmpInst *> shouldSummarizeInput;
2845  if (shouldSendTelemetry)
2846  {
2847  // bool sentData = false;
2848  AllocaInst *sentDataVariable = new AllocaInst(boolType, "sentData", currentBlock);
2849  new StoreInst(falseValue, sentDataVariable, currentBlock);
2850 
2851  for (set<VuoCompilerCable *>::iterator i = outgoingCables.begin(); i != outgoingCables.end(); ++i)
2852  {
2853  VuoCompilerCable *cable = *i;
2854 
2855  VuoCompilerPort *inputPort = static_cast<VuoCompilerPort *>(cable->getBase()->getToPort()->getCompiler());
2856  ICmpInst *shouldSendDataForInput = VuoCompilerCodeGenUtilities::generateShouldSendDataTelemetryComparison(module, currentBlock,
2857  inputPort->getIdentifier(),
2858  compositionStateValue,
2859  constantStrings);
2860  shouldSummarizeInput[inputPort] = shouldSendDataForInput;
2861  }
2862 
2863  if (dataValue)
2864  {
2865  Value *shouldSummarizeOutput = VuoCompilerCodeGenUtilities::generateShouldSendDataTelemetryComparison(module, currentBlock,
2866  outputPort->getIdentifier(),
2867  compositionStateValue,
2868  constantStrings);
2869 
2870  for (set<VuoCompilerCable *>::iterator i = outgoingCables.begin(); i != outgoingCables.end(); ++i)
2871  {
2872  VuoCompilerCable *cable = *i;
2873 
2874  if (cable->carriesData())
2875  {
2876  VuoCompilerPort *inputPort = static_cast<VuoCompilerPort *>(cable->getBase()->getToPort()->getCompiler());
2877  shouldSummarizeOutput = BinaryOperator::Create(Instruction::Or, shouldSummarizeOutput, shouldSummarizeInput[inputPort], "", currentBlock);
2878  }
2879  }
2880 
2881  BasicBlock *summaryBlock = BasicBlock::Create(module->getContext(), "outputSummary", function, NULL);
2882  BasicBlock *sendOutputBlock = BasicBlock::Create(module->getContext(), "sendOutput", function, NULL);
2883  BranchInst::Create(summaryBlock, sendOutputBlock, shouldSummarizeOutput, currentBlock);
2884 
2885  // sentData = true;
2886  new StoreInst(trueValue, sentDataVariable, summaryBlock);
2887 
2888  // dataSummary = <type>_getSummary(portValue);
2889  VuoCompilerType *type = outputPort->getDataVuoType()->getCompiler();
2890  Value *dataSummaryValue = type->generateSummaryFromValueFunctionCall(module, summaryBlock, dataValue);
2891  new StoreInst(dataSummaryValue, dataSummaryVariable, summaryBlock);
2892 
2893  BranchInst::Create(sendOutputBlock, summaryBlock);
2894  currentBlock = sendOutputBlock;
2895  }
2896 
2897  if (shouldSendTelemetry && outputNode != graph->getPublishedInputNode())
2898  {
2899  Value *sentDataValue = new LoadInst(sentDataVariable, "", false, currentBlock);
2900  Value *dataSummaryValue = new LoadInst(dataSummaryVariable, "", false, currentBlock);
2901 
2902  Constant *outputPortIdentifierValue = constantStrings.get(module, outputPort->getIdentifier());
2903 
2904  VuoCompilerCodeGenUtilities::generateSendOutputPortsUpdated(module, currentBlock, compositionStateValue, outputPortIdentifierValue,
2905  transmittedEventValue, sentDataValue, dataSummaryValue);
2906  }
2907  }
2908 
2909  // If the output port should transmit an event...
2910  bool alwaysTransmitsEvent = (dynamic_cast<VuoCompilerTriggerPort *>(outputPort) || ! requiresEvent);
2911  BasicBlock *transmissionBlock = NULL;
2912  BasicBlock *noTransmissionBlock = NULL;
2913  if (alwaysTransmitsEvent)
2914  {
2915  transmissionBlock = currentBlock;
2916  }
2917  else
2918  {
2919  transmissionBlock = BasicBlock::Create(module->getContext(), "transmission", function, NULL);
2920  noTransmissionBlock = BasicBlock::Create(module->getContext(), "noTransmission", function, NULL);
2921 
2922  ConstantInt *zeroValue = ConstantInt::get(static_cast<IntegerType *>(eventValue->getType()), 0);
2923  ICmpInst *eventValueIsTrue = new ICmpInst(*currentBlock, ICmpInst::ICMP_NE, eventValue, zeroValue, "");
2924  BranchInst::Create(transmissionBlock, noTransmissionBlock, eventValueIsTrue, currentBlock);
2925  }
2926 
2927  // ... then transmit the event and data (if any) to each connected input port.
2928  for (set<VuoCompilerCable *>::iterator i = outgoingCables.begin(); i != outgoingCables.end(); ++i)
2929  {
2930  VuoCompilerCable *cable = *i;
2931 
2932  VuoCompilerNode *inputNode = cable->getBase()->getToNode()->getCompiler();
2933  Value *inputNodeContextValue = inputNode->generateGetContext(module, transmissionBlock, compositionStateValue);
2934  VuoCompilerInputEventPort *inputPort = static_cast<VuoCompilerInputEventPort *>( cable->getBase()->getToPort()->getCompiler() );
2935  Value *inputPortContextValue = inputPort->generateGetPortContext(module, transmissionBlock, inputNodeContextValue);
2936 
2937  Value *transmittedDataValue = (cable->carriesData() ? dataValue : NULL);
2938 
2939  cable->generateTransmission(module, transmissionBlock, inputNodeContextValue, inputPortContextValue, transmittedDataValue, requiresEvent);
2940 
2941  if (shouldSendTelemetry && inputNode != graph->getPublishedInputNode())
2942  {
2943  // char *inputDataSummary = NULL;
2944  AllocaInst *inputDataSummaryVariable = new AllocaInst(pointerToCharType, "inputDataSummary", transmissionBlock);
2945  new StoreInst(ConstantPointerNull::get(pointerToCharType), inputDataSummaryVariable, transmissionBlock);
2946 
2947  // bool receivedData = false;
2948  AllocaInst *receivedDataVariable = new AllocaInst(boolType, "receivedData", transmissionBlock);
2949  new StoreInst(falseValue, receivedDataVariable, transmissionBlock);
2950 
2951  VuoType *inputDataType = inputPort->getDataVuoType();
2952  if (inputDataType)
2953  {
2954  BasicBlock *summaryBlock = BasicBlock::Create(module->getContext(), "inputSummary", function, NULL);
2955  BasicBlock *sendInputBlock = BasicBlock::Create(module->getContext(), "sendInput", function, NULL);
2956  BranchInst::Create(summaryBlock, sendInputBlock, shouldSummarizeInput[inputPort], transmissionBlock);
2957 
2958  Value *inputDataSummaryValue;
2959  if (transmittedDataValue)
2960  {
2961  // receivedData = true;
2962  new StoreInst(trueValue, receivedDataVariable, summaryBlock);
2963 
2964  // inputDataSummary = dataSummary;
2965  inputDataSummaryValue = new LoadInst(dataSummaryVariable, "", false, summaryBlock);
2966  }
2967  else
2968  {
2969  // inputDataSummary = <Type>_getSummary(inputData);
2970  Value *inputDataValue = inputPort->generateLoadData(module, summaryBlock, inputNodeContextValue, inputPortContextValue);
2971  inputDataSummaryValue = inputDataType->getCompiler()->generateSummaryFromValueFunctionCall(module, summaryBlock, inputDataValue);
2972  }
2973  new StoreInst(inputDataSummaryValue, inputDataSummaryVariable, summaryBlock);
2974 
2975  BranchInst::Create(sendInputBlock, summaryBlock);
2976  transmissionBlock = sendInputBlock;
2977  }
2978 
2979  Value *receivedDataValue = new LoadInst(receivedDataVariable, "", false, transmissionBlock);
2980  Value *inputDataSummaryValue = new LoadInst(inputDataSummaryVariable, "", false, transmissionBlock);
2981 
2982  Constant *inputPortIdentifierValue = constantStrings.get(module, inputPort->getIdentifier());
2983 
2984  VuoCompilerCodeGenUtilities::generateSendInputPortsUpdated(module, transmissionBlock, compositionStateValue, inputPortIdentifierValue,
2985  transmittedEventValue, receivedDataValue, inputDataSummaryValue);
2986 
2987  if (inputDataType && ! transmittedDataValue)
2988  {
2989  // free(inputDataSummary);
2990  VuoCompilerCodeGenUtilities::generateFreeCall(module, transmissionBlock, inputDataSummaryValue);
2991  }
2992  }
2993  }
2994 
2995  if (alwaysTransmitsEvent)
2996  {
2997  currentBlock = transmissionBlock;
2998  }
2999  else
3000  {
3001  BranchInst::Create(noTransmissionBlock, transmissionBlock);
3002  currentBlock = noTransmissionBlock;
3003  }
3004 
3005  if (shouldSendTelemetry && dataValue)
3006  {
3007  // free(dataSummary)
3008  Function *freeFunction = VuoCompilerCodeGenUtilities::getFreeFunction(module);
3009  LoadInst *dataSummaryValue = new LoadInst(dataSummaryVariable, "", false, currentBlock);
3010  CallInst::Create(freeFunction, dataSummaryValue, "", currentBlock);
3011  }
3012 }
3013 
3018 void VuoCompilerBitcodeGenerator::generateTransmissionFromNode(Function *function, BasicBlock *&currentBlock,
3019  Value *compositionStateValue, Value *nodeContextValue,
3020  VuoCompilerNode *node, bool requiresEvent, bool shouldSendTelemetry)
3021 {
3022  vector<VuoPort *> outputPorts = node->getBase()->getOutputPorts();
3023  for (vector<VuoPort *>::iterator i = outputPorts.begin(); i != outputPorts.end(); ++i)
3024  {
3025  // If the output port is a trigger port, do nothing.
3026  VuoCompilerOutputEventPort *outputEventPort = dynamic_cast<VuoCompilerOutputEventPort *>((*i)->getCompiler());
3027  if (! outputEventPort)
3028  continue;
3029 
3030  Value *portContextValue = outputEventPort->generateGetPortContext(module, currentBlock, nodeContextValue);
3031  Value *outputEventValue = outputEventPort->generateLoadEvent(module, currentBlock, nodeContextValue, portContextValue);
3032 
3033  BasicBlock *telemetryBlock = NULL;
3034  BasicBlock *noTelemetryBlock = NULL;
3035  if (requiresEvent)
3036  {
3037  telemetryBlock = BasicBlock::Create(module->getContext(), "", function, NULL);
3038  noTelemetryBlock = BasicBlock::Create(module->getContext(), "", function, NULL);
3039 
3040  // If the output port isn't transmitting an event, do nothing.
3041  ConstantInt *zeroValue = ConstantInt::get(static_cast<IntegerType *>(outputEventValue->getType()), 0);
3042  ICmpInst *eventValueIsTrue = new ICmpInst(*currentBlock, ICmpInst::ICMP_NE, outputEventValue, zeroValue, "");
3043  BranchInst::Create(telemetryBlock, noTelemetryBlock, eventValueIsTrue, currentBlock);
3044  }
3045  else
3046  {
3047  telemetryBlock = currentBlock;
3048  }
3049 
3050  // Transmit the data through the output port to each connected input port.
3051  VuoCompilerOutputData *outputData = outputEventPort->getData();
3052  Value *outputDataValue = (outputData ?
3053  outputEventPort->generateLoadData(module, telemetryBlock, nodeContextValue, portContextValue) :
3054  NULL);
3055  generateTransmissionFromOutputPort(function, telemetryBlock, compositionStateValue,
3056  node, outputEventPort, outputEventValue, outputDataValue, requiresEvent, shouldSendTelemetry);
3057 
3058  if (requiresEvent)
3059  {
3060  BranchInst::Create(noTelemetryBlock, telemetryBlock);
3061  currentBlock = noTelemetryBlock;
3062  }
3063  else
3064  {
3065  currentBlock = telemetryBlock;
3066  }
3067  }
3068 }
3069 
3074 void VuoCompilerBitcodeGenerator::generateTelemetryFromPublishedOutputNode(Function *function, BasicBlock *&currentBlock, Value *compositionStateValue,
3075  Value *nodeContextValue, VuoCompilerNode *node)
3076 {
3077  IntegerType *boolType = IntegerType::get(module->getContext(), 1);
3078  PointerType *pointerToCharType = PointerType::get(IntegerType::get(module->getContext(), 8), 0);
3079 
3080  for (auto inputPort : node->getBase()->getInputPorts())
3081  {
3082  // If the published output port is for internal use only, do nothing.
3083  if (inputPort == graph->getGatherPortOnPublishedOutputNode())
3084  continue;
3085 
3086  VuoCompilerInputEventPort *inputEventPort = dynamic_cast<VuoCompilerInputEventPort *>(inputPort->getCompiler());
3087 
3088  BasicBlock *telemetryBlock = BasicBlock::Create(module->getContext(), "", function, NULL);
3089  BasicBlock *noTelemetryBlock = BasicBlock::Create(module->getContext(), "", function, NULL);
3090 
3091  // If the published output port isn't transmitting an event, do nothing.
3092  Value *eventValue = inputEventPort->generateLoadEvent(module, currentBlock, nodeContextValue);
3093  ConstantInt *zeroValue = ConstantInt::get(static_cast<IntegerType *>(eventValue->getType()), 0);
3094  ICmpInst *eventValueIsTrue = new ICmpInst(*currentBlock, ICmpInst::ICMP_NE, eventValue, zeroValue, "");
3095  BranchInst::Create(telemetryBlock, noTelemetryBlock, eventValueIsTrue, currentBlock);
3096 
3097  VuoCompilerInputData *data = inputEventPort->getData();
3098  Value *dataValue = data ? inputEventPort->generateLoadData(module, telemetryBlock, nodeContextValue) : NULL;
3099  Constant *trueValue = ConstantInt::get(boolType, 1);
3100  Constant *falseValue = ConstantInt::get(boolType, 0);
3101 
3102  Value *sentDataValue = NULL;
3103  Value *dataSummaryValue = NULL;
3104  if (dataValue)
3105  {
3106  // sentData = true;
3107  sentDataValue = trueValue;
3108 
3109  // dataSummary = <type>_getSummary(portValue);
3110  VuoCompilerType *type = inputEventPort->getDataVuoType()->getCompiler();
3111  dataSummaryValue = type->generateSummaryFromValueFunctionCall(module, telemetryBlock, dataValue);
3112  }
3113  else
3114  {
3115  // sentData = false;
3116  sentDataValue = falseValue;
3117 
3118  // dataSummary = NULL;
3119  dataSummaryValue = ConstantPointerNull::get(pointerToCharType);
3120  }
3121 
3122  Constant *portIdentifierValue = constantStrings.get(module, inputEventPort->getBase()->getClass()->getName());
3123  VuoCompilerCodeGenUtilities::generateSendPublishedOutputPortsUpdated(module, telemetryBlock, compositionStateValue, portIdentifierValue,
3124  sentDataValue, dataSummaryValue);
3125 
3126  BranchInst::Create(noTelemetryBlock, telemetryBlock);
3127  currentBlock = noTelemetryBlock;
3128  }
3129 }
3130 
3137 void VuoCompilerBitcodeGenerator::generateDataOnlyTransmissionFromNode(Function *function, BasicBlock *&currentBlock, Value *compositionStateValue,
3138  VuoCompilerNode *node, bool shouldWaitForDownstreamNodes,
3139  bool shouldUpdateTriggers, bool shouldSendTelemetry)
3140 {
3141  vector<VuoCompilerNode *> downstreamNodes = graph->getNodesDownstreamViaDataOnlyTransmission(node);
3142  if (downstreamNodes.empty())
3143  return;
3144 
3145  if (shouldWaitForDownstreamNodes)
3146  {
3147  // Claim the nodes downstream via data-only transmission.
3148  generateWaitForNodes(module, function, currentBlock, compositionStateValue, downstreamNodes, NULL, true);
3149  }
3150 
3151  // For this node and each node downstream via data-only transmission...
3152  vector<VuoCompilerNode *> nodesToVisit = downstreamNodes;
3153  nodesToVisit.insert(nodesToVisit.begin(), node);
3154  for (VuoCompilerNode *visitedNode : nodesToVisit)
3155  {
3156  if (graph->mayTransmitDataOnly(visitedNode))
3157  {
3158  Value *nodeContextValue = visitedNode->generateGetContext(module, currentBlock, compositionStateValue);
3159 
3160  // Simulate an event having just hit all input ports of the node (necessary due to published input node's doors).
3161  vector<VuoPort *> inputPorts = visitedNode->getBase()->getInputPorts();
3162  for (size_t i = VuoNodeClass::unreservedInputPortStartIndex; i < inputPorts.size(); ++i)
3163  {
3164  VuoCompilerInputEventPort *inputEventPort = static_cast<VuoCompilerInputEventPort *>(inputPorts[i]->getCompiler());
3165  inputEventPort->generateStoreEvent(module, currentBlock, nodeContextValue, true);
3166  }
3167 
3168  // Call the node's event function, and send telemetry if needed.
3169  generateNodeExecution(function, currentBlock, compositionStateValue, visitedNode, false);
3170 
3171  // Transmit data through the node's outgoing cables, and send telemetry for port updates if needed.
3172  generateTransmissionFromNode(function, currentBlock, compositionStateValue, nodeContextValue, visitedNode, false, shouldSendTelemetry);
3173 
3174  // Reset the node's event inputs and outputs.
3175  VuoCompilerCodeGenUtilities::generateResetNodeContextEvents(module, currentBlock, nodeContextValue);
3176  }
3177 
3178  if (visitedNode != node)
3179  {
3180  if (shouldUpdateTriggers)
3181  {
3182  // Call the downstream node's trigger update function.
3183  visitedNode->generateCallbackUpdateFunctionCall(module, currentBlock, compositionStateValue);
3184  }
3185 
3186  if (shouldWaitForDownstreamNodes)
3187  {
3188  // Signal the downstream node.
3189  generateSignalForNodes(module, currentBlock, compositionStateValue, vector<VuoCompilerNode *>(1, visitedNode));
3190  }
3191  }
3192  }
3193 }
3194 
3198 void VuoCompilerBitcodeGenerator::generateNodeExecution(Function *function, BasicBlock *&currentBlock,
3199  Value *compositionStateValue, VuoCompilerNode *node,
3200  bool shouldSendTelemetry)
3201 {
3202  Value *nodeIdentifierValue = constantStrings.get(module, node->getIdentifier());
3203 
3204  if (shouldSendTelemetry)
3205  {
3206  // Send telemetry indicating that the node's execution has started.
3207  VuoCompilerCodeGenUtilities::generateSendNodeExecutionStarted(module, currentBlock, compositionStateValue, nodeIdentifierValue);
3208  }
3209 
3210  // Call the node's event function.
3211  if (debugMode)
3212  VuoCompilerCodeGenUtilities::generatePrint(module, currentBlock, node->getBase()->getTitle() + "\n");
3213  node->generateEventFunctionCall(module, function, currentBlock, compositionStateValue);
3214 
3215  if (shouldSendTelemetry)
3216  {
3217  // Send telemetry indicating that the node's execution has finished.
3218  VuoCompilerCodeGenUtilities::generateSendNodeExecutionFinished(module, currentBlock, compositionStateValue, nodeIdentifierValue);
3219  }
3220 }
3221 
3225 void VuoCompilerBitcodeGenerator::generateAllocation(void)
3226 {
3227 #ifdef VUO_PRO
3228  generateAllocation_Pro();
3229 #endif
3230 
3231  {
3232  Constant *value = constantStrings.get(module, VuoCompilerComposition::topLevelCompositionIdentifier);
3233  new GlobalVariable(*module, value->getType(), true, GlobalValue::ExternalLinkage, value, "vuoTopLevelCompositionIdentifier");
3234  }
3235 }
3236 
3244 void VuoCompilerBitcodeGenerator::generateSetupFunction(bool isStatefulComposition)
3245 {
3246  Function *function = VuoCompilerCodeGenUtilities::getSetupFunction(module);
3247  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
3248 
3249  Value *topLevelRuntimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, block);
3250  Value *topLevelCompositionIdentifierValue = constantStrings.get(module, VuoCompilerComposition::topLevelCompositionIdentifier);
3251  Value *topLevelCompositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, topLevelRuntimeStateValue, topLevelCompositionIdentifierValue);
3252 
3253  // Top__compositionAddNodeMetadata(compositionState);
3254 
3255  Function *compositionCreateAndRegisterMetadataFunction = VuoCompilerCodeGenUtilities::getCompositionAddNodeMetadataFunction(module);
3256  CallInst::Create(compositionCreateAndRegisterMetadataFunction, topLevelCompositionStateValue, "", block);
3257 
3258  // vuoInitContextForTopLevelComposition(compositionState, hasInstanceData, publishedOutputPortCount);
3259 
3260  size_t publishedOutputPortCount = composition->getBase()->getPublishedOutputPorts().size();
3261  VuoCompilerCodeGenUtilities::generateInitContextForTopLevelComposition(module, block, topLevelCompositionStateValue,
3262  isStatefulComposition, publishedOutputPortCount);
3263 
3264  // Set each published input port to its initial value.
3265 
3266  Function *compositionSetPublishedInputPortValueFunction = VuoCompilerCodeGenUtilities::getCompositionSetPublishedInputPortValueFunction(module);
3267  Value *falseValue = ConstantInt::get(compositionSetPublishedInputPortValueFunction->getFunctionType()->getParamType(3), 0);
3268 
3269  for (VuoPublishedPort *publishedInputPort : composition->getBase()->getPublishedInputPorts())
3270  {
3271  string name = publishedInputPort->getClass()->getName();
3272  string initialValue = static_cast<VuoCompilerPublishedPort *>(publishedInputPort->getCompiler())->getInitialValue();
3273 
3274  vector<Value *> args;
3275  args.push_back(topLevelCompositionStateValue);
3276  args.push_back( constantStrings.get(module, name) );
3277  args.push_back( constantStrings.get(module, initialValue) );
3278  args.push_back(falseValue);
3279  CallInst::Create(compositionSetPublishedInputPortValueFunction, args, "", block);
3280  }
3281 
3282  // Top__compositionPerformDataOnlyTransmissions(compositionState);
3283 
3284  Function *compositionPerformDataOnlyTransmissionsFunction = VuoCompilerCodeGenUtilities::getCompositionPerformDataOnlyTransmissionsFunction(module);
3285  CallInst::Create(compositionPerformDataOnlyTransmissionsFunction, topLevelCompositionStateValue, "", block);
3286 
3287  // Update the function pointers for all trigger functions in the top-level composition.
3288 
3289  for (map<VuoCompilerTriggerPort *, Function *>::iterator i = topLevelTriggerFunctions.begin(); i != topLevelTriggerFunctions.end(); ++i)
3290  {
3291  VuoCompilerTriggerPort *trigger = i->first;
3292  Function *function = i->second;
3293 
3294  VuoCompilerNode *node = graph->getNodeForTriggerPort(trigger);
3295  Value *nodeContextValue = node->generateGetContext(module, block, topLevelCompositionStateValue);
3296  trigger->generateStoreFunction(module, block, nodeContextValue, function);
3297  }
3298 
3299  // Update the function pointers for all trigger functions in subcompositions.
3300 
3301  for (map<string, map<size_t, map<VuoCompilerTriggerDescription *, Function *> > >::iterator i = subcompositionTriggerFunctions.begin(); i != subcompositionTriggerFunctions.end(); ++i)
3302  {
3303  string compositionIdentifier = i->first;
3304 
3305  for (map<size_t, map<VuoCompilerTriggerDescription *, Function *> >::iterator j = i->second.begin(); j != i->second.end(); ++j)
3306  {
3307  size_t nodeIndex = j->first;
3308 
3309  for (map<VuoCompilerTriggerDescription *, Function *>::iterator k = j->second.begin(); k != j->second.end(); ++k)
3310  {
3311  VuoCompilerTriggerDescription *trigger = k->first;
3312  Function *function = k->second;
3313 
3314  Value *compositionIdentifierValue = constantStrings.get(module, compositionIdentifier);
3315  Value *compositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, topLevelRuntimeStateValue, compositionIdentifierValue);
3316 
3317  int portContextIndex = trigger->getPortContextIndex();
3318  Value *nodeContextValue = VuoCompilerCodeGenUtilities::generateGetNodeContext(module, block, compositionStateValue, nodeIndex);
3319  Value *portContextValue = VuoCompilerCodeGenUtilities::generateGetNodeContextPortContext(module, block, nodeContextValue, portContextIndex);
3320  VuoCompilerCodeGenUtilities::generateSetPortContextTriggerFunction(module, block, portContextValue, function);
3321 
3322  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, compositionStateValue);
3323  }
3324  }
3325  }
3326 
3327  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, topLevelCompositionStateValue);
3328 
3329  ReturnInst::Create(module->getContext(), block);
3330 }
3331 
3338 void VuoCompilerBitcodeGenerator::generateCleanupFunction(void)
3339 {
3340  Function *function = VuoCompilerCodeGenUtilities::getCleanupFunction(module);
3341  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
3342 
3343  Value *topLevelRuntimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, block);
3344  Value *topLevelCompositionIdentifierValue = constantStrings.get(module, VuoCompilerComposition::topLevelCompositionIdentifier);
3345  Value *topLevelCompositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, topLevelRuntimeStateValue, topLevelCompositionIdentifierValue);
3346 
3347  VuoCompilerCodeGenUtilities::generateFiniContextForTopLevelComposition(module, block, topLevelCompositionStateValue);
3348 
3349  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, topLevelCompositionStateValue);
3350 
3351  ReturnInst::Create(module->getContext(), block);
3352 }
3353 
3359 void VuoCompilerBitcodeGenerator::generateInstanceInitFunction(bool isStatefulComposition)
3360 {
3361  Function *function = VuoCompilerCodeGenUtilities::getInstanceInitFunction(module);
3362  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
3363 
3364  if (isStatefulComposition)
3365  {
3366  map<VuoPort *, size_t> indexOfParameter;
3367  Function *nodeInstanceInitFunction = VuoCompilerCodeGenUtilities::getNodeInstanceInitFunction(module, moduleKey, true,
3369  vector<VuoPort *>(),
3370  indexOfParameter, constantStrings);
3371 
3372  Value *topLevelRuntimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, block);
3373  Value *topLevelCompositionIdentifierValue = constantStrings.get(module, VuoCompilerComposition::topLevelCompositionIdentifier);
3374  Value *topLevelCompositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, topLevelRuntimeStateValue, topLevelCompositionIdentifierValue);
3375 
3376  CallInst::Create(nodeInstanceInitFunction, topLevelCompositionStateValue, "", block);
3377 
3378  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, topLevelCompositionStateValue);
3379  }
3380 
3381  ReturnInst::Create(module->getContext(), block);
3382 }
3383 
3389 void VuoCompilerBitcodeGenerator::generateInstanceFiniFunction(bool isStatefulComposition)
3390 {
3391  Function *function = VuoCompilerCodeGenUtilities::getInstanceFiniFunction(module);
3392  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
3393 
3394  if (isStatefulComposition)
3395  {
3396  Function *nodeInstanceFiniFunction = VuoCompilerCodeGenUtilities::getNodeInstanceFiniFunction(module, moduleKey,
3398  constantStrings);
3399 
3400  Value *topLevelRuntimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, block);
3401  Value *topLevelCompositionIdentifierValue = constantStrings.get(module, VuoCompilerComposition::topLevelCompositionIdentifier);
3402  Value *topLevelCompositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, topLevelRuntimeStateValue, topLevelCompositionIdentifierValue);
3403 
3404  PointerType *instanceDataType = static_cast<PointerType *>( nodeInstanceFiniFunction->getFunctionType()->getParamType(1) );
3405  ConstantPointerNull *nullInstanceDataValue = ConstantPointerNull::get(instanceDataType);
3406 
3407  vector<Value *> args;
3408  args.push_back(topLevelCompositionStateValue);
3409  args.push_back(nullInstanceDataValue);
3410  CallInst::Create(nodeInstanceFiniFunction, args, "", block);
3411 
3412  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, topLevelCompositionStateValue);
3413  }
3414 
3415  ReturnInst::Create(module->getContext(), block);
3416 }
3417 
3423 void VuoCompilerBitcodeGenerator::generateInstanceTriggerStartFunction(bool isStatefulComposition)
3424 {
3426  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
3427 
3428  if (isStatefulComposition)
3429  {
3430  map<VuoPort *, size_t> indexOfParameter;
3431  Function *nodeInstanceTriggerStartFunction = VuoCompilerCodeGenUtilities::getNodeInstanceTriggerStartFunction(module, moduleKey,
3433  vector<VuoPort *>(),
3434  indexOfParameter,
3435  constantStrings);
3436 
3437  Value *topLevelRuntimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, block);
3438  Value *topLevelCompositionIdentifierValue = constantStrings.get(module, VuoCompilerComposition::topLevelCompositionIdentifier);
3439  Value *topLevelCompositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, topLevelRuntimeStateValue, topLevelCompositionIdentifierValue);
3440 
3441  PointerType *instanceDataType = static_cast<PointerType *>( nodeInstanceTriggerStartFunction->getFunctionType()->getParamType(1) );
3442  ConstantPointerNull *nullInstanceDataValue = ConstantPointerNull::get(instanceDataType);
3443 
3444  vector<Value *> args;
3445  args.push_back(topLevelCompositionStateValue);
3446  args.push_back(nullInstanceDataValue);
3447  CallInst::Create(nodeInstanceTriggerStartFunction, args, "", block);
3448 
3449  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, topLevelCompositionStateValue);
3450  }
3451 
3452  ReturnInst::Create(module->getContext(), block);
3453 }
3454 
3460 void VuoCompilerBitcodeGenerator::generateInstanceTriggerStopFunction(bool isStatefulComposition)
3461 {
3463  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
3464 
3465  {
3466  Function *nodeInstanceTriggerStopFunction = VuoCompilerCodeGenUtilities::getNodeInstanceTriggerStopFunction(module, moduleKey,
3468  constantStrings);
3469 
3470  Value *topLevelRuntimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, block);
3471  Value *topLevelCompositionIdentifierValue = constantStrings.get(module, VuoCompilerComposition::topLevelCompositionIdentifier);
3472  Value *topLevelCompositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, topLevelRuntimeStateValue, topLevelCompositionIdentifierValue);
3473 
3474  PointerType *instanceDataType = static_cast<PointerType *>( nodeInstanceTriggerStopFunction->getFunctionType()->getParamType(1) );
3475  ConstantPointerNull *nullInstanceDataValue = ConstantPointerNull::get(instanceDataType);
3476 
3477  vector<Value *> args;
3478  args.push_back(topLevelCompositionStateValue);
3479  args.push_back(nullInstanceDataValue);
3480  CallInst::Create(nodeInstanceTriggerStopFunction, args, "", block);
3481 
3482  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, topLevelCompositionStateValue);
3483  }
3484 
3485  ReturnInst::Create(module->getContext(), block);
3486 }
3487 
3493 void VuoCompilerBitcodeGenerator::generateTriggerFunctions(void)
3494 {
3495  auto isSpinOffTrigger = [] (const string &nodeClassName)
3496  {
3497  return (VuoStringUtilities::beginsWith(nodeClassName, "vuo.event.spinOff") ||
3498  VuoStringUtilities::beginsWith(nodeClassName, "vuo.list.build") ||
3499  VuoStringUtilities::beginsWith(nodeClassName, "vuo.list.process"));
3500  };
3501 
3502  map<VuoCompilerTriggerPort *, Function *> workerFunctionForTrigger;
3503  for (VuoCompilerTriggerPort *trigger : graph->getTriggerPorts())
3504  {
3505  Function *workerFunction = generateTriggerWorkerFunction(trigger);
3506  workerFunctionForTrigger[trigger] = workerFunction;
3507  }
3508 
3509  if (isTopLevelComposition)
3510  {
3511  for (map<VuoCompilerTriggerPort *, Function *>::iterator i = workerFunctionForTrigger.begin(); i != workerFunctionForTrigger.end(); ++i)
3512  {
3513  VuoCompilerTriggerPort *trigger = i->first;
3514  Function *workerFunction = i->second;
3515 
3516  VuoType *dataType = trigger->getDataVuoType();
3517 
3518  VuoCompilerNode *node = graph->getNodeForTriggerPort(trigger);
3519  size_t triggerNodeIndex = node->getIndexInOrderedNodes();
3520 
3521  string portIdentifier = trigger->getIdentifier();
3522 
3523  int portContextIndex = trigger->getIndexInPortContexts();
3524 
3525  bool canDropEvents = (trigger->getBase()->getEventThrottling() == VuoPortClass::EventThrottling_Drop);
3526 
3527  bool isPublishedTrigger = (trigger == graph->getPublishedInputTrigger());
3528 
3529  bool isSpinOff = isSpinOffTrigger(node->getBase()->getNodeClass()->getClassName());
3530 
3531  int minThreadsNeeded, maxThreadsNeeded;
3532  graph->getWorkerThreadsNeeded(trigger, minThreadsNeeded, maxThreadsNeeded);
3533 
3534  int chainCount = (int)graph->getChains()[trigger].size();
3535 
3536  Function *function = generateTriggerSchedulerFunction(dataType, VuoCompilerComposition::topLevelCompositionIdentifier, triggerNodeIndex,
3537  portIdentifier, portContextIndex, canDropEvents, isPublishedTrigger, isSpinOff,
3538  minThreadsNeeded, maxThreadsNeeded, chainCount, workerFunction);
3539  topLevelTriggerFunctions[trigger] = function;
3540  }
3541 
3542  for (VuoCompilerNode *node : graph->getNodes())
3543  {
3544  VuoCompilerNodeClass *nodeClass = node->getBase()->getNodeClass()->getCompiler();
3545 
3547  node->getGraphvizIdentifier());
3548 
3549  vector<VuoCompilerTriggerDescription *> triggers = nodeClass->getTriggerDescriptions();
3550  for (vector<VuoCompilerTriggerDescription *>::iterator j = triggers.begin(); j != triggers.end(); ++j)
3551  {
3552  VuoCompilerTriggerDescription *trigger = *j;
3553 
3554  size_t triggerNodeIndex = trigger->getNodeIndex();
3555  string triggerNodeIdentifier = trigger->getNodeIdentifier();
3556  string portIdentifier = VuoStringUtilities::buildPortIdentifier(triggerNodeIdentifier, trigger->getPortName());
3557  int portContextIndex = trigger->getPortContextIndex();
3558  bool canDropEvents = (trigger->getEventThrottling() == VuoPortClass::EventThrottling_Drop);
3559  VuoType *dataType = trigger->getDataType();
3560  string subcompositionNodeClassName = trigger->getSubcompositionNodeClassName();
3561  VuoCompilerNodeClass *subcompositionNodeClass = (subcompositionNodeClassName.empty() ?
3562  nodeClass :
3563  compiler->getNodeClass(subcompositionNodeClassName));
3564  string subcompositionNodeIdentifier = trigger->getSubcompositionNodeIdentifier();
3565  string fullSubcompositionNodeIdentifier = (subcompositionNodeIdentifier.empty() ?
3566  nodeIdentifier :
3567  VuoStringUtilities::buildCompositionIdentifier(nodeIdentifier, subcompositionNodeIdentifier));
3568  bool isPublishedTrigger = (triggerNodeIdentifier == graph->getPublishedInputTriggerNodeIdentifier());
3569 
3570  bool isSpinOff = isSpinOffTrigger(trigger->getNodeClassName());
3571 
3572  int minThreadsNeeded, maxThreadsNeeded;
3573  if (isPublishedTrigger)
3574  minThreadsNeeded = maxThreadsNeeded = -1;
3575  else
3576  trigger->getWorkerThreadsNeeded(minThreadsNeeded, maxThreadsNeeded);
3577 
3578  int chainCount = trigger->getChainCount();
3579 
3580  Function *workerFunctionSrc = subcompositionNodeClass->getTriggerWorkerFunction(portIdentifier);
3581  Function *workerFunction = VuoCompilerModule::declareFunctionInModule(module, workerFunctionSrc);
3582 
3583  Function *function = generateTriggerSchedulerFunction(dataType, fullSubcompositionNodeIdentifier, triggerNodeIndex,
3584  portIdentifier, portContextIndex, canDropEvents, isPublishedTrigger, isSpinOff,
3585  minThreadsNeeded, maxThreadsNeeded, chainCount, workerFunction);
3586 
3587  subcompositionTriggerFunctions[fullSubcompositionNodeIdentifier][triggerNodeIndex][trigger] = function;
3588  }
3589  }
3590  }
3591 }
3592 
3636 Function * VuoCompilerBitcodeGenerator::generateTriggerSchedulerFunction(VuoType *dataType,
3637  string compositionIdentifier, size_t nodeIndex,
3638  string portIdentifier, int portContextIndex,
3639  bool canDropEvents, bool isPublishedInputTrigger, bool isSpinOff,
3640  int minThreadsNeeded, int maxThreadsNeeded, int chainCount,
3641  Function *workerFunction)
3642 {
3643  string functionName = VuoStringUtilities::prefixSymbolName(workerFunction->getName().str(),
3644  VuoStringUtilities::transcodeToIdentifier(compositionIdentifier));
3645  FunctionType *functionType = VuoCompilerCodeGenUtilities::getFunctionType(module, dataType);
3646  Function *function = Function::Create(functionType, GlobalValue::InternalLinkage, functionName, module);
3647 
3648  if (dataType)
3649  {
3650  AttributeSet paramAttributes = dataType->getCompiler()->getFunctionParameterAttributes();
3651  function->setAttributes(paramAttributes);
3652  }
3653 
3654  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, NULL);
3655  BasicBlock *finalBlock = BasicBlock::Create(module->getContext(), "final", function, NULL);
3656  BasicBlock *scheduleBlock = BasicBlock::Create(module->getContext(), "schedule", function, NULL);
3657 
3658  Value *runtimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, initialBlock);
3659  Value *compositionIdentifierValue = constantStrings.get(module, compositionIdentifier);
3660 
3661  Value *compositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, initialBlock, runtimeStateValue, compositionIdentifierValue);
3662  VuoCompilerCodeGenUtilities::generateRegisterCall(module, initialBlock, compositionStateValue, VuoCompilerCodeGenUtilities::getFreeFunction(module));
3663  VuoCompilerCodeGenUtilities::generateRetainCall(module, initialBlock, compositionStateValue);
3664 
3665  Value *nodeContextValue = VuoCompilerCodeGenUtilities::generateGetNodeContext(module, initialBlock, compositionStateValue, nodeIndex);
3666  Value *portContextValue = VuoCompilerCodeGenUtilities::generateGetNodeContextPortContext(module, initialBlock, nodeContextValue, portContextIndex);
3667 
3668  if (canDropEvents)
3669  {
3670  BasicBlock *checkEventDropBlock = BasicBlock::Create(module->getContext(), "checkEventDrop", function, NULL);
3671  BranchInst::Create(checkEventDropBlock, initialBlock);
3672 
3673  // Do a non-blocking wait on the trigger's semaphore to check if it's already claimed. If so...
3674  Value *retValue = VuoCompilerTriggerPort::generateNonBlockingWaitForSemaphore(module, checkEventDropBlock, portContextValue);
3675  Constant *zeroValue = ConstantInt::get(retValue->getType(), 0);
3676  ICmpInst *isTriggerAvailableValue = new ICmpInst(*checkEventDropBlock, ICmpInst::ICMP_EQ, retValue, zeroValue, "");
3677  BasicBlock *dropEventBlock = BasicBlock::Create(module->getContext(), "dropEvent", function, NULL);
3678  BranchInst::Create(scheduleBlock, dropEventBlock, isTriggerAvailableValue, checkEventDropBlock);
3679 
3680  // Release the data value.
3681  if (dataType)
3682  VuoCompilerTriggerPort::generateDataValueDiscardFromScheduler(module, function, dropEventBlock, dataType);
3683 
3684  // Send telemetry that the event has been dropped.
3685  Constant *portIdentifierValue = constantStrings.get(module, portIdentifier);
3686  VuoCompilerCodeGenUtilities::generateSendEventDropped(module, dropEventBlock, compositionStateValue, portIdentifierValue);
3687 
3688  VuoCompilerCodeGenUtilities::generateReleaseCall(module, dropEventBlock, compositionStateValue);
3689 
3690  BranchInst::Create(finalBlock, dropEventBlock);
3691  }
3692  else
3693  {
3694  BranchInst::Create(scheduleBlock, initialBlock);
3695  }
3696 
3697  // Enter the trigger's dispatch group for tracking workers scheduled.
3698  Value *triggerWorkersScheduledValue = VuoCompilerCodeGenUtilities::getTriggerWorkersScheduledValue(module, scheduleBlock, compositionStateValue);
3699  VuoCompilerCodeGenUtilities::generateEnterDispatchGroup(module, scheduleBlock, triggerWorkersScheduledValue);
3700 
3701  Value *eventIdValue;
3702  if (! isPublishedInputTrigger)
3703  {
3704  // Get a unique ID for this event.
3705  eventIdValue = VuoCompilerCodeGenUtilities::generateGetNextEventId(module, scheduleBlock, compositionStateValue);
3706 
3707  // If this trigger fires in response to an input event, and the original event came from the published input trigger,
3708  // associate the new (spun off) event's ID with the original event.
3709  if (isSpinOff)
3710  {
3711  Value *compositionContextValue = VuoCompilerCodeGenUtilities::generateGetCompositionContext(module, scheduleBlock, compositionStateValue);
3712  VuoCompilerCodeGenUtilities::generateSpunOffExecutingEvent(module, scheduleBlock, compositionContextValue, eventIdValue);
3713  }
3714  }
3715  else
3716  {
3717  // Use the event ID from the parent composition or `firePublishedInputTrigger()`.
3718  Value *compositionContextValue = VuoCompilerCodeGenUtilities::generateGetCompositionContext(module, scheduleBlock, compositionStateValue);
3719  eventIdValue = VuoCompilerCodeGenUtilities::generateGetOneExecutingEvent(module, scheduleBlock, compositionContextValue);
3720  }
3721 
3722  // Schedule the trigger's worker function via `vuoScheduleTriggerWorker()`.
3723  VuoCompilerTriggerPort::generateScheduleWorker(module, function, scheduleBlock,
3724  compositionStateValue, eventIdValue, portContextValue, dataType,
3725  minThreadsNeeded, maxThreadsNeeded, chainCount, workerFunction);
3726  BranchInst::Create(finalBlock, scheduleBlock);
3727 
3728  ReturnInst::Create(module->getContext(), finalBlock);
3729 
3730  return function;
3731 }
3732 
3877 Function * VuoCompilerBitcodeGenerator::generateTriggerWorkerFunction(VuoCompilerTriggerPort *trigger)
3878 {
3880  Function *function = trigger->getWorkerFunction(module, functionName, true);
3881 
3882  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, NULL);
3883  BasicBlock *triggerBlock = BasicBlock::Create(module->getContext(), "trigger", function, NULL);
3884  BasicBlock *finalBlock = BasicBlock::Create(module->getContext(), "final", function, NULL);
3885 
3886  Value *compositionStateValue = trigger->generateCompositionStateValue(module, initialBlock, function);
3887  Value *compositionContextValue = VuoCompilerCodeGenUtilities::generateGetCompositionContext(module, initialBlock, compositionStateValue);
3888  Value *eventIdValue = trigger->generateEventIdValue(module, initialBlock, function);
3889 
3890  VuoCompilerNode *triggerNode = graph->getNodeForTriggerPort(trigger);
3891  Value *triggerNodeContextValue = triggerNode->generateGetContext(module, initialBlock, compositionStateValue);
3892  Value *triggerWorkersScheduledValue = VuoCompilerCodeGenUtilities::getTriggerWorkersScheduledValue(module, initialBlock, compositionStateValue);
3893  bool canDropEvents = (trigger->getBase()->getEventThrottling() == VuoPortClass::EventThrottling_Drop);
3894 
3895  bool isPublishedInputTrigger = (trigger == graph->getPublishedInputTrigger());
3896  bool isNodeEventForSubcomposition = (! isTopLevelComposition && isPublishedInputTrigger);
3897 
3898  if (! isNodeEventForSubcomposition)
3899  {
3900  // Check if `isPaused` is true. If so...
3901  BasicBlock *isPausedBlock = BasicBlock::Create(module->getContext(), "isPaused", function, NULL);
3902  ICmpInst *isPausedValueIsTrue = VuoCompilerCodeGenUtilities::generateIsPausedComparison(module, initialBlock, compositionStateValue);
3903  BranchInst::Create(isPausedBlock, triggerBlock, isPausedValueIsTrue, initialBlock);
3904 
3905  // Release the data value.
3906  trigger->generateDataValueDiscardFromWorker(module, isPausedBlock, function);
3907 
3908  // Wait for the published output node's semaphore, if not already claimed in `firePublishedInputPortEvent()`.
3909  VuoCompilerNode *publishedOutputNode = graph->getPublishedOutputNode();
3910  vector<VuoCompilerNode *> publishedOutputNodeVector(1, publishedOutputNode);
3911  if (publishedOutputNode && ! isPublishedInputTrigger)
3912  generateWaitForNodes(module, function, isPausedBlock, compositionStateValue, publishedOutputNodeVector);
3913 
3914  // Call `vuoSendEventFinished()`.
3915  VuoCompilerCodeGenUtilities::generateSendEventFinished(module, isPausedBlock, compositionStateValue, eventIdValue);
3916 
3917  if (isPublishedInputTrigger)
3918  {
3919  // Signal the semaphores claimed in `firePublishedInputPortEvent()`.
3920  vector<VuoCompilerNode *> triggerWaitNodes = getNodesToWaitOnBeforeTransmission(trigger);
3921  generateSignalForNodes(module, isPausedBlock, compositionStateValue, triggerWaitNodes);
3922  }
3923 
3924  // Signal the published output node's semaphore.
3925  if (publishedOutputNode)
3926  generateSignalForNodes(module, isPausedBlock, compositionStateValue, publishedOutputNodeVector);
3927 
3928  if (canDropEvents)
3929  // Signal the trigger's semaphore for event dropping.
3930  trigger->generateSignalForSemaphore(module, isPausedBlock, triggerNodeContextValue);
3931 
3932  // Leave the trigger's dispatch group for tracking workers scheduled.
3933  VuoCompilerCodeGenUtilities::generateLeaveDispatchGroup(module, isPausedBlock, triggerWorkersScheduledValue);
3934 
3935  // Call `vuoReturnThreadsForTriggerWorker()`.
3936  VuoCompilerCodeGenUtilities::generateReturnThreadsForTriggerWorker(module, isPausedBlock, eventIdValue, compositionStateValue);
3937 
3938  BranchInst::Create(finalBlock, isPausedBlock);
3939  // Otherwise...
3940  }
3941  else
3942  {
3943  BranchInst::Create(triggerBlock, initialBlock);
3944  }
3945 
3946  if (isPublishedInputTrigger)
3947  {
3948  if (! isNodeEventForSubcomposition)
3949  {
3950  // Signal the published output node if it was waited on in `firePublishedInputPortEvent()` just to track event start/finished.
3951  vector<VuoCompilerNode *> triggerWaitNodes = getNodesToWaitOnBeforeTransmission(trigger);
3952  VuoCompilerNode *publishedOutputNode = graph->getPublishedOutputNode();
3953  if (find(triggerWaitNodes.begin(), triggerWaitNodes.end(), publishedOutputNode) == triggerWaitNodes.end())
3954  {
3955  vector<VuoCompilerNode *> publishedOutputNodeVector(1, publishedOutputNode);
3956  generateSignalForNodes(module, triggerBlock, compositionStateValue, publishedOutputNodeVector);
3957  }
3958  }
3959  }
3960  else
3961  {
3962  // Claim the semaphores of all necessary downstream nodes.
3963  vector<VuoCompilerNode *> triggerWaitNodes = getNodesToWaitOnBeforeTransmission(trigger);
3964  generateWaitForNodes(module, function, triggerBlock, compositionStateValue, triggerWaitNodes, eventIdValue);
3965 
3966  // Update the trigger's data value.
3967  Value *triggerDataValue = trigger->generateDataValueUpdate(module, triggerBlock, function, triggerNodeContextValue);
3968 
3969  // Transmit events and data (if any) out of the trigger port, and send telemetry for port updates.
3970  generateTransmissionFromOutputPort(function, triggerBlock, compositionStateValue, triggerNode, trigger, NULL, triggerDataValue);
3971  }
3972 
3973  // If the trigger node isn't downstream of the trigger, signal the trigger node's semaphore.
3974  vector<VuoCompilerNode *> downstreamNodes = graph->getNodesDownstream(trigger);
3975  if (find(downstreamNodes.begin(), downstreamNodes.end(), triggerNode) == downstreamNodes.end())
3976  generateSignalForNodes(module, triggerBlock, compositionStateValue, vector<VuoCompilerNode *>(1, triggerNode));
3977 
3978  if (canDropEvents)
3979  // Signal the trigger's semaphore for event dropping.
3980  trigger->generateSignalForSemaphore(module, triggerBlock, triggerNodeContextValue);
3981 
3982  // Leave the trigger's dispatch group for tracking workers scheduled.
3983  VuoCompilerCodeGenUtilities::generateLeaveDispatchGroup(module, triggerBlock, triggerWorkersScheduledValue);
3984 
3985 
3986  // Schedule the chain worker function for each chain immediately downstream of the trigger.
3987 
3988  map<VuoCompilerChain *, vector<VuoCompilerChain *> > chainsImmediatelyDownstream;
3989  map<VuoCompilerChain *, vector<VuoCompilerChain *> > chainsImmediatelyUpstream;
3990  set<VuoCompilerChain *> chainsScheduled;
3991 
3992  vector<VuoCompilerChain *> allChains = chainsForTrigger[trigger];
3993 
3994  if (! allChains.empty())
3995  {
3996  // Organize the chains so it's easy to look up what's downstream/upstream of what.
3997  for (vector<VuoCompilerChain *>::iterator i = allChains.begin(); i != allChains.end(); ++i)
3998  {
3999  VuoCompilerChain *chain = *i;
4000  VuoCompilerNode *firstNodeInThisChain = chain->getNodes().front();
4001 
4002  for (vector<VuoCompilerChain *>::iterator j = allChains.begin(); j != allChains.end(); ++j)
4003  {
4004  VuoCompilerChain *otherChain = *j;
4005 
4006  if (chain == otherChain)
4007  break; // Any chains after this are downstream.
4008 
4009  VuoCompilerNode *lastNodeInOtherChain = otherChain->getNodes().back();
4010 
4011  if (graph->mayTransmit(lastNodeInOtherChain, firstNodeInThisChain, trigger))
4012  {
4013  chainsImmediatelyUpstream[chain].push_back(otherChain);
4014  chainsImmediatelyDownstream[otherChain].push_back(chain);
4015  }
4016  }
4017  }
4018 
4019  // Create the context to pass to the chain workers.
4020  Value *contextValue = VuoCompilerChain::generateMakeContext(module, triggerBlock, compositionStateValue, eventIdValue);
4021 
4022  // Find all chains immediately downstream of the trigger (i.e., chains that have no other chains upstream).
4023  vector<VuoCompilerChain *> firstChains;
4024  for (vector<VuoCompilerChain *>::iterator i = allChains.begin(); i != allChains.end(); ++i)
4025  {
4026  VuoCompilerChain *chain = *i;
4027  map<VuoCompilerChain *, vector<VuoCompilerChain *> >::iterator upstreamIter = chainsImmediatelyUpstream.find(chain);
4028  if (upstreamIter == chainsImmediatelyUpstream.end())
4029  firstChains.push_back(chain);
4030  }
4031 
4032  // Choose one chain to execute in the trigger worker, to reduce overhead creating/destroying threads.
4033  VuoCompilerChain *chainToExecute = firstChains.back();
4034  firstChains.pop_back();
4035  chainsScheduled.insert(chainToExecute);
4036  size_t chainIndex = find(allChains.begin(), allChains.end(), chainToExecute) - allChains.begin();
4037  VuoCompilerCodeGenUtilities::generateRetainCall(module, triggerBlock, contextValue);
4038 
4039  // Call `vuoGrantThreadsToChain()` for the chosen chain.
4040  int minThreadsNeeded, maxThreadsNeeded;
4041  graph->getWorkerThreadsNeeded(chainToExecute, minThreadsNeeded, maxThreadsNeeded);
4042  VuoCompilerCodeGenUtilities::generateGrantThreadsToChain(module, triggerBlock, minThreadsNeeded, maxThreadsNeeded,
4043  eventIdValue, compositionStateValue, chainIndex);
4044 
4045  // Schedule the rest of the chains immediately downstream of the trigger.
4046  generateAndScheduleChainWorkerFunctions(triggerBlock, compositionStateValue, contextValue, firstChains, trigger,
4047  allChains, chainsImmediatelyDownstream, chainsImmediatelyUpstream, chainsScheduled);
4048 
4049  // Execute the chosen chain.
4050  generateChainExecution(function, triggerBlock, compositionStateValue, contextValue, eventIdValue, chainToExecute, trigger,
4051  allChains, chainsImmediatelyDownstream, chainsImmediatelyUpstream, chainsScheduled);
4052  VuoCompilerCodeGenUtilities::generateReleaseCall(module, triggerBlock, contextValue);
4053  }
4054  else
4055  {
4056  // Call `vuoReturnThreadsForTriggerWorker()`.
4057  VuoCompilerCodeGenUtilities::generateReturnThreadsForTriggerWorker(module, triggerBlock, eventIdValue, compositionStateValue);
4058 
4059  if (isNodeEventForSubcomposition)
4060  {
4061  // Leave the dispatch group waited on by `nodeEvent()`/`nodeInstanceEvent()`.
4062  Value *subcompositionOutputGroupValue = VuoCompilerCodeGenUtilities::generateGetNodeContextExecutingGroup(module, triggerBlock, compositionContextValue);
4063  VuoCompilerCodeGenUtilities::generateLeaveDispatchGroup(module, triggerBlock, subcompositionOutputGroupValue);
4064  }
4065  }
4066 
4067  BranchInst::Create(finalBlock, triggerBlock);
4068 
4069  // Free the trigger worker's context.
4070  trigger->generateFreeContext(module, finalBlock, function);
4071  VuoCompilerCodeGenUtilities::generateReleaseCall(module, finalBlock, compositionStateValue);
4072 
4073  ReturnInst::Create(module->getContext(), finalBlock);
4074 
4075  return function;
4076 }
4077 
4081 void VuoCompilerBitcodeGenerator::generateAndScheduleChainWorkerFunctions(BasicBlock *schedulerBlock,
4082  Value *compositionStateValueInScheduler, Value *contextValueInScheduler,
4083  const vector<VuoCompilerChain *> &chainsToSchedule, VuoCompilerTriggerPort *trigger,
4084  const vector<VuoCompilerChain *> &allChains,
4085  const map<VuoCompilerChain *, vector<VuoCompilerChain *> > &chainsImmediatelyDownstream,
4086  const map<VuoCompilerChain *, vector<VuoCompilerChain *> > &chainsImmediatelyUpstream,
4087  set<VuoCompilerChain *> &chainsScheduled)
4088 {
4089  // Find the chains in chainsToSchedule that haven't already been scheduled.
4090  vector<VuoCompilerChain *> uniqueChainsToSchedule;
4091  for (vector<VuoCompilerChain *>::const_iterator i = chainsToSchedule.begin(); i != chainsToSchedule.end(); ++i)
4092  {
4093  VuoCompilerChain *chain = *i;
4094  if (chainsScheduled.find(chain) == chainsScheduled.end())
4095  {
4096  uniqueChainsToSchedule.push_back(chain);
4097  chainsScheduled.insert(chain);
4098  }
4099  }
4100 
4101  // Retain the context once for each chain to be scheduled.
4102  for (vector<VuoCompilerChain *>::const_iterator i = uniqueChainsToSchedule.begin(); i != uniqueChainsToSchedule.end(); ++i)
4103  VuoCompilerCodeGenUtilities::generateRetainCall(module, schedulerBlock, contextValueInScheduler);
4104 
4105  // Schedule each chain.
4106  for (vector<VuoCompilerChain *>::const_iterator i = uniqueChainsToSchedule.begin(); i != uniqueChainsToSchedule.end(); ++i)
4107  {
4108  VuoCompilerChain *chain = *i;
4109  generateAndScheduleChainWorkerFunction(schedulerBlock, compositionStateValueInScheduler, contextValueInScheduler,
4110  chain, trigger, allChains, chainsImmediatelyDownstream, chainsImmediatelyUpstream,
4111  chainsScheduled);
4112  }
4113 }
4114 
4118 void VuoCompilerBitcodeGenerator::generateAndScheduleChainWorkerFunction(BasicBlock *schedulerBlock,
4119  Value *compositionStateValueInScheduler, Value *contextValueInScheduler,
4120  VuoCompilerChain *chain, VuoCompilerTriggerPort *trigger,
4121  const vector<VuoCompilerChain *> &allChains,
4122  const map<VuoCompilerChain *, vector<VuoCompilerChain *> > &chainsImmediatelyDownstream,
4123  const map<VuoCompilerChain *, vector<VuoCompilerChain *> > &chainsImmediatelyUpstream,
4124  set<VuoCompilerChain *> &chainsScheduled)
4125 {
4126  int minThreadsNeeded, maxThreadsNeeded;
4127  graph->getWorkerThreadsNeeded(chain, minThreadsNeeded, maxThreadsNeeded);
4128 
4129  size_t chainIndex = find(allChains.begin(), allChains.end(), chain) - allChains.begin();
4130 
4131  vector<VuoCompilerChain *> upstreamChains;
4132  map<VuoCompilerChain *, vector<VuoCompilerChain *> >::const_iterator upstreamChainsIter = chainsImmediatelyUpstream.find(chain);
4133  if (upstreamChainsIter != chainsImmediatelyUpstream.end())
4134  upstreamChains = upstreamChainsIter->second;
4135 
4136  vector<size_t> upstreamChainIndices;
4137  for (vector<VuoCompilerChain *>::iterator i = upstreamChains.begin(); i != upstreamChains.end(); ++i)
4138  upstreamChainIndices.push_back( find(allChains.begin(), allChains.end(), *i) - allChains.begin() );
4139 
4140  // Call `vuoScheduleChainWorker` for the worker function implemented below.
4141  Function *chainWorker = chain->generateScheduleWorker(module, schedulerBlock, compositionStateValueInScheduler, contextValueInScheduler,
4142  trigger->getIdentifier(), minThreadsNeeded, maxThreadsNeeded, chainIndex,
4143  upstreamChainIndices);
4144 
4145  BasicBlock *chainBlock = BasicBlock::Create(module->getContext(), "", chainWorker, 0);
4146  Value *contextValueInChainWorker = chainWorker->arg_begin();
4147  Value *compositionStateValueInChainWorker = chain->generateCompositionStateValue(module, chainBlock, contextValueInChainWorker);
4148  Value *eventIdValue = chain->generateEventIdValue(module, chainBlock, contextValueInChainWorker);
4149 
4150  // Execute the chain.
4151  generateChainExecution(chainWorker, chainBlock, compositionStateValueInChainWorker, contextValueInChainWorker, eventIdValue, chain, trigger,
4152  allChains, chainsImmediatelyDownstream, chainsImmediatelyUpstream, chainsScheduled);
4153 
4154  // Release the chain worker's context.
4155  VuoCompilerCodeGenUtilities::generateReleaseCall(module, chainBlock, contextValueInChainWorker);
4156 
4157  ReturnInst::Create(module->getContext(), chainBlock);
4158 }
4159 
4163 void VuoCompilerBitcodeGenerator::generateChainExecution(Function *function, BasicBlock *&block,
4164  Value *compositionStateValue, Value *contextValue,
4165  Value *eventIdValue, VuoCompilerChain *chain, VuoCompilerTriggerPort *trigger,
4166  const vector<VuoCompilerChain *> &allChains,
4167  const map<VuoCompilerChain *, vector<VuoCompilerChain *> > &chainsImmediatelyDownstream,
4168  const map<VuoCompilerChain *, vector<VuoCompilerChain *> > &chainsImmediatelyUpstream,
4169  set<VuoCompilerChain *> &chainsScheduled)
4170 {
4171  size_t chainIndex = find(allChains.begin(), allChains.end(), chain) - allChains.begin();
4172  Value *chainIndexValue = ConstantInt::get(eventIdValue->getType(), chainIndex);
4173 
4174  // For each node in the chain...
4175  vector<VuoCompilerNode *> chainNodes = chain->getNodes();
4176  for (vector<VuoCompilerNode *>::iterator i = chainNodes.begin(); i != chainNodes.end(); ++i)
4177  {
4178  VuoCompilerNode *node = *i;
4179 
4180  Function *nodeExecutionFunction = executionFunctionForNode[node];
4181  if (! nodeExecutionFunction)
4182  {
4183  nodeExecutionFunction = generateNodeExecutionFunction(module, node);
4184  executionFunctionForNode[node] = nodeExecutionFunction;
4185  }
4186 
4187  Function *nodeTransmissionFunction = transmissionFunctionForNode[node];
4188  if (! nodeTransmissionFunction)
4189  {
4190  nodeTransmissionFunction = generateNodeTransmissionFunction(module, node);
4191  transmissionFunctionForNode[node] = nodeTransmissionFunction;
4192  }
4193 
4194  // If the event hit the node, call its event function and send telemetry.
4195  vector<Value *> nodeExecutionArgs;
4196  nodeExecutionArgs.push_back(compositionStateValue);
4197  nodeExecutionArgs.push_back(eventIdValue);
4198  nodeExecutionArgs.push_back(chainIndexValue);
4199  CallInst *isHitValue = CallInst::Create(nodeExecutionFunction, nodeExecutionArgs, "", block);
4200 
4201  // Whether or not the event hit the node, wait on any necessary downstream nodes.
4202  if (! (graph->isRepeatedInFeedbackLoop(node, trigger) && chain->isLastNodeInLoop()))
4203  {
4204  vector<VuoCompilerNode *> outputNodes = getNodesToWaitOnBeforeTransmission(trigger, node);
4205  generateWaitForNodes(module, function, block, compositionStateValue, outputNodes, eventIdValue);
4206  }
4207 
4208  // If the event hit the node, transmit events and data through its output cables and send telemetry.
4209  vector<Value *> nodeTransmissionArgs;
4210  nodeTransmissionArgs.push_back(compositionStateValue);
4211  nodeTransmissionArgs.push_back(isHitValue);
4212  CallInst::Create(nodeTransmissionFunction, nodeTransmissionArgs, "", block);
4213 
4214  // Whether or not the event hit the node, if this was the last time this event could reach the node,
4215  // signal the node's semaphore.
4216  if (! (graph->isRepeatedInFeedbackLoop(node, trigger) && ! chain->isLastNodeInLoop()))
4217  {
4218  // Special case: If this is the published output node in a subcomposition,
4219  // the node's semaphore is signaled in the node's execution function or the subcomposition's nodeEvent()/nodeInstanceEvent().
4220  if (! (! isTopLevelComposition && node == graph->getPublishedOutputNode()))
4221  generateSignalForNodes(module, block, compositionStateValue, vector<VuoCompilerNode *>(1, node));
4222  }
4223  }
4224 
4225  // Schedule any chains immediately downstream, if this chain is the one responsible for doing so.
4226  vector<VuoCompilerChain *> downstreamChains;
4227  map<VuoCompilerChain *, vector<VuoCompilerChain *> >::const_iterator downstreamChainsIter = chainsImmediatelyDownstream.find(chain);
4228  if (downstreamChainsIter != chainsImmediatelyDownstream.end())
4229  downstreamChains = downstreamChainsIter->second;
4230  if (! downstreamChains.empty())
4231  {
4232  vector<size_t> downstreamChainIndices;
4233  for (vector<VuoCompilerChain *>::iterator i = downstreamChains.begin(); i != downstreamChains.end(); ++i)
4234  downstreamChainIndices.push_back( find(allChains.begin(), allChains.end(), *i) - allChains.begin() );
4235 
4236  vector<VuoCompilerChain *> nextChains;
4237  for (vector<VuoCompilerChain *>::iterator i = downstreamChains.begin(); i != downstreamChains.end(); ++i)
4238  {
4239  VuoCompilerChain *downstreamChain = *i;
4240  nextChains.push_back(downstreamChain);
4241  }
4242 
4243  generateAndScheduleChainWorkerFunctions(block, compositionStateValue, contextValue, nextChains, trigger, allChains,
4244  chainsImmediatelyDownstream, chainsImmediatelyUpstream, chainsScheduled);
4245  }
4246 
4247  // Return the threads used by this chain to the thread pool.
4248  VuoCompilerCodeGenUtilities::generateReturnThreadsForChainWorker(module, block, eventIdValue, compositionStateValue, chainIndexValue);
4249 }
4250 
4296 Function * VuoCompilerBitcodeGenerator::generateNodeExecutionFunction(Module *module, VuoCompilerNode *node)
4297 {
4298  string functionName = node->getIdentifier() + "__execute";
4299  PointerType *pointerToCompositionStateType = PointerType::get(VuoCompilerCodeGenUtilities::getCompositionStateType(module), 0);
4300  Type *boolType = IntegerType::get(module->getContext(), 1);
4301  Type *eventIdType = VuoCompilerCodeGenUtilities::generateNoEventIdConstant(module)->getType();
4302  vector<Type *> params;
4303  params.push_back(pointerToCompositionStateType);
4304  params.push_back(eventIdType);
4305  params.push_back(eventIdType);
4306  FunctionType *functionType = FunctionType::get(boolType, params, false);
4307  Function *function = Function::Create(functionType, GlobalValue::InternalLinkage, functionName, module);
4308 
4309  Function::arg_iterator args = function->arg_begin();
4310  Value *compositionStateValue = args++;
4311  compositionStateValue->setName("compositionState");
4312  Value *eventIdValue = args++;
4313  eventIdValue->setName("eventId");
4314  Value *chainIndexValue = args++;
4315  chainIndexValue->setName("chainIndex");
4316 
4317  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, NULL);
4318  BasicBlock *finalBlock = BasicBlock::Create(module->getContext(), "final", function, NULL);
4319 
4320  Value *nodeContextValue = node->generateGetContext(module, initialBlock, compositionStateValue);
4321  Value *isHitValue = node->generateReceivedEventCondition(module, initialBlock, nodeContextValue);
4322 
4323  if (node == graph->getPublishedOutputNode())
4324  {
4325  if (isTopLevelComposition)
4326  {
4327  VuoCompilerCodeGenUtilities::generateSendEventFinished(module, initialBlock, compositionStateValue, eventIdValue);
4328 
4329  BranchInst::Create(finalBlock, initialBlock);
4330  }
4331  else
4332  {
4333  // Call the trigger functions for any published trigger ports that the event has hit.
4334 
4335  BasicBlock *currBlock = initialBlock;
4336 
4337  Value *compositionContextValue = VuoCompilerCodeGenUtilities::generateGetCompositionContext(module, currBlock, compositionStateValue);
4338 
4339  vector<VuoPublishedPort *> publishedInputPorts = composition->getBase()->getPublishedInputPorts();
4340  vector<VuoPublishedPort *> publishedOutputPorts = composition->getBase()->getPublishedOutputPorts();
4341 
4342  set<string> publishedOutputTriggerNames = graph->getPublishedOutputTriggers();
4343 
4344  for (size_t publishedPortIndex = 0; publishedPortIndex < publishedOutputPorts.size(); ++publishedPortIndex)
4345  {
4346  VuoPort *port = graph->getInputPortOnPublishedOutputNode(publishedPortIndex);
4347 
4348  Value *isPortHitValue = node->generateReceivedEventCondition(module, currBlock, nodeContextValue, vector<VuoPort *>(1, port));
4349 
4350  if (publishedOutputTriggerNames.find( port->getClass()->getName() ) != publishedOutputTriggerNames.end())
4351  {
4352  BasicBlock *triggerBlock = BasicBlock::Create(module->getContext(), "trigger", function, NULL);
4353  BasicBlock *nextBlock = BasicBlock::Create(module->getContext(), "next", function, NULL);
4354  BranchInst::Create(triggerBlock, nextBlock, isPortHitValue, currBlock);
4355 
4356  VuoCompilerInputEventPort *eventPort = static_cast<VuoCompilerInputEventPort *>( port->getCompiler() );
4357  VuoCompilerInputEventPortClass *eventPortClass = static_cast<VuoCompilerInputEventPortClass *>( port->getClass()->getCompiler() );
4358  VuoType *dataType = eventPort->getDataVuoType();
4359 
4360  FunctionType *triggerFunctionType = VuoCompilerCodeGenUtilities::getFunctionType(module, dataType);
4361 
4362  vector<Value *> args;
4363  if (dataType)
4364  {
4365  Value *dataValue = eventPort->generateLoadData(module, triggerBlock, nodeContextValue);
4366  bool isPassedByValue = dataType->getCompiler()->getFunctionParameterAttributes().hasAttrSomewhere(Attribute::ByVal);
4367  bool isLoweredToTwoParameters = eventPortClass->getDataClass()->isLoweredToTwoParameters();
4368  Value *secondArg = NULL;
4369  Value **secondArgIfNeeded = (isLoweredToTwoParameters ? &secondArg : NULL);
4370  Value *arg = VuoCompilerCodeGenUtilities::convertArgumentToParameterType(dataValue, triggerFunctionType, 0, isPassedByValue,
4371  secondArgIfNeeded, module, triggerBlock);
4372  args.push_back(arg);
4373  if (secondArg)
4374  args.push_back(secondArg);
4375  }
4376 
4377  int indexInSubcompositionPorts = VuoNodeClass::unreservedInputPortStartIndex + publishedInputPorts.size() +
4378  VuoNodeClass::unreservedOutputPortStartIndex + publishedPortIndex;
4379 
4380  Value *portContextValue = VuoCompilerCodeGenUtilities::generateGetNodeContextPortContext(module, triggerBlock, compositionContextValue, indexInSubcompositionPorts);
4381  Value *triggerFunction = VuoCompilerCodeGenUtilities::generateGetPortContextTriggerFunction(module, triggerBlock, portContextValue, triggerFunctionType);
4382 
4383  CallInst::Create(triggerFunction, args, "", triggerBlock);
4384  BranchInst::Create(nextBlock, triggerBlock);
4385 
4386  currBlock = nextBlock;
4387  }
4388  else
4389  {
4390  VuoCompilerCodeGenUtilities::generateSetNodeContextOutputEvent(module, currBlock, compositionContextValue, publishedPortIndex, isPortHitValue);
4391  }
4392  }
4393 
4394  // If this event (which may or may not have actually hit the published output node) is from
4395  // nodeEvent()/nodeInstanceEvent() or an event spun off of it, and is the final one to complete, then...
4396 
4397  Value *subcompositionFinishedValue = VuoCompilerCodeGenUtilities::generateFinishedExecutingEvent(module, currBlock, compositionContextValue, eventIdValue);
4398  ConstantInt *falseValue = ConstantInt::get(static_cast<IntegerType *>(subcompositionFinishedValue->getType()), 0);
4399  ICmpInst *subcompositionFinishedIsTrue = new ICmpInst(*currBlock, ICmpInst::ICMP_NE, subcompositionFinishedValue, falseValue, "");
4400  BasicBlock *leaveBlock = BasicBlock::Create(module->getContext(), "leave", function, NULL);
4401  BasicBlock *signalBlock = BasicBlock::Create(module->getContext(), "signal", function, NULL);
4402  BranchInst::Create(leaveBlock, signalBlock, subcompositionFinishedIsTrue, currBlock);
4403 
4404  // Leave the dispatch group waited on by nodeEvent()/nodeInstanceEvent().
4405 
4406  Value *subcompositionOutputGroupValue = VuoCompilerCodeGenUtilities::generateGetNodeContextExecutingGroup(module, leaveBlock, compositionContextValue);
4407  VuoCompilerCodeGenUtilities::generateLeaveDispatchGroup(module, leaveBlock, subcompositionOutputGroupValue);
4408  BranchInst::Create(finalBlock, leaveBlock);
4409 
4410  // Otherwise, signal the published output node's semaphore so that the remaining events can claim it.
4411  // (For the final event, the published output node's semaphore is signaled in nodeEvent()/nodeInstanceEvent().)
4412 
4413  generateSignalForNodes(module, signalBlock, compositionStateValue, vector<VuoCompilerNode *>(1, node));
4414  BranchInst::Create(finalBlock, signalBlock);
4415  }
4416  }
4417  else
4418  {
4419  // If the node received an event, then...
4420  BasicBlock *executeBlock = BasicBlock::Create(module->getContext(), "execute", function, NULL);
4421  BranchInst::Create(executeBlock, finalBlock, isHitValue, initialBlock);
4422 
4423  if (node->getBase()->getNodeClass()->getCompiler()->isSubcomposition())
4424  {
4425  // Pass the event ID to the subcomposition.
4426  VuoCompilerCodeGenUtilities::generateStartedExecutingEvent(module, executeBlock, nodeContextValue, eventIdValue);
4427 
4428  // Pass the chain's reserved threads to the subcomposition.
4429  Value *compositionIdentifierValue = VuoCompilerCodeGenUtilities::generateGetCompositionStateCompositionIdentifier(module, executeBlock, compositionStateValue);
4430  Value *subcompositionIdentifierValue = node->generateSubcompositionIdentifierValue(module, executeBlock, compositionIdentifierValue);
4432  eventIdValue, compositionStateValue, chainIndexValue,
4433  subcompositionIdentifierValue);
4434  VuoCompilerCodeGenUtilities::generateFreeCall(module, executeBlock, subcompositionIdentifierValue);
4435  }
4436 
4437  // Call the node's event function, and send telemetry that the node's execution has started and finished.
4438  bool shouldSendTelemetry = (node != graph->getPublishedInputNode());
4439  generateNodeExecution(function, executeBlock, compositionStateValue, node, shouldSendTelemetry);
4440  BranchInst::Create(finalBlock, executeBlock);
4441  }
4442 
4443  ReturnInst::Create(module->getContext(), isHitValue, finalBlock);
4444 
4445  return function;
4446 }
4447 
4472 Function * VuoCompilerBitcodeGenerator::generateNodeTransmissionFunction(Module *module, VuoCompilerNode *node)
4473 {
4474  string functionName = node->getIdentifier() + "__transmit";
4475  PointerType *pointerToCompositionStateType = PointerType::get(VuoCompilerCodeGenUtilities::getCompositionStateType(module), 0);
4476  Type *boolType = IntegerType::get(module->getContext(), 1);
4477  vector<Type *> params;
4478  params.push_back(pointerToCompositionStateType);
4479  params.push_back(boolType);
4480  FunctionType *functionType = FunctionType::get(Type::getVoidTy(module->getContext()), params, false);
4481  Function *function = Function::Create(functionType, GlobalValue::InternalLinkage, functionName, module);
4482 
4483  Function::arg_iterator args = function->arg_begin();
4484  Value *compositionStateValue = args++;
4485  compositionStateValue->setName("compositionState");
4486  Value *isHitValue = args++;
4487  isHitValue->setName("isHit");
4488 
4489  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, NULL);
4490  BasicBlock *transmitBlock = BasicBlock::Create(module->getContext(), "transmit", function, NULL);
4491  BasicBlock *finalBlock = BasicBlock::Create(module->getContext(), "final", function, NULL);
4492 
4493  // If the node received an event, then...
4494  BranchInst::Create(transmitBlock, finalBlock, isHitValue, initialBlock);
4495 
4496  Value *nodeContextValue = node->generateGetContext(module, transmitBlock, compositionStateValue);
4497 
4498  if (node == graph->getPublishedOutputNode())
4499  {
4500  if (isTopLevelComposition)
4501  generateTelemetryFromPublishedOutputNode(function, transmitBlock, compositionStateValue, nodeContextValue, node);
4502  }
4503  else
4504  {
4505  // Transmit events and data through the node's outgoing cables, and send telemetry for port updates.
4506  generateTransmissionFromNode(function, transmitBlock, compositionStateValue, nodeContextValue, node);
4507  }
4508 
4509  // Reset the node's event inputs and outputs.
4510  VuoCompilerCodeGenUtilities::generateResetNodeContextEvents(module, transmitBlock, nodeContextValue);
4511 
4512  BranchInst::Create(finalBlock, transmitBlock);
4513  ReturnInst::Create(module->getContext(), finalBlock);
4514 
4515  return function;
4516 }
4517 
4522 {
4523  this->debugMode = debugMode;
4524 }