Vuo  2.3.1
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"
19 #include "VuoCompilerGraph.hh"
23 #include "VuoCompilerNode.hh"
24 #include "VuoCompilerNodeClass.hh"
30 #include "VuoCompilerType.hh"
31 #include "VuoComposition.hh"
33 #include "VuoNode.hh"
34 #include "VuoNodeClass.hh"
35 #include "VuoStringUtilities.hh"
36 #include "VuoPublishedPort.hh"
37 #include "VuoType.hh"
38 
43  bool isTopLevelComposition,
44  string moduleKey, VuoCompiler *compiler)
45 {
46  VuoCompilerBitcodeGenerator * cg = new VuoCompilerBitcodeGenerator(composition, isTopLevelComposition, moduleKey, compiler);
47  return cg;
48 }
49 
53 VuoCompilerBitcodeGenerator::VuoCompilerBitcodeGenerator(VuoCompilerComposition *composition,
54  bool isTopLevelComposition,
55  string moduleKey, VuoCompiler *compiler)
56 {
57 #if VUO_PRO
58  VuoCompilerBitcodeGenerator_Pro();
59 #endif
60  module = nullptr;
61  constantsCache = nullptr;
62  debugMode = false;
63 
64  this->composition = composition;
65  this->isTopLevelComposition = isTopLevelComposition;
66  this->moduleKey = moduleKey;
67  this->compiler = compiler;
68 
69  graph = composition->getCachedGraph(compiler);
70 
71  chainsForTrigger = graph->getChains(); // store in a data member, rather than calling getChains() multiple times, to preserve order of chains
72  makeOrderedNodes();
73  makeOrderedTypes();
74  makePortContextInfo();
75  makeSubcompositionModelPorts();
76  makeDependencies();
77 }
78 
83 {
84  for (vector<VuoPort *>::iterator i = modelOutputPorts.begin(); i != modelOutputPorts.end(); ++i)
85  {
86  VuoPort *modelOutputPort = *i;
87  if (modelOutputPort->getClass()->getPortType() == VuoPortClass::triggerPort)
88  {
89  delete modelOutputPort->getClass()->getCompiler();
90  delete modelOutputPort->getCompiler();
91  }
92  }
93 }
94 
98 struct ChainSort
99 {
102  set<VuoCompilerNode *> lastNodeInLoop;
103 
107  bool operator() (const vector<VuoCompilerNode *> &chainNodes1, const vector<VuoCompilerNode *> &chainNodes2)
108  {
109  // If the chains have an upstream-downstream relationship, return whether chainNodes1 is upstream of chainNodes2.
110 
111  vector<VuoCompilerNode *> downstreamOfChain1 = graph->getNodesDownstream(chainNodes1.back(), trigger);
112  vector<VuoCompilerNode *> downstreamOfChain2 = graph->getNodesDownstream(chainNodes2.back(), trigger);
113 
114  bool isNode2DownstreamOfNode1 = find(downstreamOfChain1.begin(), downstreamOfChain1.end(), chainNodes2.front()) != downstreamOfChain1.end();
115  bool isNode1DownstreamOfNode2 = find(downstreamOfChain2.begin(), downstreamOfChain2.end(), chainNodes1.front()) != downstreamOfChain2.end();
116 
117  if (isNode2DownstreamOfNode1 && isNode1DownstreamOfNode2)
118  return (lastNodeInLoop.find(chainNodes1.front()) != lastNodeInLoop.end());
119  else if (isNode2DownstreamOfNode1)
120  return true;
121  else if (isNode1DownstreamOfNode2)
122  return false;
123 
124  // If at least one of the chains contains a trigger port, return the chain containing the trigger port with
125  // the greatest number of downstream nodes.
126 
127  size_t maxNumDownstreamOfTrigger[2] = { 0, 0 };
128  vector<VuoCompilerNode *> chainNodes[2] = { chainNodes1, chainNodes2 };
129  for (int i = 0; i < 2; ++i)
130  {
131  for (vector<VuoCompilerNode *>::const_iterator j = chainNodes[i].begin(); j != chainNodes[i].end(); ++j)
132  {
133  VuoCompilerNode *node = *j;
134  vector<VuoPort *> outputPorts = node->getBase()->getOutputPorts();
135  for (vector<VuoPort *>::iterator k = outputPorts.begin(); k != outputPorts.end(); ++k)
136  {
137  VuoPort *outputPort = *k;
138  if (outputPort->getClass()->getPortType() == VuoPortClass::triggerPort)
139  {
140  VuoCompilerTriggerPort *trigger = dynamic_cast<VuoCompilerTriggerPort *>( outputPort->getCompiler() );
141  size_t numDownstreamOfTrigger = graph->getNodesDownstream(trigger).size();
142  maxNumDownstreamOfTrigger[i] = max(maxNumDownstreamOfTrigger[i], numDownstreamOfTrigger);
143  }
144  }
145  }
146  }
147 
148  if (maxNumDownstreamOfTrigger[0] != maxNumDownstreamOfTrigger[1])
149  return maxNumDownstreamOfTrigger[0] > maxNumDownstreamOfTrigger[1];
150 
151  // Tiebreak: Sort alphabetically.
152 
153  return chainNodes1.front()->getIdentifier() < chainNodes2.front()->getIdentifier();
154  }
155 };
156 
160 void VuoCompilerBitcodeGenerator::makeOrderedNodes(void)
161 {
162  // For each trigger, put its downstream nodes into topological order (optimized with ChainSort so that
163  // orderedNodes will be more likely to match the ordering of the triggers with more downstream nodes).
164  for (VuoCompilerTriggerPort *trigger : graph->getTriggerPorts())
165  {
166  vector<VuoCompilerChain *> chains;
167  map<VuoCompilerTriggerPort *, vector<VuoCompilerChain *> >::iterator chainsIter = chainsForTrigger.find(trigger);
168  if (chainsIter != chainsForTrigger.end())
169  chains = chainsIter->second;
170 
171  vector< vector<VuoCompilerNode *> > chainNodeLists;
172  set<VuoCompilerNode *> lastNodeInLoop;
173  for (VuoCompilerChain *chain : chains)
174  {
175  if (chain->isLastNodeInLoop())
176  lastNodeInLoop.insert( chain->getNodes().front() );
177  else
178  chainNodeLists.push_back( chain->getNodes() );
179  }
180 
181  ChainSort c;
182  c.graph = graph;
183  c.trigger = trigger;
184  c.lastNodeInLoop = lastNodeInLoop;
185  sort(chainNodeLists.begin(), chainNodeLists.end(), c);
186 
187  vector<VuoCompilerNode *> orderedNodeList;
188 
189  VuoCompilerNode *triggerNode = graph->getNodeForTriggerPort(trigger);
190  orderedNodeList.push_back(triggerNode);
191 
192  for (vector<VuoCompilerNode *> chainNodeList : chainNodeLists)
193  {
194  auto triggerNodeIter = std::find(chainNodeList.begin(), chainNodeList.end(), triggerNode);
195  if (triggerNodeIter != chainNodeList.end())
196  chainNodeList.erase(triggerNodeIter);
197 
198  orderedNodeList.insert( orderedNodeList.end(), chainNodeList.begin(), chainNodeList.end() );
199  }
200 
201  downstreamNodesForTrigger[trigger] = orderedNodeList;
202  }
203 
204  vector< vector<VuoCompilerNode *> > orderedNodesPerTrigger;
205  for (const map<VuoCompilerTriggerPort *, vector<VuoCompilerNode *> >::value_type &i : downstreamNodesForTrigger)
206  orderedNodesPerTrigger.push_back(i.second);
207 
208  // For each node that can transmit without an event, put it and its downstream nodes in with the triggers' downstream nodes.
209  for (VuoCompilerNode *node : graph->getNodes())
210  {
211  if (graph->mayTransmitDataOnly(node))
212  {
213  vector<VuoCompilerNode *> downstreamNodes = graph->getNodesDownstreamViaDataOnlyTransmission(node);
214  vector<VuoCompilerNode *> nodesInProgress;
215  nodesInProgress.push_back(node);
216  nodesInProgress.insert(nodesInProgress.end(), downstreamNodes.begin(), downstreamNodes.end());
217  orderedNodesPerTrigger.push_back(nodesInProgress);
218  }
219  }
220 
221  // Put the downstream nodes per trigger in descending order of number of downstream nodes.
222  std::sort(orderedNodesPerTrigger.begin(), orderedNodesPerTrigger.end(),
223  [](const vector<VuoCompilerNode *> &nodes1, const vector<VuoCompilerNode *> &nodes2) {
224  if (nodes1.size() != nodes2.size())
225  return nodes1.size() < nodes2.size();
226 
227  // Tiebreak: Sort alphabetically.
228  ostringstream oss1;
229  ostringstream oss2;
230  for (VuoCompilerNode *n : nodes1)
231  oss1 << n->getIdentifier() << " ";
232  for (VuoCompilerNode *n : nodes2)
233  oss2 << n->getIdentifier() << " ";
234  return oss1.str() < oss2.str();
235  });
236 
237  // Visit each trigger, in descending order of number of downstream nodes (so that orderedNodes will be more likely
238  // to match the ordering of the triggers with more downstream nodes, and thus be more likely to wait on them one at
239  // a time instead of less efficiently having to wait on all initially).
240  int previousTriggerNodeIndex = -1;
241  for (vector< vector<VuoCompilerNode *> >::reverse_iterator i = orderedNodesPerTrigger.rbegin(); i != orderedNodesPerTrigger.rend(); ++i)
242  {
243  // Merge the trigger's downstream nodes into orderedNodes.
244  int previousNodeIndex = previousTriggerNodeIndex;
245  bool isFirstNode = true;
246  for (VuoCompilerNode *node : *i)
247  {
248  vector<VuoCompilerNode *>::iterator nodeIter = find(orderedNodes.begin(), orderedNodes.end(), node);
249  if (nodeIter == orderedNodes.end())
250  nodeIter = orderedNodes.insert(orderedNodes.begin() + previousNodeIndex + 1, node);
251 
252  previousNodeIndex = max(previousNodeIndex, (int)(nodeIter - orderedNodes.begin()));
253  if (isFirstNode)
254  {
255  previousTriggerNodeIndex = previousNodeIndex;
256  isFirstNode = false;
257  }
258  }
259  }
260 
261  // Add (at the end) any remaining nodes in the composition.
262  for (VuoCompilerNode *node : graph->getNodes())
263  if (find(orderedNodes.begin(), orderedNodes.end(), node) == orderedNodes.end())
264  orderedNodes.push_back(node);
265 
266  for (size_t i = 0; i < orderedNodes.size(); ++i)
267  orderedNodes[i]->setIndexInOrderedNodes(i);
268 }
269 
273 void VuoCompilerBitcodeGenerator::sortNodes(vector<VuoCompilerNode *> &nodes)
274 {
275  vector<VuoCompilerNode *> sortedNodes;
276  for (vector<VuoCompilerNode *>::iterator i = orderedNodes.begin(); i != orderedNodes.end(); ++i)
277  {
278  VuoCompilerNode *node = *i;
279  if (find(nodes.begin(), nodes.end(), node) != nodes.end())
280  sortedNodes.push_back(node);
281  }
282  nodes = sortedNodes;
283 }
284 
288 vector<VuoCompilerNode *> VuoCompilerBitcodeGenerator::getNodesToWaitOnBeforeTransmission(VuoCompilerTriggerPort *trigger)
289 {
290  // Does the trigger have a scatter downstream, and another trigger overlaps with some branches of the scatter but
291  // not others? If so, then all downstream nodes will be locked before the event can proceed.
292  // (The analysis is an approximation. It checks if another trigger overlaps *anywhere* downstream, even if the
293  // overlap is after the scatter has been fully gathered back up.)
294  // This prevents deadlocks involving one trigger claiming one branch and the other trigger claiming another
295  // (https://b33p.net/kosada/node/6696, https://b33p.net/kosada/node/12503).
296 
297  bool hasScatterOverlappedByAnotherTrigger = graph->hasScatterPartiallyOverlappedByAnotherTrigger(trigger);
298 
299  // Does the trigger port cause a `Spin Off` node to fire an event that has downstream nodes in common with the trigger?
300  // If so, then all downstream nodes will be locked before the event can proceed.
301  // This prevents the trigger's event from getting stuck behind and having to wait on the `Spin Off` event,
302  // defeating the purpose of the `Spin Off` node (https://b33p.net/kosada/node/11351).
303 
304  bool hasOverlapWithSpinOff = graph->hasOverlapWithSpinOff(trigger);
305 
306  // Would the trigger port wait on nodes in a different order than orderedNodes?
307  // If so, then all downstream nodes will be locked before the event can proceed.
308  // This prevents deadlock where the events from two different trigger ports reach the downstream nodes in a different order
309  // (https://b33p.net/kosada/node/7924).
310 
311  vector<VuoCompilerNode *> sortedDownstreamNodes = downstreamNodesForTrigger[trigger];
312  sortNodes(sortedDownstreamNodes);
313  bool hasOutOfOrderDownstreamNodes = (downstreamNodesForTrigger[trigger] != sortedDownstreamNodes);
314 
315  // Wait for either all nodes downstream of the trigger or the nodes directly connected to the trigger.
316  vector<VuoCompilerNode *> nodesToWaitOn;
317  if (hasScatterOverlappedByAnotherTrigger || hasOverlapWithSpinOff || hasOutOfOrderDownstreamNodes)
318  nodesToWaitOn = downstreamNodesForTrigger[trigger];
319  else
320  {
321  nodesToWaitOn = graph->getNodesImmediatelyDownstream(trigger);
322  VuoCompilerNode *triggerNode = downstreamNodesForTrigger[trigger].front();
323  if (find(nodesToWaitOn.begin(), nodesToWaitOn.end(), triggerNode) == nodesToWaitOn.end())
324  nodesToWaitOn.push_back(triggerNode);
325  }
326 
327  return nodesToWaitOn;
328 }
329 
333 vector<VuoCompilerNode *> VuoCompilerBitcodeGenerator::getNodesToWaitOnBeforeTransmission(VuoCompilerTriggerPort *trigger, VuoCompilerNode *node)
334 {
335  // Does the node have a scatter downstream, and another trigger overlaps with some branches of the scatter but
336  // not others? If so, then all downstream nodes will be locked before the event can proceed.
337  // (The analysis is an approximation. It checks if another trigger overlaps *anywhere* downstream, even if the
338  // overlap is after the scatter has been fully gathered back up.)
339  // This prevents deadlocks involving one trigger claiming one branch and the other trigger claiming another
340  // (https://b33p.net/kosada/node/6696, https://b33p.net/kosada/node/12503, https://b33p.net/kosada/node/16202).
341 
342  bool hasGatherOverlappedByAnotherTrigger = graph->hasScatterPartiallyOverlappedByAnotherTrigger(node, trigger);
343 
344  // Wait for either all nodes downstream of the node or the nodes directly connected to the node.
345  vector<VuoCompilerNode *> nodesToWaitOn =
346  (hasGatherOverlappedByAnotherTrigger ?
347  graph->getNodesDownstream(node, trigger) :
348  graph->getNodesImmediatelyDownstream(node, trigger));
349 
350  return nodesToWaitOn;
351 }
352 
356 void VuoCompilerBitcodeGenerator::makeOrderedTypes(void)
357 {
358  for (VuoCompilerNode *node : graph->getNodes())
359  {
360  vector<VuoPort *> inputPorts = node->getBase()->getInputPorts();
361  vector<VuoPort *> outputPorts = node->getBase()->getOutputPorts();
362  vector<VuoPort *> ports;
363  ports.insert(ports.end(), inputPorts.begin(), inputPorts.end());
364  ports.insert(ports.end(), outputPorts.begin(), outputPorts.end());
365 
366  for (VuoPort *port : ports)
367  {
368  VuoType *dataType = static_cast<VuoCompilerPort *>(port->getCompiler())->getDataVuoType();
369 
370  if (dataType)
371  {
372  vector<VuoCompilerType *>::iterator typeIter = find(orderedTypes.begin(), orderedTypes.end(), dataType->getCompiler());
373  if (typeIter == orderedTypes.end())
374  orderedTypes.push_back(dataType->getCompiler());
375  }
376  }
377  }
378 }
379 
383 void VuoCompilerBitcodeGenerator::makePortContextInfo(void)
384 {
385  for (VuoCompilerNode *node : graph->getNodes())
386  {
387  vector<VuoPort *> inputPorts = node->getBase()->getInputPorts();
388  vector<VuoPort *> outputPorts = node->getBase()->getOutputPorts();
389  vector<VuoPort *> ports;
390  ports.insert(ports.end(), inputPorts.begin(), inputPorts.end());
391  ports.insert(ports.end(), outputPorts.begin(), outputPorts.end());
392  for (size_t i = 0; i < ports.size(); ++i)
393  {
394  VuoCompilerPort *port = static_cast<VuoCompilerPort *>( ports[i]->getCompiler() );
395 
396  port->setNodeIdentifier( node->getIdentifier() );
397  port->setIndexInPortContexts(i);
398  }
399  }
400 }
401 
405 void VuoCompilerBitcodeGenerator::makeSubcompositionModelPorts(void)
406 {
407  Module module("", *VuoCompiler::globalLLVMContext);
408 
409  vector<VuoPublishedPort *> publishedInputPorts = composition->getBase()->getPublishedInputPorts();
410  vector<VuoPublishedPort *> publishedOutputPorts = composition->getBase()->getPublishedOutputPorts();
411  modelInputPorts.insert( modelInputPorts.end(), publishedInputPorts.begin(), publishedInputPorts.end() );
412  modelOutputPorts.insert( modelOutputPorts.end(), publishedOutputPorts.begin(), publishedOutputPorts.end() );
413 
414  set<string> publishedOutputTriggerNames = graph->getPublishedOutputTriggers();
415 
416  for (size_t i = 0; i < modelOutputPorts.size(); ++i)
417  {
418  string portName = modelOutputPorts[i]->getClass()->getName();
419  if (publishedOutputTriggerNames.find(portName) != publishedOutputTriggerNames.end())
420  {
421  VuoType *dataType = static_cast<VuoCompilerPortClass *>( modelOutputPorts[i]->getClass()->getCompiler() )->getDataVuoType();
422  VuoCompilerTriggerPortClass *modelTriggerPortClass = new VuoCompilerTriggerPortClass(portName);
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  module = new Module(moduleKey, *VuoCompiler::globalLLVMContext);
466  constantsCache = new VuoCompilerConstantsCache(module);
467 
468  for (VuoCompilerNode *node : orderedNodes)
469  node->setConstantsCache(constantsCache);
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  if (isTopLevelComposition)
502  {
503  generateShouldShowSplashWindowFunction(compiler->shouldShowSplashWindow());
504 
505  generateAllocation();
506  generateSetupFunction(isStatefulComposition);
507  generateCleanupFunction();
508 
509  generateInstanceInitFunction(isStatefulComposition);
510  generateInstanceFiniFunction(isStatefulComposition);
511  generateInstanceTriggerStartFunction(isStatefulComposition);
512  generateInstanceTriggerStopFunction(isStatefulComposition);
513 
514  generateSetInputPortValueFunction();
515 
516  generateGetPublishedPortCountFunction(true);
517  generateGetPublishedPortCountFunction(false);
518  generateGetPublishedPortNamesFunction(true);
519  generateGetPublishedPortNamesFunction(false);
520  generateGetPublishedPortTypesFunction(true);
521  generateGetPublishedPortTypesFunction(false);
522  generateGetPublishedPortDetailsFunction(true);
523  generateGetPublishedPortDetailsFunction(false);
524  generateGetPublishedPortValueFunction(true);
525  generateGetPublishedPortValueFunction(false);
526  generateSetPublishedInputPortValueFunction();
527  generateFirePublishedInputPortEventFunction();
528  }
529 
530  composition->setModule(module);
531 
532  delete constantsCache;
533  constantsCache = nullptr;
534 
535  return module;
536 }
537 
541 void VuoCompilerBitcodeGenerator::generateCompositionMetadata(void)
542 {
543  json_object *metadataJson = json_object_new_object();
544  json_object *nodeMetadataJson = json_object_new_object();
545 
546  string title = composition->getBase()->getMetadata()->getCustomizedName();
547  if (title.empty())
548  {
549  string nodeClassNamePart = VuoStringUtilities::split(moduleKey, '.').back();
550  title = VuoStringUtilities::expandCamelCase(nodeClassNamePart);
551  }
552  json_object_object_add(metadataJson, "title", json_object_new_string(title.c_str()));
553 
554  string description = composition->getBase()->getMetadata()->getDescription();
555  json_object_object_add(metadataJson, "description", json_object_new_string(description.c_str()));
556 
557  json_object *keywordsJson = json_object_new_array();
558  for (const string &keyword : composition->getBase()->getMetadata()->getKeywords())
559  json_object_array_add(keywordsJson, json_object_new_string(keyword.c_str()));
560  json_object_object_add(metadataJson, "keywords", keywordsJson);
561 
562  string version = composition->getBase()->getMetadata()->getVersion();
563  if (! version.empty())
564  json_object_object_add(metadataJson, "version", json_object_new_string(version.c_str()));
565 
566  json_object *dependenciesJson = json_object_new_array();
567  for (const string &dependency : dependencies)
568  json_object_array_add(dependenciesJson, json_object_new_string(dependency.c_str()));
569  json_object_object_add(metadataJson, "dependencies", dependenciesJson);
570 
571  json_object *compatibilityJson = json_tokener_parse(composition->getCompatibleTargets().toJsonString().c_str());
572  json_object_object_add(metadataJson, "compatibility", compatibilityJson);
573 
574  if (! isTopLevelComposition)
575  {
576 #if VUO_PRO
577  generateCompositionMetadata_Pro(nodeMetadataJson);
578 #endif
579 
580  json_object *triggersJson = json_object_new_array();
581  for (VuoCompilerTriggerPort *trigger : graph->getTriggerPorts())
582  {
583  VuoCompilerNode *triggerNode = graph->getNodeForTriggerPort(trigger);
584  json_object *t = VuoCompilerTriggerDescription::getJson(triggerNode, trigger, graph);
585  json_object_array_add(triggersJson, t);
586  }
587  for (VuoCompilerNode *node : graph->getNodes())
588  {
589  VuoCompilerNodeClass *nodeClass = node->getBase()->getNodeClass()->getCompiler();
590  vector<VuoCompilerTriggerDescription *> triggersInSubcomposition = nodeClass->getTriggerDescriptions();
591  for (VuoCompilerTriggerDescription *triggerInSubcomposition : triggersInSubcomposition)
592  {
593  json_object *t = triggerInSubcomposition->getJsonWithinSubcomposition(node);
594  json_object_array_add(triggersJson, t);
595  }
596  }
597  json_object_object_add(nodeMetadataJson, "triggers", triggersJson);
598 
599  json_object *nodesJson = json_object_new_object();
600  for (VuoCompilerNode *node : orderedNodes)
601  {
602  json_object *nodeClassNameJson = json_object_new_string(node->getBase()->getNodeClass()->getClassName().c_str());
603  json_object_object_add(nodesJson, node->getIdentifier().c_str(), nodeClassNameJson);
604  }
605  json_object_object_add(nodeMetadataJson, "nodes", nodesJson);
606  }
607 
608  json_object_object_add(metadataJson, "node", nodeMetadataJson);
609 
610  string metadata = json_object_to_json_string_ext(metadataJson, JSON_C_TO_STRING_PLAIN);
611  json_object_put(metadataJson);
612 
613  VuoCompilerCodeGenUtilities::generateModuleMetadata(module, metadata, moduleKey);
614 }
615 
621 void VuoCompilerBitcodeGenerator::generateShouldShowSplashWindowFunction(bool shouldShow)
622 {
623  IntegerType *returnType = IntegerType::get(module->getContext(), 8);
624  FunctionType *functionType = FunctionType::get(returnType, false);
625  Function *function = Function::Create(functionType, GlobalValue::ExternalLinkage, "vuoShouldShowSplashWindow", module);
626  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
627  Value *boolValue = ConstantInt::get(returnType, shouldShow);
628  ReturnInst::Create(module->getContext(), boolValue, block);
629 }
630 
637 void VuoCompilerBitcodeGenerator::generateCompositionAddNodeMetadataFunction(void)
638 {
640  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
641 
642  Function::arg_iterator args = function->arg_begin();
643  Value *compositionStateValue = args++;
644  compositionStateValue->setName("compositionState");
645 
646  Function *compositionCreateContextForNodeFunction = VuoCompilerCodeGenUtilities::getCompositionCreateContextForNodeFunction(module);
647  Function *compositionSetPortValueFunction = VuoCompilerCodeGenUtilities::getCompositionSetPortValueFunction(module);
648  Function *compositionGetPortValueFunction = VuoCompilerCodeGenUtilities::getCompositionGetPortValueFunction(module);
649  Function *compositionFireTriggerPortEventFunction = VuoCompilerCodeGenUtilities::getCompositionFireTriggerPortEventFunction(module);
650  Function *releasePortDataFunction = VuoCompilerCodeGenUtilities::getCompositionReleasePortDataFunction(module);
651 
652  for (vector<VuoCompilerNode *>::iterator i = orderedNodes.begin(); i != orderedNodes.end(); ++i)
653  {
654  VuoCompilerNode *node = *i;
655 
656  node->generateAddMetadata(module, block, compositionStateValue, orderedTypes, compositionCreateContextForNodeFunction,
657  compositionSetPortValueFunction, compositionGetPortValueFunction, compositionFireTriggerPortEventFunction,
658  releasePortDataFunction);
659  }
660 
661  ReturnInst::Create(module->getContext(), block);
662 }
663 
670 void VuoCompilerBitcodeGenerator::generateCompositionCreateContextForNodeFunction(void)
671 {
673  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, NULL);
674  BasicBlock *finalBlock = BasicBlock::Create(module->getContext(), "final", function, NULL);
675 
676  Function::arg_iterator args = function->arg_begin();
677  Value *nodeIndexValue = args++;
678  nodeIndexValue->setName("nodeIndex");
679 
680  PointerType *pointerToNodeContext = PointerType::get(VuoCompilerCodeGenUtilities::getNodeContextType(module), 0);
681  AllocaInst *nodeContextVariable = new AllocaInst(pointerToNodeContext, 0, "nodeContext", initialBlock);
682 
683  vector< pair<BasicBlock *, BasicBlock *> > blocksForIndex;
684 
685  for (size_t i = 0; i < orderedNodes.size(); ++i)
686  {
687  VuoCompilerNode *node = orderedNodes[i];
688 
689  BasicBlock *block = BasicBlock::Create(module->getContext(), node->getIdentifier(), function, NULL);
690  Value *nodeContextValue = node->generateCreateContext(module, block);
691  new StoreInst(nodeContextValue, nodeContextVariable, block);
692 
693  blocksForIndex.push_back(make_pair(block, block));
694  }
695 
696  VuoCompilerCodeGenUtilities::generateIndexMatchingCode(module, function, initialBlock, finalBlock, nodeIndexValue, blocksForIndex);
697 
698  Value *nodeContextValue = new LoadInst(nodeContextVariable, "", false, finalBlock);
699  ReturnInst::Create(module->getContext(), nodeContextValue, finalBlock);
700 }
701 
710 void VuoCompilerBitcodeGenerator::generateCompositionPerformDataOnlyTransmissionsFunction(void)
711 {
713  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
714 
715  Function::arg_iterator args = function->arg_begin();
716  Value *compositionStateValue = args++;
717  compositionStateValue->setName("compositionState");
718 
719  // Copy data along cables supporting data-only transmission at this level of the composition.
720 
722  generateDataOnlyTransmissionFromNode(function, block, compositionStateValue, node, false, false, false);
723 
724  // For each subcomposition node…
725 
726  for (VuoCompilerNode *node : orderedNodes)
727  {
728  Function *subcompositionFunctionSrc = node->getBase()->getNodeClass()->getCompiler()->getCompositionPerformDataOnlyTransmissionsFunction();
729  if (subcompositionFunctionSrc)
730  {
731  Value *runtimeStateValue = VuoCompilerCodeGenUtilities::generateGetCompositionStateRuntimeState(module, block, compositionStateValue);
732  Value *compositionIdentifierValue = VuoCompilerCodeGenUtilities::generateGetCompositionStateCompositionIdentifier(module, block, compositionStateValue);
733  Value *subcompositionIdentifierValue = node->generateSubcompositionIdentifierValue(module, block, compositionIdentifierValue);
734  Value *subcompositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, runtimeStateValue, subcompositionIdentifierValue);
735  Value *subcompositionStateValueDst = new BitCastInst(subcompositionStateValue, subcompositionFunctionSrc->getFunctionType()->getParamType(0), "", block);
736 
737  // Copy the subcomposition node's input port values to the subcomposition's published input node's input ports.
738 
739  Function *setPublishedInputPortValueFunctionSrc = node->getBase()->getNodeClass()->getCompiler()->getCompositionSetPublishedInputPortValueFunction();
740  Function *setPublishedInputPortValueFunctionDst = VuoCompilerModule::declareFunctionInModule(module, setPublishedInputPortValueFunctionSrc);
741  Value *falseValue = ConstantInt::get(setPublishedInputPortValueFunctionDst->getFunctionType()->getParamType(3), 0);
742 
743  for (VuoPort *inputPort : node->getBase()->getInputPorts())
744  {
745  VuoCompilerInputEventPort *inputEventPort = static_cast<VuoCompilerInputEventPort *>(inputPort->getCompiler());
746  VuoCompilerInputData *inputData = inputEventPort->getData();
747  if (inputData)
748  {
749  Value *inputPortNameValue = constantsCache->get(inputPort->getClass()->getName());
750  Value *dataValue = constantsCache->get(inputData->getInitialValue());
751 
752  vector<Value *> args;
753  args.push_back(subcompositionStateValueDst);
754  args.push_back(inputPortNameValue);
755  args.push_back(dataValue);
756  args.push_back(falseValue);
757  CallInst::Create(setPublishedInputPortValueFunctionDst, args, "", block);
758  }
759  }
760 
761  // Call recursively for the subcomposition.
762 
763  Function *subcompositionFunctionDst = VuoCompilerModule::declareFunctionInModule(module, subcompositionFunctionSrc);
764  CallInst::Create(subcompositionFunctionDst, subcompositionStateValueDst, "", block);
765 
766  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, subcompositionStateValue);
767  VuoCompilerCodeGenUtilities::generateFreeCall(module, block, subcompositionIdentifierValue);
768  }
769  }
770 
771  ReturnInst::Create(module->getContext(), block);
772 }
773 
781 void VuoCompilerBitcodeGenerator::generateCompositionReleasePortDataFunction(void)
782 {
784  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, NULL);
785  BasicBlock *finalBlock = BasicBlock::Create(module->getContext(), "final", function, NULL);
786 
787  Function::arg_iterator args = function->arg_begin();
788  Value *portAddressAsVoidPointer = args++;
789  portAddressAsVoidPointer->setName("portData");
790  Value *typeIndexValue = args++;
791  typeIndexValue->setName("typeIndex");
792 
793  vector< pair<BasicBlock *, BasicBlock *> > blocksForIndex;
794 
795  for (vector<VuoCompilerType *>::iterator i = orderedTypes.begin(); i != orderedTypes.end(); ++i)
796  {
797  VuoCompilerType *type = *i;
798 
799  BasicBlock *block = BasicBlock::Create(module->getContext(), type->getBase()->getModuleKey(), function, NULL);
800  type->generateReleaseCall(module, block, portAddressAsVoidPointer);
801 
802  blocksForIndex.push_back(make_pair(block, block));
803  }
804 
805  VuoCompilerCodeGenUtilities::generateIndexMatchingCode(module, function, initialBlock, finalBlock, typeIndexValue, blocksForIndex);
806 
807  ReturnInst::Create(module->getContext(), finalBlock);
808 }
809 
813 void VuoCompilerBitcodeGenerator::generateSetInputDataFromNodeFunctionArguments(Function *function, BasicBlock *&block, Value *compositionStateValue,
814  map<VuoPort *, size_t> indexOfParameter,
815  map<VuoPort *, size_t> indexOfEventParameter,
816  bool shouldWaitForDataOnlyDownstreamNodes,
817  bool shouldUpdateTriggers, bool shouldSendTelemetry)
818 {
819  VuoCompilerNode *publishedInputNode = graph->getPublishedInputNode();
820  if (! publishedInputNode)
821  return;
822 
823  Value *publishedNodeContextValue = publishedInputNode->generateGetContext(module, block, compositionStateValue);
824 
825  vector<VuoPublishedPort *> publishedInputPorts = composition->getBase()->getPublishedInputPorts();
826  vector<VuoCompilerInputEventPort *> inputEventPorts;
827 
828  // Copy data from the function arguments to the published input node's input ports.
829 
830  for (size_t i = 0; i < publishedInputPorts.size(); ++i)
831  {
832  VuoPublishedPort *publishedInputPort = publishedInputPorts[i];
833 
834  VuoPort *inputPort = graph->getInputPortOnPublishedInputNode(i);
835  VuoCompilerInputEventPort *inputEventPort = static_cast<VuoCompilerInputEventPort *>( inputPort->getCompiler() );
836  inputEventPorts.push_back(inputEventPort);
837 
838  if (publishedInputPort->getClass()->getPortType() == VuoPortClass::dataAndEventPort)
839  {
840  size_t dataArgIndex = indexOfParameter[ modelInputPorts[i] ];
841  Value *dataPointer = inputEventPort->getDataType()->convertArgsToPortData(module, block, function, dataArgIndex);
842 
843  inputEventPort->generateReplaceData(module, block, publishedNodeContextValue, dataPointer);
844  }
845  }
846 
847  // Transmit data through the published input node and onward through the published input cables.
848  // (This temporarily sets an event on all of the published input node's input ports.)
849 
850  generateDataOnlyTransmissionFromNode(function, block, compositionStateValue, publishedInputNode,
851  shouldWaitForDataOnlyDownstreamNodes, shouldUpdateTriggers, shouldSendTelemetry);
852 
853  // Copy events from the function arguments to the published input node's input ports.
854 
855  for (size_t i = 0; i < publishedInputPorts.size(); ++i)
856  {
857  VuoCompilerInputEventPort *inputEventPort = inputEventPorts[i];
858 
859  map<VuoPort *, size_t> *indexMap = (inputEventPort->getBase()->getClass()->getPortType() == VuoPortClass::dataAndEventPort ?
860  &indexOfEventParameter :
861  &indexOfParameter);
862 
863  auto foundIndex = indexMap->find( modelInputPorts[i] );
864  if (foundIndex != indexMap->end())
865  {
866  size_t eventArgIndex = foundIndex->second;
867  Value *eventArg = VuoCompilerCodeGenUtilities::getArgumentAtIndex(function, eventArgIndex);
868 
869  inputEventPort->generateStoreEvent(module, block, publishedNodeContextValue, eventArg);
870  }
871  }
872 }
873 
882 void VuoCompilerBitcodeGenerator::generateNodeEventFunction(bool isStatefulComposition)
883 {
884  vector<VuoPort *> modelPorts;
885  modelPorts.insert(modelPorts.end(), modelInputPorts.begin(), modelInputPorts.end());
886  modelPorts.insert(modelPorts.end(), modelOutputPorts.begin(), modelOutputPorts.end());
887 
888  vector<VuoPublishedPort *> publishedInputPorts = composition->getBase()->getPublishedInputPorts();
889  vector<VuoPublishedPort *> publishedOutputPorts = composition->getBase()->getPublishedOutputPorts();
890  vector<VuoPublishedPort *> publishedPorts;
891  publishedPorts.insert(publishedPorts.end(), publishedInputPorts.begin(), publishedInputPorts.end());
892  publishedPorts.insert(publishedPorts.end(), publishedOutputPorts.begin(), publishedOutputPorts.end());
893 
894  map<VuoPort *, string> displayNamesForPorts;
895  map<VuoPort *, json_object *> detailsForPorts;
896  for (size_t i = 0; i < modelPorts.size(); ++i)
897  {
898  VuoPort *modelPort = modelPorts[i];
899  VuoPublishedPort *publishedPort = publishedPorts[i];
900 
901  string portName = modelPort->getClass()->getName();
902  bool isAllCaps = true;
903  for (size_t j = 0; j < portName.length(); ++j)
904  if (! isupper(portName[j]))
905  {
906  isAllCaps = false;
907  break;
908  }
909  if (isAllCaps)
910  displayNamesForPorts[modelPort] = portName;
911 
912  detailsForPorts[modelPort] = static_cast<VuoCompilerPortClass *>( publishedPort->getClass()->getCompiler() )->getDetails();
913  }
914 
915  map<VuoPort *, string> defaultValuesForInputPorts;
916  map<VuoPort *, VuoPortClass::EventBlocking> eventBlockingForInputPorts;
917  for (size_t i = 0; i < publishedInputPorts.size(); ++i)
918  {
919  VuoPublishedPort *publishedInputPort = publishedInputPorts[i];
920 
921  string defaultValue = static_cast<VuoCompilerPublishedPort *>( publishedInputPort->getCompiler() )->getInitialValue();
922  if (! defaultValue.empty())
923  defaultValuesForInputPorts[publishedInputPort] = defaultValue;
924 
925  eventBlockingForInputPorts[publishedInputPort] = graph->getPublishedInputEventBlocking(i);
926  }
927 
928  map<VuoPort *, size_t> indexOfParameter;
929  map<VuoPort *, size_t> indexOfEventParameter;
930  Function *function = VuoCompilerCodeGenUtilities::getNodeEventFunction(module, moduleKey, true, isStatefulComposition,
932  modelInputPorts, modelOutputPorts,
933  detailsForPorts, displayNamesForPorts,
934  defaultValuesForInputPorts, eventBlockingForInputPorts,
935  indexOfParameter, indexOfEventParameter, constantsCache);
936  BasicBlock *block = &(function->getEntryBlock());
937 
939  if (! trigger)
940  {
941  ReturnInst::Create(module->getContext(), block);
942  return;
943  }
944 
945  VuoCompilerNode *triggerNode = graph->getNodeForTriggerPort(trigger);
946 
947  Value *compositionStateValue = function->arg_begin();
948  Value *compositionContextValue = VuoCompilerCodeGenUtilities::generateGetCompositionContext(module, block, compositionStateValue);
949 
950  // Get the event ID passed down from the composition containing this subcomposition node.
951 
952  Value *eventIdValue = VuoCompilerCodeGenUtilities::generateGetOneExecutingEvent(module, block, compositionContextValue);
953 
954  // Claim all necessary downstream nodes.
955 
956  vector<VuoCompilerNode *> triggerWaitNodes = getNodesToWaitOnBeforeTransmission(trigger);
957  generateLockNodes(module, block, compositionStateValue, triggerWaitNodes, eventIdValue);
958 
959  // Set the data and event for each input port on the published input node from the input arguments.
960 
961  bool hasClaimedNodesDownstreamOfPublishedInputNode = (triggerWaitNodes.size() > 2);
962  generateSetInputDataFromNodeFunctionArguments(function, block, compositionStateValue, indexOfParameter, indexOfEventParameter,
963  ! hasClaimedNodesDownstreamOfPublishedInputNode, true, true);
964 
965  // Wait for the event to reach the published output node (if any) and all other leaf nodes — part 1.
966 
967  Value *subcompositionOutputGroupValue = VuoCompilerCodeGenUtilities::generateGetNodeContextExecutingGroup(module, block, compositionContextValue);
968  VuoCompilerCodeGenUtilities::generateEnterDispatchGroup(module, block, subcompositionOutputGroupValue);
969 
970  // Fire an event from the published input trigger.
971 
972  Value *triggerNodeContextValue = triggerNode->generateGetContext(module, block, compositionStateValue);
973  Value *triggerFunctionValue = trigger->generateLoadFunction(module, block, triggerNodeContextValue);
974  CallInst::Create(triggerFunctionValue, "", block);
975 
976  // Wait for the event to reach the published output node (if any) and all other leaf nodes — part 2.
977 
978  VuoCompilerCodeGenUtilities::generateWaitForDispatchGroup(module, block, subcompositionOutputGroupValue);
979 
980  // Set each output argument from the published output port values.
981 
982  VuoCompilerNode *publishedOutputNode = graph->getPublishedOutputNode();
983  Value *publishedOutputNodeContext = publishedOutputNode->generateGetContext(module, block, compositionStateValue);
984  for (size_t i = 0; i < modelOutputPorts.size(); ++i)
985  {
986  VuoPort *modelOutputPort = modelOutputPorts[i];
987  VuoPortClass::PortType portType = modelOutputPort->getClass()->getPortType();
988 
989  if (portType == VuoPortClass::dataAndEventPort || portType == VuoPortClass::eventOnlyPort)
990  {
992  bool hasEventParameter = false;
993  size_t eventIndex = 0;
994 
995  if (portType == VuoPortClass::dataAndEventPort)
996  {
997  size_t index = indexOfParameter[ modelOutputPort ];
998  Value *outputArg = VuoCompilerCodeGenUtilities::getArgumentAtIndex(function, index);
999 
1000  Value *inputDataPointer = inputPort->generateRetrieveData(module, block, publishedOutputNodeContext);
1001 
1002  VuoCompilerType *dataType = inputPort->getDataVuoType()->getCompiler();
1003  VuoCompilerCodeGenUtilities::generateMemoryCopy(module, block, inputDataPointer, outputArg, dataType->getSize(module));
1004 
1005  map<VuoPort *, size_t>::iterator iter = indexOfEventParameter.find(modelOutputPort);
1006  if (iter != indexOfEventParameter.end())
1007  {
1008  hasEventParameter = true;
1009  eventIndex = iter->second;
1010  }
1011  }
1012  else
1013  {
1014  hasEventParameter = true;
1015  eventIndex = indexOfParameter[ modelOutputPort ];
1016  }
1017 
1018  if (hasEventParameter)
1019  {
1020  Value *outputArg = VuoCompilerCodeGenUtilities::getArgumentAtIndex(function, eventIndex);
1021 
1022  Value *eventValue = VuoCompilerCodeGenUtilities::generateGetNodeContextOutputEvent(module, block, compositionContextValue, i);
1023  new StoreInst(eventValue, outputArg, block);
1024  }
1025  }
1026  }
1027 
1028  // Signal the published output node.
1029 
1030  generateUnlockNodes(module, block, compositionStateValue, vector<VuoCompilerNode *>(1, publishedOutputNode));
1031 
1032  ReturnInst::Create(module->getContext(), block);
1033 }
1034 
1040 void VuoCompilerBitcodeGenerator::generateNodeInstanceInitFunction(void)
1041 {
1042  vector<VuoPort *> inputPorts;
1043  if (! isTopLevelComposition)
1044  inputPorts = modelInputPorts;
1045 
1046  map<VuoPort *, size_t> indexOfParameter;
1047  Function *function = VuoCompilerCodeGenUtilities::getNodeInstanceInitFunction(module, moduleKey, true,
1049  inputPorts, indexOfParameter, constantsCache);
1050  BasicBlock *block = &(function->getEntryBlock());
1051 
1052  Value *compositionStateValue = function->arg_begin();
1053 
1054  if (! isTopLevelComposition)
1055  generateSetInputDataFromNodeFunctionArguments(function, block, compositionStateValue, indexOfParameter, map<VuoPort *, size_t>(),
1056  false, false, false);
1057 
1058  for (VuoCompilerNode *node : graph->getNodes())
1059  {
1060  if (node->getBase()->getNodeClass()->getCompiler()->isStateful())
1061  {
1062  BasicBlock *initBlock = NULL;
1063  BasicBlock *nextBlock = NULL;
1064  Value *replacementJsonValue = NULL;
1066  compositionStateValue, block, initBlock, nextBlock,
1067  constantsCache, replacementJsonValue);
1068 
1069  node->generateInitFunctionCall(module, initBlock, compositionStateValue);
1070 
1071  VuoCompilerCodeGenUtilities::generateJsonObjectPut(module, initBlock, replacementJsonValue);
1072 
1073  BranchInst::Create(nextBlock, initBlock);
1074  block = nextBlock;
1075  }
1076  }
1077 
1078  PointerType *instanceDataType = static_cast<PointerType *>( function->getReturnType() );
1079  ConstantPointerNull *nullInstanceDataValue = ConstantPointerNull::get(instanceDataType);
1080  ReturnInst::Create(module->getContext(), nullInstanceDataValue, block);
1081 }
1082 
1089 void VuoCompilerBitcodeGenerator::generateNodeInstanceFiniFunction(void)
1090 {
1091  Function *function = VuoCompilerCodeGenUtilities::getNodeInstanceFiniFunction(module, moduleKey,
1093  constantsCache);
1094  BasicBlock *block = &(function->getEntryBlock());
1095 
1096  Value *compositionStateValue = function->arg_begin();
1097 
1098  for (VuoCompilerNode *node : graph->getNodes())
1099  {
1100  if (node->getBase()->getNodeClass()->getCompiler()->isStateful())
1101  {
1102  BasicBlock *finiBlock = NULL;
1103  BasicBlock *nextBlock = NULL;
1104  Value *replacementJsonValue = NULL;
1106  compositionStateValue, block, finiBlock, nextBlock,
1107  constantsCache, replacementJsonValue);
1108 
1109  node->generateFiniFunctionCall(module, finiBlock, compositionStateValue);
1110 
1111  VuoCompilerCodeGenUtilities::generateJsonObjectPut(module, finiBlock, replacementJsonValue);
1112 
1113  BranchInst::Create(nextBlock, finiBlock);
1114  block = nextBlock;
1115  }
1116  }
1117 
1118  ReturnInst::Create(module->getContext(), block);
1119 }
1120 
1128 void VuoCompilerBitcodeGenerator::generateNodeInstanceTriggerStartFunction(void)
1129 {
1130  vector<VuoPort *> inputPorts;
1131  if (! isTopLevelComposition)
1132  inputPorts = modelInputPorts;
1133 
1134  map<VuoPort *, size_t> indexOfParameter;
1135  Function *function = VuoCompilerCodeGenUtilities::getNodeInstanceTriggerStartFunction(module, moduleKey,
1137  inputPorts, indexOfParameter, constantsCache);
1138  BasicBlock *block = &(function->getEntryBlock());
1139 
1140  Value *compositionStateValue = function->arg_begin();
1141 
1142  if (! isTopLevelComposition)
1143  generateSetInputDataFromNodeFunctionArguments(function, block, compositionStateValue, indexOfParameter, map<VuoPort *, size_t>(),
1144  false, false, false);
1145 
1146  // Since a node's nodeInstanceTriggerStart() function can generate an event,
1147  // make sure trigger functions wait until all nodes' init functions have completed.
1148  generateLockNodes(module, block, compositionStateValue, orderedNodes);
1149 
1150  for (VuoCompilerNode *node : graph->getNodes())
1151  {
1152  if (node->getBase()->getNodeClass()->getCompiler()->isStateful())
1153  {
1154  // { /* call nodeInstanceTriggerStart() for node */ }
1155  node->generateCallbackStartFunctionCall(module, block, compositionStateValue);
1156  }
1157  }
1158 
1159  generateUnlockNodes(module, block, compositionStateValue, orderedNodes);
1160 
1161  ReturnInst::Create(module->getContext(), block);
1162 }
1163 
1169 void VuoCompilerBitcodeGenerator::generateNodeInstanceTriggerStopFunction(void)
1170 {
1171  Function *function = VuoCompilerCodeGenUtilities::getNodeInstanceTriggerStopFunction(module, moduleKey,
1173  constantsCache);
1174  BasicBlock *block = &(function->getEntryBlock());
1175 
1176  Value *compositionStateValue = function->arg_begin();
1177 
1178  // Stop all triggers from firing events — call nodeInstanceTriggerStop() for each stateful node.
1179  generateLockNodes(module, block, compositionStateValue, orderedNodes);
1180  for (VuoCompilerNode *node : graph->getNodes())
1181  {
1182  if (node->getBase()->getNodeClass()->getCompiler()->isStateful())
1183  node->generateCallbackStopFunctionCall(module, block, compositionStateValue);
1184  }
1185  generateUnlockNodes(module, block, compositionStateValue, orderedNodes);
1186 
1187  if (isTopLevelComposition)
1188  {
1189  // Wait for any scheduled trigger workers to launch events into the composition.
1190  Value *triggerWorkersScheduledValue = VuoCompilerCodeGenUtilities::getTriggerWorkersScheduledValue(module, block, compositionStateValue);
1191  VuoCompilerCodeGenUtilities::generateWaitForDispatchGroup(module, block, triggerWorkersScheduledValue);
1192 
1193  // Wait for any in-progress events to travel through the composition.
1194  generateLockNodes(module, block, compositionStateValue, orderedNodes);
1195  generateUnlockNodes(module, block, compositionStateValue, orderedNodes);
1196  }
1197 
1198  ReturnInst::Create(module->getContext(), block);
1199 }
1200 
1206 void VuoCompilerBitcodeGenerator::generateNodeInstanceTriggerUpdateFunction(void)
1207 {
1208  map<VuoPort *, size_t> indexOfParameter;
1209  Function *function = VuoCompilerCodeGenUtilities::getNodeInstanceTriggerUpdateFunction(module, moduleKey,
1211  modelInputPorts, indexOfParameter, constantsCache);
1212  BasicBlock *block = &(function->getEntryBlock());
1213 
1214  Value *compositionStateValue = function->arg_begin();
1215 
1217  if (! trigger)
1218  {
1219  ReturnInst::Create(module->getContext(), block);
1220  return;
1221  }
1222 
1223  vector<VuoCompilerNode *> triggerWaitNodes = getNodesToWaitOnBeforeTransmission(trigger);
1224  generateLockNodes(module, block, compositionStateValue, triggerWaitNodes);
1225 
1226  bool hasClaimedNodesDownstreamOfPublishedInputNode = (triggerWaitNodes.size() > 2);
1227  generateSetInputDataFromNodeFunctionArguments(function, block, compositionStateValue, indexOfParameter, map<VuoPort *, size_t>(),
1228  ! hasClaimedNodesDownstreamOfPublishedInputNode, true, true);
1229 
1230  generateUnlockNodes(module, block, compositionStateValue, triggerWaitNodes);
1231 
1232  ReturnInst::Create(module->getContext(), block);
1233 }
1234 
1238 void VuoCompilerBitcodeGenerator::generateLockNodes(Module *module, BasicBlock *block,
1239  Value *compositionStateValue, vector<VuoCompilerNode *> nodes,
1240  Value *eventIdValue)
1241 {
1242  if (nodes.empty())
1243  return;
1244 
1245  if (! eventIdValue)
1246  eventIdValue = VuoCompilerCodeGenUtilities::generateGetNextEventId(module, block, compositionStateValue);
1247 
1248  if (nodes.size() == 1)
1249  {
1250  size_t nodeIndex = nodes[0]->getIndexInOrderedNodes();
1251  VuoCompilerCodeGenUtilities::generateLockNode(module, block, compositionStateValue, nodeIndex, eventIdValue);
1252  }
1253  else
1254  {
1255  sortNodes(nodes);
1256 
1257  vector<size_t> nodeIndices;
1258  std::transform(nodes.begin(), nodes.end(), std::back_inserter(nodeIndices), [](VuoCompilerNode *n) { return n->getIndexInOrderedNodes(); });
1259 
1260  VuoCompilerCodeGenUtilities::generateLockNodes(module, block, compositionStateValue, nodeIndices, eventIdValue, constantsCache);
1261  }
1262 }
1263 
1267 void VuoCompilerBitcodeGenerator::generateUnlockNodes(Module *module, BasicBlock *block, Value *compositionStateValue,
1268  vector<VuoCompilerNode *> nodes)
1269 {
1270  if (nodes.empty())
1271  return;
1272 
1273  if (nodes.size() == 1)
1274  {
1275  size_t nodeIndex = nodes[0]->getIndexInOrderedNodes();
1276  VuoCompilerCodeGenUtilities::generateUnlockNode(module, block, compositionStateValue, nodeIndex);
1277  }
1278  else
1279  {
1280  vector<size_t> nodeIndices;
1281  std::transform(nodes.begin(), nodes.end(), std::back_inserter(nodeIndices), [](VuoCompilerNode *n) { return n->getIndexInOrderedNodes(); });
1282 
1283  VuoCompilerCodeGenUtilities::generateUnlockNodes(module, block, compositionStateValue, nodeIndices, constantsCache);
1284  }
1285 }
1286 
1351 void VuoCompilerBitcodeGenerator::generateCompositionGetPortValueFunction(void)
1352 {
1354 
1355  Function::arg_iterator args = function->arg_begin();
1356  Value *compositionStateValue = args++;
1357  compositionStateValue->setName("compositionState");
1358  Value *portIdentifierValue = args++;
1359  portIdentifierValue->setName("portIdentifier");
1360  Value *serializationTypeValue = args++;
1361  serializationTypeValue->setName("serializationType");
1362  Value *isThreadSafeValue = args++;
1363  isThreadSafeValue->setName("isThreadSafe");
1364 
1365 
1366  // char *ret = NULL;
1367 
1368  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, 0);
1369  PointerType *pointerToCharType = PointerType::get(IntegerType::get(module->getContext(), 8), 0);
1370 
1371  AllocaInst *retVariable = new AllocaInst(pointerToCharType, 0, "ret", initialBlock);
1372  ConstantPointerNull *nullPointerToChar = ConstantPointerNull::get(pointerToCharType);
1373  new StoreInst(nullPointerToChar, retVariable, false, initialBlock);
1374 
1375  // void *portAddress = vuoGetDataForPort(compositionState, portIdentifier);
1376 
1377  Value *portAddressAsVoidPointer = VuoCompilerCodeGenUtilities::generateGetDataForPort(module, initialBlock, compositionStateValue, portIdentifierValue);
1378 
1379  // if (portAddress != NULL)
1380 
1381  BasicBlock *checkWaitBlock = BasicBlock::Create(module->getContext(), "checkWait", function, 0);
1382  BasicBlock *finalBlock = BasicBlock::Create(module->getContext(), "final", function, 0);
1383 
1384  ConstantPointerNull *nullPortAddress = ConstantPointerNull::get(static_cast<PointerType *>(portAddressAsVoidPointer->getType()));
1385  ICmpInst *portAddressNotEqualsNull = new ICmpInst(*initialBlock, ICmpInst::ICMP_NE, portAddressAsVoidPointer, nullPortAddress, "");
1386  BranchInst::Create(checkWaitBlock, finalBlock, portAddressNotEqualsNull, initialBlock);
1387 
1388  // unsigned long typeIndex = vuoGetTypeIndexForPort(compositionState, portIdentifier);
1389  // unsigned long nodeIndex = vuoGetNodeIndexForPort(compositionState, portIdentifier);
1390 
1391  Value *typeIndexValue = VuoCompilerCodeGenUtilities::generateGetTypeIndexForPort(module, checkWaitBlock, compositionStateValue, portIdentifierValue);
1392  Value *nodeIndexValue = VuoCompilerCodeGenUtilities::generateGetNodeIndexForPort(module, checkWaitBlock, compositionStateValue, portIdentifierValue);
1393 
1394  // if (isThreadSafe)
1395  // {
1396  // unsigned long eventId = vuoGetNextEventId();
1397  // vuoLockNode(compositionState, nodeIndex, eventId);
1398  // }
1399 
1400  BasicBlock *waitBlock = BasicBlock::Create(module->getContext(), "wait", function, 0);
1401  BasicBlock *checkTypeIndexBlock = BasicBlock::Create(module->getContext(), "checkTypeIndex", function, 0);
1402  ConstantInt *falseValue = ConstantInt::get(static_cast<IntegerType *>(isThreadSafeValue->getType()), 0);
1403  ICmpInst *isThreadSafeEqualsTrue = new ICmpInst(*checkWaitBlock, ICmpInst::ICMP_NE, isThreadSafeValue, falseValue, "");
1404  BranchInst::Create(waitBlock, checkTypeIndexBlock, isThreadSafeEqualsTrue, checkWaitBlock);
1405 
1406  Value *eventIdValue = VuoCompilerCodeGenUtilities::generateGetNextEventId(module, waitBlock, compositionStateValue);
1407  VuoCompilerCodeGenUtilities::generateLockNode(module, waitBlock, compositionStateValue, nodeIndexValue, eventIdValue);
1408  BranchInst::Create(checkTypeIndexBlock, waitBlock);
1409 
1410 
1411  // if (typeIndex == 0)
1412  // {
1413  // VuoImage portValue = (VuoImage)(*portAddress);
1414  // if (serializationType == 0)
1415  // ret = VuoImage_getSummary(portValue);
1416  // else if (serializationType == 1)
1417  // ret = VuoImage_getString(portValue);
1418  // else
1419  // ret = VuoImage_getInterprocessString(portValue);
1420  // }
1421  // else if (typeIndex == 3)
1422  // {
1423  // VuoReal portValue = (VuoReal)(*portAddress);
1424  // if (serializationType == 0)
1425  // ret = VuoReal_getSummary(portValue);
1426  // else
1427  // ret = VuoReal_getString(portValue);
1428  // }
1429  // else if ...
1430 
1431  vector< pair<BasicBlock *, BasicBlock *> > blocksForIndex;
1432  for (size_t i = 0; i < orderedTypes.size(); ++i)
1433  {
1434  VuoCompilerType *type = orderedTypes[i];
1435 
1436  string typeName = type->getBase()->getModuleKey();
1437  bool hasInterprocess = type->hasInterprocessStringFunction();
1438 
1439  BasicBlock *checkSummaryBlock = BasicBlock::Create(module->getContext(), typeName + "_checkSummary", function, 0);
1440  BasicBlock *summaryBlock = BasicBlock::Create(module->getContext(), typeName + "_summary", function, 0);
1441  BasicBlock *checkStringBlock = NULL;
1442  BasicBlock *stringBlock = BasicBlock::Create(module->getContext(), typeName + "_string", function, 0);
1443  BasicBlock *interprocessBlock = NULL;
1444  BasicBlock *typeFinalBlock = BasicBlock::Create(module->getContext(), typeName + "_final", function, 0);
1445 
1446  BasicBlock *firstStringBlock = NULL;
1447  if (hasInterprocess)
1448  {
1449  checkStringBlock = BasicBlock::Create(module->getContext(), typeName + "_checkString", function, 0);
1450  interprocessBlock = BasicBlock::Create(module->getContext(), typeName + "_interprocess", function, 0);
1451  firstStringBlock = checkStringBlock;
1452  }
1453  else
1454  {
1455  firstStringBlock = stringBlock;
1456  }
1457 
1458  ConstantInt *zeroValue = ConstantInt::get(static_cast<IntegerType *>(serializationTypeValue->getType()), 0);
1459  ICmpInst *serializationTypeEqualsZero = new ICmpInst(*checkSummaryBlock, ICmpInst::ICMP_EQ, serializationTypeValue, zeroValue, "");
1460  BranchInst::Create(summaryBlock, firstStringBlock, serializationTypeEqualsZero, checkSummaryBlock);
1461 
1462  Value *summaryValue = type->generateSummaryFromValueFunctionCall(module, summaryBlock, portAddressAsVoidPointer);
1463  new StoreInst(summaryValue, retVariable, summaryBlock);
1464  BranchInst::Create(typeFinalBlock, summaryBlock);
1465 
1466  if (hasInterprocess)
1467  {
1468  ConstantInt *oneValue = ConstantInt::get(static_cast<IntegerType *>(serializationTypeValue->getType()), 1);
1469  ICmpInst *serializationTypeEqualsOne = new ICmpInst(*checkStringBlock, ICmpInst::ICMP_EQ, serializationTypeValue, oneValue, "");
1470  BranchInst::Create(stringBlock, interprocessBlock, serializationTypeEqualsOne, checkStringBlock);
1471  }
1472 
1473  Value *stringValue = type->generateStringFromValueFunctionCall(module, stringBlock, portAddressAsVoidPointer);
1474  new StoreInst(stringValue, retVariable, stringBlock);
1475  BranchInst::Create(typeFinalBlock, stringBlock);
1476 
1477  if (hasInterprocess)
1478  {
1479  Value *interprocessValue = type->generateInterprocessStringFromValueFunctionCall(module, interprocessBlock, portAddressAsVoidPointer);
1480  new StoreInst(interprocessValue, retVariable, interprocessBlock);
1481  BranchInst::Create(typeFinalBlock, interprocessBlock);
1482  }
1483 
1484  blocksForIndex.push_back( make_pair(checkSummaryBlock, typeFinalBlock) );
1485  }
1486 
1487  BasicBlock *checkSignalBlock = BasicBlock::Create(module->getContext(), "checkSignal", function, 0);
1488  VuoCompilerCodeGenUtilities::generateIndexMatchingCode(module, function, checkTypeIndexBlock, checkSignalBlock, typeIndexValue, blocksForIndex);
1489 
1490 
1491  // if (isThreadSafe)
1492  // vuoUnlockNode(compositionState, nodeIndex);
1493 
1494  BasicBlock *signalBlock = BasicBlock::Create(module->getContext(), "signal", function, 0);
1495  BranchInst::Create(signalBlock, finalBlock, isThreadSafeEqualsTrue, checkSignalBlock);
1496 
1497  VuoCompilerCodeGenUtilities::generateUnlockNode(module, signalBlock, compositionStateValue, nodeIndexValue);
1498  BranchInst::Create(finalBlock, signalBlock);
1499 
1500 
1501  // return ret;
1502 
1503  LoadInst *retValue = new LoadInst(retVariable, "", false, finalBlock);
1504  ReturnInst::Create(module->getContext(), retValue, finalBlock);
1505 }
1506 
1585 void VuoCompilerBitcodeGenerator::generateCompositionSetPortValueFunction(void)
1586 {
1588 
1589  Function::arg_iterator args = function->arg_begin();
1590  Value *compositionStateValue = args++;
1591  compositionStateValue->setName("compositionState");
1592  Value *portIdentifierValue = args++;
1593  portIdentifierValue->setName("portIdentifier");
1594  Value *valueAsStringValue = args++;
1595  valueAsStringValue->setName("valueAsString");
1596  Value *isThreadSafeValue = args++;
1597  isThreadSafeValue->setName("isThreadSafe");
1598  Value *shouldUpdateTriggersValue = args++;
1599  shouldUpdateTriggersValue->setName("shouldUpdateTriggers");
1600  Value *shouldSendTelemetryValue = args++;
1601  shouldSendTelemetryValue->setName("shouldSendTelemetry");
1602  Value *hasOldValue = args++;
1603  hasOldValue->setName("hasOldValue");
1604  Value *hasNewValue = args++;
1605  hasNewValue->setName("hasNewValue");
1606 
1607 
1608  // void *portAddress = vuoGetDataForPort(compositionState, portIdentifier);
1609 
1610  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, 0);
1611  Value *portAddressAsVoidPointer = VuoCompilerCodeGenUtilities::generateGetDataForPort(module, initialBlock, compositionStateValue, portIdentifierValue);
1612 
1613  // if (portAddress != NULL)
1614 
1615  BasicBlock *checkWaitBlock = BasicBlock::Create(module->getContext(), "checkWait", function, 0);
1616  BasicBlock *finalBlock = BasicBlock::Create(module->getContext(), "final", function, 0);
1617 
1618  ConstantPointerNull *nullPortAddress = ConstantPointerNull::get(static_cast<PointerType *>(portAddressAsVoidPointer->getType()));
1619  ICmpInst *portAddressNotEqualsNull = new ICmpInst(*initialBlock, ICmpInst::ICMP_NE, portAddressAsVoidPointer, nullPortAddress, "");
1620  BranchInst::Create(checkWaitBlock, finalBlock, portAddressNotEqualsNull, initialBlock);
1621 
1622  // dispatch_semaphore_t nodeSemaphore = vuoGetNodeSemaphoreForPort(compositionState, portIdentifier);
1623  // unsigned long typeIndex = vuoGetTypeIndexForPort(compositionState, portIdentifier);
1624  // unsigned long nodeIndex = vuoGetNodeIndexForPort(compositionState, portIdentifier);
1625  // char *summary = NULL;
1626 
1627  Value *typeIndexValue = VuoCompilerCodeGenUtilities::generateGetTypeIndexForPort(module, checkWaitBlock, compositionStateValue, portIdentifierValue);
1628  Value *nodeIndexValue = VuoCompilerCodeGenUtilities::generateGetNodeIndexForPort(module, checkWaitBlock, compositionStateValue, portIdentifierValue);
1629 
1630  PointerType *pointerToCharType = PointerType::get(IntegerType::get(module->getContext(), 8), 0);
1631  AllocaInst *summaryVariable = new AllocaInst(pointerToCharType, 0, "summary", checkWaitBlock);
1632  ConstantPointerNull *nullSummary = ConstantPointerNull::get(pointerToCharType);
1633  new StoreInst(nullSummary, summaryVariable, false, checkWaitBlock);
1634 
1635  // if (isThreadSafe)
1636  // {
1637  // unsigned long eventId = vuoGetNextEventId();
1638  // vuoLockNode(compositionState, nodeIndex, eventId);
1639  // }
1640 
1641  BasicBlock *waitBlock = BasicBlock::Create(module->getContext(), "wait", function, 0);
1642  BasicBlock *checkTypeIndexBlock = BasicBlock::Create(module->getContext(), "checkTypeIndex", function, 0);
1643  ConstantInt *falseArgValue = ConstantInt::get(static_cast<IntegerType *>(isThreadSafeValue->getType()), 0);
1644  ICmpInst *isThreadSafeEqualsTrue = new ICmpInst(*checkWaitBlock, ICmpInst::ICMP_NE, isThreadSafeValue, falseArgValue, "");
1645  BranchInst::Create(waitBlock, checkTypeIndexBlock, isThreadSafeEqualsTrue, checkWaitBlock);
1646 
1647  Value *eventIdValue = VuoCompilerCodeGenUtilities::generateGetNextEventId(module, waitBlock, compositionStateValue);
1648  VuoCompilerCodeGenUtilities::generateLockNode(module, waitBlock, compositionStateValue, nodeIndexValue, eventIdValue);
1649  BranchInst::Create(checkTypeIndexBlock, waitBlock);
1650 
1651 
1652  // if (typeIndex == 0)
1653  // {
1654  // VuoText newPortValue;
1655  // if (hasNewValue)
1656  // {
1657  // newPortValue = VuoText_makeFromString(valueAsString);
1658  // VuoRetain(newPortValue);
1659  // }
1660  // if (hasOldValue)
1661  // VuoRelease(*(portContext->data));
1662  // if (hasNewValue)
1663  // {
1664  // memcpy(portContext->data, &newPortValue, sizeof(VuoText));
1665  // if (shouldSendTelemetry)
1666  // summary = VuoText_getSummary(newPortValue);
1667  // }
1668  // }
1669  // else if (typeIndex == 1)
1670  // {
1671  // if (hasNewValue)
1672  // {
1673  // VuoReal newPortValue = VuoReal_makeFromString(valueAsString);
1674  // memcpy(portContext->data, &newPortValue, sizeof(VuoReal));
1675  // if (shouldSendTelemetry)
1676  // summary = VuoReal_getSummary(newPortValue);
1677  // }
1678  // }
1679  // else if ...
1680 
1681  ICmpInst *hasOldValueIsTrue = new ICmpInst(*checkTypeIndexBlock, ICmpInst::ICMP_NE, hasOldValue, falseArgValue, "");
1682  ICmpInst *hasNewValueIsTrue = new ICmpInst(*checkTypeIndexBlock, ICmpInst::ICMP_NE, hasNewValue, falseArgValue, "");
1683  ICmpInst *shouldSendTelemetryIsTrue = new ICmpInst(*checkTypeIndexBlock, ICmpInst::ICMP_NE, shouldSendTelemetryValue, falseArgValue, "");
1684 
1685  vector< pair<BasicBlock *, BasicBlock *> > blocksForTypeIndex;
1686  for (size_t i = 0; i < orderedTypes.size(); ++i)
1687  {
1688  VuoCompilerType *type = orderedTypes[i];
1689 
1690  BasicBlock *typeInitialBlock = BasicBlock::Create(module->getContext(), type->getBase()->getModuleKey() + "_initial", function, 0);
1691  BasicBlock *makeNewValueBlock = BasicBlock::Create(module->getContext(), "makeNewValue", function, 0);
1692  BasicBlock *checkOldValueBlock = BasicBlock::Create(module->getContext(), "checkOldValue", function, 0);
1693  BasicBlock *releaseOldValueBlock = BasicBlock::Create(module->getContext(), "releaseOldValue", function, 0);
1694  BasicBlock *checkNewValueBlock = BasicBlock::Create(module->getContext(), "checkNewValue", function, 0);
1695  BasicBlock *setNewValueBlock = BasicBlock::Create(module->getContext(), "setNewValue", function, 0);
1696  BasicBlock *summaryBlock = BasicBlock::Create(module->getContext(), "summary", function, 0);
1697  BasicBlock *typeFinalBlock = BasicBlock::Create(module->getContext(), type->getBase()->getModuleKey() + "_final", function, 0);
1698 
1699  Value *portAddress = type->convertToPortData(typeInitialBlock, portAddressAsVoidPointer);
1700  AllocaInst *newPortValueAddress = new AllocaInst(cast<PointerType>(portAddress->getType())->getElementType(), 0, "newPortValueAddress", typeInitialBlock);
1701 
1702  BranchInst::Create(makeNewValueBlock, checkOldValueBlock, hasNewValueIsTrue, typeInitialBlock);
1703 
1704  Value *newPortValueAddressLocal = type->generateValueFromStringFunctionCall(module, makeNewValueBlock, valueAsStringValue);
1705  VuoCompilerCodeGenUtilities::generateMemoryCopy(module, makeNewValueBlock, newPortValueAddressLocal, newPortValueAddress, type->getSize(module));
1706  type->generateRetainCall(module, makeNewValueBlock, newPortValueAddress);
1707  BranchInst::Create(checkOldValueBlock, makeNewValueBlock);
1708 
1709  BranchInst::Create(releaseOldValueBlock, checkNewValueBlock, hasOldValueIsTrue, checkOldValueBlock);
1710 
1711  type->generateReleaseCall(module, releaseOldValueBlock, portAddress);
1712  BranchInst::Create(checkNewValueBlock, releaseOldValueBlock);
1713 
1714  BranchInst::Create(setNewValueBlock, typeFinalBlock, hasNewValueIsTrue, checkNewValueBlock);
1715 
1716  VuoCompilerCodeGenUtilities::generateMemoryCopy(module, setNewValueBlock, newPortValueAddress, portAddress, type->getSize(module));
1717  BranchInst::Create(summaryBlock, typeFinalBlock, shouldSendTelemetryIsTrue, setNewValueBlock);
1718 
1719  Value *summaryValue = type->generateSummaryFromValueFunctionCall(module, summaryBlock, portAddress);
1720  new StoreInst(summaryValue, summaryVariable, false, summaryBlock);
1721  BranchInst::Create(typeFinalBlock, summaryBlock);
1722 
1723  blocksForTypeIndex.push_back( make_pair(typeInitialBlock, typeFinalBlock) );
1724  }
1725 
1726  BasicBlock *checkUpdateBlock = BasicBlock::Create(module->getContext(), "checkUpdate", function, 0);
1727  VuoCompilerCodeGenUtilities::generateIndexMatchingCode(module, function, checkTypeIndexBlock, checkUpdateBlock, typeIndexValue, blocksForTypeIndex);
1728 
1729 
1730  // if (shouldUpdateTriggers)
1731  // {
1732  // if (nodeIndex == 0)
1733  // {
1734  // Top__FirePeriodically2__fired(...);
1735  // }
1736  // else if ...
1737  // }
1738 
1739  Constant *zeroValue = ConstantInt::get(shouldUpdateTriggersValue->getType(), 0);
1740  ICmpInst *shouldUpdateTriggersIsTrue = new ICmpInst(*checkUpdateBlock, ICmpInst::ICMP_NE, shouldUpdateTriggersValue, zeroValue, "");
1741  BasicBlock *updateTriggersBlock = BasicBlock::Create(module->getContext(), "updateTriggers", function, 0);
1742  BasicBlock *checkSendBlock = BasicBlock::Create(module->getContext(), "checkSend", function, 0);
1743  BranchInst::Create(updateTriggersBlock, checkSendBlock, shouldUpdateTriggersIsTrue, checkUpdateBlock);
1744 
1745  vector< pair<BasicBlock *, BasicBlock *> > blocksForNodeIndex;
1746  for (size_t i = 0; i < orderedNodes.size(); ++i)
1747  {
1748  VuoCompilerNode *node = orderedNodes[i];
1749  BasicBlock *currentBlock = BasicBlock::Create(module->getContext(), node->getIdentifier(), function, 0);
1750  BasicBlock *origCurrentBlock = currentBlock;
1751 
1752  node->generateCallbackUpdateFunctionCall(module, currentBlock, compositionStateValue);
1753 
1754  generateDataOnlyTransmissionFromNode(function, currentBlock, compositionStateValue, node, true, true, true);
1755 
1756  blocksForNodeIndex.push_back( make_pair(origCurrentBlock, currentBlock) );
1757  }
1758 
1759  BasicBlock *checkSignalBlock = BasicBlock::Create(module->getContext(), "checkSignal", function, 0);
1760  VuoCompilerCodeGenUtilities::generateIndexMatchingCode(module, function, updateTriggersBlock, checkSignalBlock, nodeIndexValue, blocksForNodeIndex);
1761 
1762 
1763  // if (isThreadSafe)
1764  // vuoUnlockNode(compositionState, nodeIndex);
1765 
1766  BasicBlock *signalBlock = BasicBlock::Create(module->getContext(), "signal", function, 0);
1767  BranchInst::Create(signalBlock, checkSendBlock, isThreadSafeEqualsTrue, checkSignalBlock);
1768 
1769  VuoCompilerCodeGenUtilities::generateUnlockNode(module, signalBlock, compositionStateValue, nodeIndexValue);
1770  BranchInst::Create(checkSendBlock, signalBlock);
1771 
1772 
1773  // if (shouldSendTelemetry)
1774  // {
1775  // sendInputPortsUpdated(portIdentifier, false, true, summary);
1776  // free(summary);
1777  // }
1778 
1779  BasicBlock *sendBlock = BasicBlock::Create(module->getContext(), "send", function, 0);
1780  BranchInst::Create(sendBlock, finalBlock, shouldSendTelemetryIsTrue, checkSendBlock);
1781 
1782  Value *summaryValue = new LoadInst(summaryVariable, "", false, sendBlock);
1783 
1784  VuoCompilerCodeGenUtilities::generateSendInputPortsUpdated(module, sendBlock, compositionStateValue, portIdentifierValue,
1785  false, true, summaryValue);
1786 
1787  VuoCompilerCodeGenUtilities::generateFreeCall(module, sendBlock, summaryValue);
1788  BranchInst::Create(finalBlock, sendBlock);
1789 
1790  ReturnInst::Create(module->getContext(), finalBlock);
1791 }
1792 
1798 void VuoCompilerBitcodeGenerator::generateSetInputPortValueFunction(void)
1799 {
1800  Function *function = VuoCompilerCodeGenUtilities::getSetInputPortValueFunction(module);
1801  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
1802 
1803  Function::arg_iterator args = function->arg_begin();
1804  Value *portIdentifierValue = args++;
1805  portIdentifierValue->setName("portIdentifier");
1806  Value *valueAsStringValue = args++;
1807  valueAsStringValue->setName("valueAsString");
1808 
1809  Function *compositionSetPortValueFunction = VuoCompilerCodeGenUtilities::getCompositionSetPortValueFunction(module);
1810 
1811  Value *topLevelRuntimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, block);
1812  Value *topLevelCompositionIdentifierValue = constantsCache->get(VuoCompilerComposition::topLevelCompositionIdentifier);
1813  Value *compositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, topLevelRuntimeStateValue, topLevelCompositionIdentifierValue);
1814 
1815  Value *trueValue = ConstantInt::get(compositionSetPortValueFunction->getFunctionType()->getParamType(3), 1);
1816 
1817  vector<Value *> compositionArgs;
1818  compositionArgs.push_back(compositionStateValue);
1819  compositionArgs.push_back(portIdentifierValue);
1820  compositionArgs.push_back(valueAsStringValue);
1821  compositionArgs.push_back(trueValue);
1822  compositionArgs.push_back(trueValue);
1823  compositionArgs.push_back(trueValue);
1824  compositionArgs.push_back(trueValue);
1825  compositionArgs.push_back(trueValue);
1826  CallInst::Create(compositionSetPortValueFunction, compositionArgs, "", block);
1827 
1828  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, compositionStateValue);
1829 
1830  ReturnInst::Create(module->getContext(), block);
1831 }
1832 
1852 void VuoCompilerBitcodeGenerator::generateCompositionFireTriggerPortEventFunction(void)
1853 {
1855 
1856  Function::arg_iterator args = function->arg_begin();
1857  Value *compositionStateValue = args++;
1858  compositionStateValue->setName("compositionState");
1859  Value *portIdentifierValue = args++;
1860  portIdentifierValue->setName("portIdentifier");
1861 
1862  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, 0);
1863 
1864  map<string, pair<BasicBlock *, BasicBlock *> > blocksForString;
1865  for (VuoCompilerTriggerPort *trigger : graph->getTriggerPorts())
1866  {
1867  VuoCompilerNode *triggerNode = graph->getNodeForTriggerPort(trigger);
1868 
1869  string currentPortIdentifier = trigger->getIdentifier();
1870 
1871  BasicBlock *currentBlock = BasicBlock::Create(module->getContext(), currentPortIdentifier, function, 0);
1872  BasicBlock *origCurrentBlock = currentBlock;
1873 
1874  Value *nodeContextValue = triggerNode->generateGetContext(module, currentBlock, compositionStateValue);
1875  Value *triggerFunctionValue = trigger->generateLoadFunction(module, currentBlock, nodeContextValue);
1876 
1877  vector<Value *> triggerArgs;
1878  VuoType *dataType = trigger->getDataVuoType();
1879  if (dataType)
1880  {
1881  generateLockNodes(module, currentBlock, compositionStateValue, vector<VuoCompilerNode *>(1, triggerNode));
1882 
1883  FunctionType *triggerFunctionType = trigger->getClass()->getFunctionType(module);
1884 
1885  Value *dataPointer = trigger->generateRetrievePreviousData(module, currentBlock, nodeContextValue);
1886  triggerArgs = dataType->getCompiler()->convertPortDataToArgs(module, currentBlock, dataPointer, triggerFunctionType, 0, false);
1887  }
1888 
1889  CallInst *call = CallInst::Create(triggerFunctionValue, triggerArgs, "", currentBlock);
1890 
1891  if (dataType)
1892  {
1893  dataType->getCompiler()->copyFunctionParameterAttributes(module, call);
1894 
1895  generateUnlockNodes(module, currentBlock, compositionStateValue, vector<VuoCompilerNode *>(1, triggerNode));
1896  }
1897 
1898  blocksForString[currentPortIdentifier] = make_pair(origCurrentBlock, currentBlock);
1899  }
1900 
1901  BasicBlock *finalBlock = BasicBlock::Create(module->getContext(), "final", function, 0);
1902 
1903  ReturnInst::Create(module->getContext(), finalBlock);
1904 
1905  VuoCompilerCodeGenUtilities::generateStringMatchingCode(module, function, initialBlock, finalBlock, portIdentifierValue, blocksForString, constantsCache);
1906 }
1907 
1923 void VuoCompilerBitcodeGenerator::generateGetPublishedPortCountFunction(bool input)
1924 {
1925  size_t count;
1926  string functionName;
1927  if (input)
1928  {
1929  count = composition->getBase()->getPublishedInputPorts().size();
1930  functionName = "getPublishedInputPortCount";
1931  }
1932  else
1933  {
1934  count = composition->getBase()->getPublishedOutputPorts().size();
1935  functionName = "getPublishedOutputPortCount";
1936  }
1937 
1938  Function *function = module->getFunction(functionName);
1939  if (! function)
1940  {
1941  vector<Type *> functionParams;
1942  FunctionType *functionType = FunctionType::get(IntegerType::get(module->getContext(), 32), functionParams, false);
1943  function = Function::Create(functionType, GlobalValue::ExternalLinkage, functionName, module);
1944  }
1945 
1946  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, 0);
1947  ConstantInt *countConstant = ConstantInt::get(module->getContext(), APInt(32, count));
1948  ReturnInst::Create(module->getContext(), countConstant, block);
1949 }
1950 
1966 void VuoCompilerBitcodeGenerator::generateGetPublishedPortNamesFunction(bool input)
1967 {
1968  string functionName;
1969  vector<VuoPublishedPort *> publishedPorts;
1970  if (input)
1971  {
1972  functionName = "getPublishedInputPortNames";
1973  publishedPorts = composition->getBase()->getPublishedInputPorts();
1974  }
1975  else
1976  {
1977  functionName = "getPublishedOutputPortNames";
1978  publishedPorts = composition->getBase()->getPublishedOutputPorts();
1979  }
1980 
1981  vector<string> names;
1982  for (vector<VuoPublishedPort *>::iterator i = publishedPorts.begin(); i != publishedPorts.end(); ++i)
1983  {
1984  names.push_back( (*i)->getClass()->getName() );
1985  }
1986 
1987  generateFunctionReturningStringArray(functionName, names);
1988 }
1989 
2005 void VuoCompilerBitcodeGenerator::generateGetPublishedPortTypesFunction(bool input)
2006 {
2007  string functionName;
2008  vector<VuoPublishedPort *> publishedPorts;
2009  if (input)
2010  {
2011  functionName = "getPublishedInputPortTypes";
2012  publishedPorts = composition->getBase()->getPublishedInputPorts();
2013  }
2014  else
2015  {
2016  functionName = "getPublishedOutputPortTypes";
2017  publishedPorts = composition->getBase()->getPublishedOutputPorts();
2018  }
2019 
2020  vector<string> types;
2021  for (vector<VuoPublishedPort *>::iterator i = publishedPorts.begin(); i != publishedPorts.end(); ++i)
2022  {
2023  VuoCompilerPublishedPort *publishedPort = static_cast<VuoCompilerPublishedPort *>((*i)->getCompiler());
2024 
2025  VuoType *type = publishedPort->getDataVuoType();
2026  string typeName = type ? type->getModuleKey() : "";
2027  types.push_back(typeName);
2028  }
2029 
2030  generateFunctionReturningStringArray(functionName, types);
2031 }
2032 
2048 void VuoCompilerBitcodeGenerator::generateGetPublishedPortDetailsFunction(bool input)
2049 {
2050  string functionName;
2051  vector<VuoPublishedPort *> publishedPorts;
2052  if (input)
2053  {
2054  functionName = "getPublishedInputPortDetails";
2055  publishedPorts = composition->getBase()->getPublishedInputPorts();
2056  }
2057  else
2058  {
2059  functionName = "getPublishedOutputPortDetails";
2060  publishedPorts = composition->getBase()->getPublishedOutputPorts();
2061  }
2062 
2063  vector<string> details;
2064  for (vector<VuoPublishedPort *>::iterator i = publishedPorts.begin(); i != publishedPorts.end(); ++i)
2065  {
2066  VuoCompilerPublishedPort *publishedPort = static_cast<VuoCompilerPublishedPort *>((*i)->getCompiler());
2067 
2068  json_object *detailsObj = publishedPort->getDetails(input);
2069  string detailsSerialized = json_object_to_json_string_ext(detailsObj, JSON_C_TO_STRING_PLAIN);
2070  details.push_back(detailsSerialized);
2071 
2072  json_object_put(detailsObj);
2073  }
2074 
2075  generateFunctionReturningStringArray(functionName, details);
2076 }
2077 
2084 void VuoCompilerBitcodeGenerator::generateFunctionReturningStringArray(string functionName, vector<string> stringValues)
2085 {
2086  Function *function = module->getFunction(functionName);
2087  if (! function)
2088  {
2089  PointerType *pointerToChar = PointerType::get(IntegerType::get(module->getContext(), 8), 0);
2090  PointerType *pointerToPointerToChar = PointerType::get(pointerToChar, 0);
2091  vector<Type *> functionParams;
2092  FunctionType *functionType = FunctionType::get(pointerToPointerToChar, functionParams, false);
2093  function = Function::Create(functionType, GlobalValue::ExternalLinkage, functionName, module);
2094  }
2095 
2096  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, 0);
2097 
2098  Constant *stringArrayGlobalPointer = VuoCompilerCodeGenUtilities::generatePointerToConstantArrayOfStrings(module, stringValues);
2099  ReturnInst::Create(module->getContext(), stringArrayGlobalPointer, block);
2100 }
2101 
2111 void VuoCompilerBitcodeGenerator::generateFirePublishedInputPortEventFunction(void)
2112 {
2113  string functionName = "firePublishedInputPortEvent";
2114  Function *function = module->getFunction(functionName);
2115  PointerType *pointerToChar = PointerType::get(IntegerType::get(module->getContext(), 8), 0);
2116  if (! function)
2117  {
2118  PointerType *pointerToPointerToChar = PointerType::get(pointerToChar, 0);
2119  Type *countType = IntegerType::get(module->getContext(), 32);
2120 
2121  vector<Type *> functionParams;
2122  functionParams.push_back(pointerToPointerToChar);
2123  functionParams.push_back(countType);
2124  FunctionType *functionType = FunctionType::get(Type::getVoidTy(module->getContext()), functionParams, false);
2125  function = Function::Create(functionType, GlobalValue::ExternalLinkage, functionName, module);
2126  }
2127 
2128  Function::arg_iterator args = function->arg_begin();
2129  Value *namesValue = args++;
2130  namesValue->setName("names");
2131  Value *countValue = args++;
2132  countValue->setName("count");
2133 
2134  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, 0);
2135 
2137  if (! trigger)
2138  {
2139  ReturnInst::Create(module->getContext(), initialBlock);
2140  return;
2141  }
2142 
2143  VuoCompilerNode *triggerNode = graph->getNodeForTriggerPort(trigger);
2144 
2145  Value *runtimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, initialBlock);
2146  Value *compositionIdentifierValue = constantsCache->get(VuoCompilerComposition::topLevelCompositionIdentifier);
2147  Value *compositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, initialBlock, runtimeStateValue,
2148  compositionIdentifierValue);
2149 
2150  // Create an event ID so the nodes claimed by this function can be used (re-claimed) by the trigger worker.
2151 
2152  Value *eventIdValue = VuoCompilerCodeGenUtilities::generateGetNextEventId(module, initialBlock, compositionStateValue);
2153 
2154  // Claim all necessary downstream nodes —
2155  // including the published output node to synchronize access to the composition's node context when tracking events started/finished.
2156 
2157  vector<VuoCompilerNode *> triggerWaitNodes = getNodesToWaitOnBeforeTransmission(trigger);
2158 
2159  VuoCompilerNode *publishedOutputNode = graph->getPublishedOutputNode();
2160  if (find(triggerWaitNodes.begin(), triggerWaitNodes.end(), publishedOutputNode) == triggerWaitNodes.end())
2161  triggerWaitNodes.push_back(publishedOutputNode);
2162 
2163  generateLockNodes(module, initialBlock, compositionStateValue, triggerWaitNodes, eventIdValue);
2164 
2165  // Start tracking the event so we can later notify the runner when the event is finished.
2166 
2167  Value *compositionContextValue = VuoCompilerCodeGenUtilities::generateGetCompositionContext(module, initialBlock, compositionStateValue);
2168  VuoCompilerCodeGenUtilities::generateStartedExecutingEvent(module, initialBlock, compositionContextValue, eventIdValue);
2169 
2170  // Mark the selected input ports on the published input node as hit by an event.
2171  //
2172  // int i = 0;
2173  // while (i < count)
2174  // {
2175  // if (! strcmp(names[i], "firstPort"))
2176  // {
2177  // ...
2178  // }
2179  // else if (! strcmp(names[i], "secondPort"))
2180  // {
2181  // ...
2182  // }
2183  // i = i + 1;
2184  // }
2185  //
2186 
2187  VuoCompilerNode *publishedInputNode = graph->getPublishedInputNode();
2188  Value *publishedInputNodeContextValue = publishedInputNode->generateGetContext(module, initialBlock, compositionStateValue);
2189 
2190  Value *zeroValue = ConstantInt::get(static_cast<IntegerType *>(countValue->getType()), 0);
2191  AllocaInst *iterVariable = new AllocaInst(countValue->getType(), 0, "i", initialBlock);
2192  new StoreInst(zeroValue, iterVariable, false, initialBlock);
2193 
2194  BasicBlock *loopConditionBlock = BasicBlock::Create(module->getContext(), "loopCondition", function, 0);
2195  BasicBlock *loopBeginBlock = BasicBlock::Create(module->getContext(), "loopBegin", function, 0);
2196  BasicBlock *loopEndBlock = BasicBlock::Create(module->getContext(), "loopEnd", function, 0);
2197  BasicBlock *fireBlock = BasicBlock::Create(module->getContext(), "fire", function, 0);
2198 
2199  BranchInst::Create(loopConditionBlock, initialBlock);
2200 
2201  Value *iterValue = new LoadInst(iterVariable, "", false, loopConditionBlock);
2202  ICmpInst *iterLessThanCount = new ICmpInst(*loopConditionBlock, ICmpInst::ICMP_ULT, iterValue, countValue, "");
2203  BranchInst::Create(loopBeginBlock, fireBlock, iterLessThanCount, loopConditionBlock);
2204 
2205  Value *iterNameValue = VuoCompilerCodeGenUtilities::generateGetArrayElement(module, loopBeginBlock, namesValue, iterValue);
2206 
2207  map<string, pair<BasicBlock *, BasicBlock *> > blocksForString;
2208 
2209  vector<VuoPublishedPort *> publishedInputPorts = composition->getBase()->getPublishedInputPorts();
2210  for (size_t i = 0; i < publishedInputPorts.size(); ++i)
2211  {
2212  string currentName = publishedInputPorts[i]->getClass()->getName();
2213  BasicBlock *currentBlock = BasicBlock::Create(module->getContext(), currentName, function, 0);
2214 
2215  VuoPort *port = graph->getInputPortOnPublishedInputNode(i);
2216  VuoCompilerInputEventPort *inputEventPort = static_cast<VuoCompilerInputEventPort *>(port->getCompiler());
2217  inputEventPort->generateStoreEvent(module, currentBlock, publishedInputNodeContextValue, true);
2218 
2219  blocksForString[currentName] = make_pair(currentBlock, currentBlock);
2220  }
2221 
2222  VuoCompilerCodeGenUtilities::generateStringMatchingCode(module, function, loopBeginBlock, loopEndBlock, iterNameValue, blocksForString, constantsCache);
2223 
2224  Value *oneValue = ConstantInt::get(static_cast<IntegerType *>(countValue->getType()), 1);
2225  Value *iterPlusOneValue = BinaryOperator::Create(Instruction::Add, iterValue, oneValue, "", loopEndBlock);
2226  new StoreInst(iterPlusOneValue, iterVariable, false, loopEndBlock);
2227 
2228  BranchInst::Create(loopConditionBlock, loopEndBlock);
2229 
2230  // Fire an event from the published input trigger.
2231 
2232  Value *triggerNodeContextValue = triggerNode->generateGetContext(module, fireBlock, compositionStateValue);
2233  Value *triggerFunctionValue = trigger->generateLoadFunction(module, fireBlock, triggerNodeContextValue);
2234  CallInst::Create(triggerFunctionValue, "", fireBlock);
2235 
2236  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, fireBlock, compositionStateValue);
2237 
2238  ReturnInst::Create(module->getContext(), fireBlock);
2239 }
2240 
2280 void VuoCompilerBitcodeGenerator::generateGetPublishedPortValueFunction(bool input)
2281 {
2282  Function *function = (input ?
2284  VuoCompilerCodeGenUtilities::getGetPublishedOutputPortValueFunction(module));
2285 
2286  Function::arg_iterator args = function->arg_begin();
2287  Value *portIdentifierValue = args++;
2288  portIdentifierValue->setName("portIdentifier");
2289  Value *shouldUseInterprocessSerializationValue = args++;
2290  shouldUseInterprocessSerializationValue->setName("shouldUseInterprocessSerialization");
2291 
2292  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, 0);
2293  PointerType *pointerToChar = PointerType::get(IntegerType::get(module->getContext(), 8), 0);
2294  AllocaInst *retVariable = new AllocaInst(pointerToChar, 0, "ret", initialBlock);
2295  ConstantPointerNull *nullValue = ConstantPointerNull::get(pointerToChar);
2296  new StoreInst(nullValue, retVariable, false, initialBlock);
2297 
2298  Value *runtimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, initialBlock);
2299  Value *compositionIdentifierValue = constantsCache->get(VuoCompilerComposition::topLevelCompositionIdentifier);
2300  Value *compositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, initialBlock, runtimeStateValue,
2301  compositionIdentifierValue);
2302 
2303  vector<VuoPort *> inputPortsOnPublishedNode;
2304  if (input)
2305  {
2306  vector<VuoPublishedPort *> publishedPorts = composition->getBase()->getPublishedInputPorts();
2307  for (size_t i = 0; i < publishedPorts.size(); ++i)
2308  {
2309  VuoPort *port = graph->getInputPortOnPublishedInputNode(i);
2310  inputPortsOnPublishedNode.push_back(port);
2311  }
2312  }
2313  else
2314  {
2315  vector<VuoPublishedPort *> publishedPorts = composition->getBase()->getPublishedOutputPorts();
2316  for (size_t i = 0; i < publishedPorts.size(); ++i)
2317  {
2318  VuoPort *port = graph->getInputPortOnPublishedOutputNode(i);
2319  inputPortsOnPublishedNode.push_back(port);
2320  }
2321  }
2322 
2323  map<string, pair<BasicBlock *, BasicBlock *> > blocksForString;
2324  for (VuoPort *port : inputPortsOnPublishedNode)
2325  {
2326  string currentName = port->getClass()->getName();
2327  BasicBlock *currentBlock = BasicBlock::Create(module->getContext(), currentName, function, 0);
2328 
2329  string currentIdentifier = static_cast<VuoCompilerEventPort *>(port->getCompiler())->getIdentifier();
2330  Constant *currentIdentifierValue = constantsCache->get(currentIdentifier);
2331 
2332  Value *retValue = VuoCompilerCodeGenUtilities::generateGetInputPortString(module, currentBlock, compositionStateValue,
2333  currentIdentifierValue, shouldUseInterprocessSerializationValue);
2334  new StoreInst(retValue, retVariable, currentBlock);
2335 
2336  blocksForString[currentName] = make_pair(currentBlock, currentBlock);
2337  }
2338 
2339  BasicBlock *finalBlock = BasicBlock::Create(module->getContext(), "final", function, 0);
2340 
2341  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, finalBlock, compositionStateValue);
2342 
2343  LoadInst *retValue = new LoadInst(retVariable, "", false, finalBlock);
2344  ReturnInst::Create(module->getContext(), retValue, finalBlock);
2345 
2346  VuoCompilerCodeGenUtilities::generateStringMatchingCode(module, function, initialBlock, finalBlock, portIdentifierValue, blocksForString, constantsCache);
2347 }
2348 
2360 void VuoCompilerBitcodeGenerator::generateCompositionSetPublishedInputPortValueFunction(void)
2361 {
2363 
2364  Function::arg_iterator args = function->arg_begin();
2365  Value *compositionStateValue = args++;
2366  compositionStateValue->setName("compositionState");
2367  Value *publishedInputPortNameValue = args++;
2368  publishedInputPortNameValue->setName("publishedInputPortName");
2369  Value *valueAsStringValue = args++;
2370  valueAsStringValue->setName("valueAsString");
2371  Value *isCompositionRunningValue = args++;
2372  isCompositionRunningValue->setName("isCompositionRunning");
2373 
2374  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, 0);
2375 
2377  if (! trigger)
2378  {
2379  ReturnInst::Create(module->getContext(), initialBlock);
2380  return;
2381  }
2382 
2383  // const char *inputPortIdentifier = NULL;
2384 
2385  PointerType *pointerToCharType = PointerType::get(IntegerType::get(module->getContext(), 8), 0);
2386  AllocaInst *inputPortIdentifierVariable = new AllocaInst(pointerToCharType, 0, "inputPortIdentifier", initialBlock);
2387  ConstantPointerNull *nullInputPortIdentifier = ConstantPointerNull::get(pointerToCharType);
2388  new StoreInst(nullInputPortIdentifier, inputPortIdentifierVariable, false, initialBlock);
2389 
2390  // if (! strcmp(publishedInputPortName, "firstName"))
2391  // inputPortIdentifier = "PublishedInputs__firstName";
2392  // else if (! strcmp(publishedInputPortName, "secondName"))
2393  // inputPortIdentifier = "PublishedInputs__secondName";
2394  // ...
2395 
2396  map<string, pair<BasicBlock *, BasicBlock *> > blocksForString;
2397  vector<VuoPublishedPort *> publishedInputPorts = composition->getBase()->getPublishedInputPorts();
2398  for (size_t i = 0; i < publishedInputPorts.size(); ++i)
2399  {
2400  string currPublishedInputPortName = publishedInputPorts[i]->getClass()->getName();
2401  BasicBlock *currBlock = BasicBlock::Create(module->getContext(), currPublishedInputPortName, function, 0);
2402 
2403  VuoPort *inputPort = graph->getInputPortOnPublishedInputNode(i);
2404  string inputPortIdentifier = static_cast<VuoCompilerPort *>(inputPort->getCompiler())->getIdentifier();
2405  Value *inputPortIdentifierValue = constantsCache->get(inputPortIdentifier);
2406 
2407  new StoreInst(inputPortIdentifierValue, inputPortIdentifierVariable, false, currBlock);
2408 
2409  blocksForString[currPublishedInputPortName] = make_pair(currBlock, currBlock);
2410  }
2411 
2412  BasicBlock *checkBlock = BasicBlock::Create(module->getContext(), "check", function, 0);
2413  BasicBlock *scheduleBlock = BasicBlock::Create(module->getContext(), "schedule", function, 0);
2414  BasicBlock *finalBlock = BasicBlock::Create(module->getContext(), "final", function, 0);
2415 
2416  VuoCompilerCodeGenUtilities::generateStringMatchingCode(module, function, initialBlock, checkBlock, publishedInputPortNameValue, blocksForString, constantsCache);
2417 
2418  // if (inputPortIdentifier != NULL)
2419  // {
2420 
2421  Value *inputPortIdentifierValue = new LoadInst(inputPortIdentifierVariable, "", false, checkBlock);
2422  ICmpInst *portIdentifierNotEqualsNull = new ICmpInst(*checkBlock, ICmpInst::ICMP_NE, inputPortIdentifierValue, nullInputPortIdentifier, "");
2423  BranchInst::Create(scheduleBlock, finalBlock, portIdentifierNotEqualsNull, checkBlock);
2424 
2425  // void **context = (void **)malloc(4 * sizeof(void *));
2426  // context[0] = (void *)compositionState;
2427  // context[1] = (void *)inputPortIdentifier;
2428  // context[2] = (void *)valueAsString;
2429  // context[3] = (void *)isCompositionRunning;
2430 
2431  Value *contextValue = VuoCompilerCodeGenUtilities::generateCreatePublishedInputWorkerContext(module, scheduleBlock, compositionStateValue,
2432  inputPortIdentifierValue, valueAsStringValue,
2433  isCompositionRunningValue);
2434 
2435  // dispatch_sync(PublishedInputsTrigger__queue, context, PublishedInputPorts__setWorker);
2436  // }
2437 
2438  VuoCompilerNode *triggerNode = graph->getNodeForTriggerPort(trigger);
2439  Value *nodeContextValue = triggerNode->generateGetContext(module, scheduleBlock, compositionStateValue);
2440  string workerFunctionName = VuoStringUtilities::transcodeToIdentifier(VuoNodeClass::publishedInputNodeClassName) + "__setWorker";
2441 
2442  Function *workerFunction = trigger->generateSynchronousSubmissionToDispatchQueue(module, scheduleBlock, nodeContextValue,
2443  workerFunctionName, contextValue);
2444 
2445  BranchInst::Create(finalBlock, scheduleBlock);
2446  ReturnInst::Create(module->getContext(), finalBlock);
2447 
2448  // void PublishedInputPorts__firstName__worker(void *context)
2449  // {
2450 
2451  Function *compositionSetPortValueFunction = VuoCompilerCodeGenUtilities::getCompositionSetPortValueFunction(module);
2452 
2453  Function::arg_iterator workerArgs = workerFunction->arg_begin();
2454  Value *contextValueInWorker = workerArgs++;
2455  contextValueInWorker->setName("context");
2456 
2457  BasicBlock *workerBlock = BasicBlock::Create(module->getContext(), "", workerFunction, 0);
2458 
2459  // VuoCompositionState *compositionState = (VuoCompositionState *)((void **)context)[0];
2460  // char *inputPortIdentifier = (char *)((void **)context)[1];
2461  // char *valueAsString = (char *)((void **)context)[2];
2462  // bool isCompositionRunning = (bool)((void **)context)[3];
2463 
2464  Type *voidPointerType = contextValueInWorker->getType();
2465  Type *voidPointerPointerType = PointerType::get(voidPointerType, 0);
2466  Type *compositionStatePointerType = PointerType::get(VuoCompilerCodeGenUtilities::getCompositionStateType(module), 0);
2467  Type *boolType = compositionSetPortValueFunction->getFunctionType()->getParamType(3);
2468 
2469  Value *contextValueAsVoidPointerArray = new BitCastInst(contextValueInWorker, voidPointerPointerType, "", workerBlock);
2470  Value *compositionStateAsVoidPointer = VuoCompilerCodeGenUtilities::generateGetArrayElement(module, workerBlock, contextValueAsVoidPointerArray, (size_t)0);
2471  Value *compositionStateValueInWorker = new BitCastInst(compositionStateAsVoidPointer, compositionStatePointerType, "", workerBlock);
2472 
2473  Value *inputPortIdentifierAsVoidPointer = VuoCompilerCodeGenUtilities::generateGetArrayElement(module, workerBlock, contextValueAsVoidPointerArray, 1);
2474  Value *inputPortIdentifierValueInWorker = new BitCastInst(inputPortIdentifierAsVoidPointer, pointerToCharType, "", workerBlock);
2475 
2476  Value *valueAsStringValueAsVoidPointer = VuoCompilerCodeGenUtilities::generateGetArrayElement(module, workerBlock, contextValueAsVoidPointerArray, 2);
2477  Value *valueAsStringValueInWorker = new BitCastInst(valueAsStringValueAsVoidPointer, pointerToCharType, "", workerBlock);
2478 
2479  Value *isCompositionRunningValueAsVoidPointer = VuoCompilerCodeGenUtilities::generateGetArrayElement(module, workerBlock, contextValueAsVoidPointerArray, 3);
2480  Value *isCompositionRunningValueInWorker = new PtrToIntInst(isCompositionRunningValueAsVoidPointer, boolType, "", workerBlock);
2481 
2482  // free(context);
2483 
2484  VuoCompilerCodeGenUtilities::generateFreeCall(module, workerBlock, contextValueInWorker);
2485 
2486  // compositionSetPortValue(compositionState, portIdentifier, valueAsString, isCompositionRunning, isCompositionRunning, isCompositionRunning, true, true);
2487  // }
2488 
2489  Value *trueValue = ConstantInt::get(boolType, 1);
2490 
2491  vector<Value *> setValueArgs;
2492  setValueArgs.push_back(compositionStateValueInWorker);
2493  setValueArgs.push_back(inputPortIdentifierValueInWorker);
2494  setValueArgs.push_back(valueAsStringValueInWorker);
2495  setValueArgs.push_back(isCompositionRunningValueInWorker);
2496  setValueArgs.push_back(isCompositionRunningValueInWorker);
2497  setValueArgs.push_back(isCompositionRunningValueInWorker);
2498  setValueArgs.push_back(trueValue);
2499  setValueArgs.push_back(trueValue);
2500  CallInst::Create(compositionSetPortValueFunction, setValueArgs, "", workerBlock);
2501 
2502  ReturnInst::Create(module->getContext(), workerBlock);
2503 }
2504 
2512 void VuoCompilerBitcodeGenerator::generateSetPublishedInputPortValueFunction(void)
2513 {
2515 
2516  Function::arg_iterator args = function->arg_begin();
2517  Value *publishedInputPortNameValue = args++;
2518  publishedInputPortNameValue->setName("publishedInputPortName");
2519  Value *valueAsStringValue = args++;
2520  valueAsStringValue->setName("valueAsString");
2521 
2522  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
2523 
2525 
2526  Value *topLevelRuntimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, block);
2527  Value *topLevelCompositionIdentifierValue = constantsCache->get(VuoCompilerComposition::topLevelCompositionIdentifier);
2528  Value *compositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, topLevelRuntimeStateValue, topLevelCompositionIdentifierValue);
2529  Value *trueValue = ConstantInt::get(compositionFunction->getFunctionType()->getParamType(3), 1);
2530 
2531  vector<Value *> compositionArgs;
2532  compositionArgs.push_back(compositionStateValue);
2533  compositionArgs.push_back(publishedInputPortNameValue);
2534  compositionArgs.push_back(valueAsStringValue);
2535  compositionArgs.push_back(trueValue);
2536  CallInst::Create(compositionFunction, compositionArgs, "", block);
2537 
2538  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, compositionStateValue);
2539 
2540  ReturnInst::Create(module->getContext(), block);
2541 }
2542 
2547 void VuoCompilerBitcodeGenerator::generateTransmissionFromOutputPort(Function *function, BasicBlock *&currentBlock,
2548  Value *compositionStateValue,
2549  VuoCompilerNode *outputNode, VuoCompilerPort *outputPort,
2550  Value *eventValue, Value *dataPointer,
2551  bool requiresEvent, bool shouldSendTelemetry)
2552 {
2553  IntegerType *boolType = IntegerType::get(module->getContext(), 1);
2554  PointerType *pointerToCharType = PointerType::get(IntegerType::get(module->getContext(), 8), 0);
2555 
2556  set<VuoCompilerCable *> outgoingCables = graph->getOutgoingCables(outputPort);
2557 
2558  Constant *trueValue = ConstantInt::get(boolType, 1);
2559  Constant *falseValue = ConstantInt::get(boolType, 0);
2560  Constant *transmittedEventValue = (requiresEvent ? trueValue : falseValue);
2561 
2562  // char *dataSummary = NULL;
2563  AllocaInst *dataSummaryVariable = new AllocaInst(pointerToCharType, 0, "dataSummary", currentBlock);
2564  new StoreInst(ConstantPointerNull::get(pointerToCharType), dataSummaryVariable, currentBlock);
2565 
2566  map<VuoCompilerPort *, ICmpInst *> shouldSummarizeInput;
2567  if (shouldSendTelemetry)
2568  {
2569  // bool sentData = false;
2570  AllocaInst *sentDataVariable = new AllocaInst(boolType, 0, "sentData", currentBlock);
2571  new StoreInst(falseValue, sentDataVariable, currentBlock);
2572 
2573  for (set<VuoCompilerCable *>::iterator i = outgoingCables.begin(); i != outgoingCables.end(); ++i)
2574  {
2575  VuoCompilerCable *cable = *i;
2576 
2577  VuoCompilerPort *inputPort = static_cast<VuoCompilerPort *>(cable->getBase()->getToPort()->getCompiler());
2578  ICmpInst *shouldSendDataForInput = VuoCompilerCodeGenUtilities::generateShouldSendDataTelemetryComparison(module, currentBlock,
2579  inputPort->getIdentifier(),
2580  compositionStateValue,
2581  constantsCache);
2582  shouldSummarizeInput[inputPort] = shouldSendDataForInput;
2583  }
2584 
2585  if (dataPointer)
2586  {
2587  Value *shouldSummarizeOutput = VuoCompilerCodeGenUtilities::generateShouldSendDataTelemetryComparison(module, currentBlock,
2588  outputPort->getIdentifier(),
2589  compositionStateValue,
2590  constantsCache);
2591 
2592  for (set<VuoCompilerCable *>::iterator i = outgoingCables.begin(); i != outgoingCables.end(); ++i)
2593  {
2594  VuoCompilerCable *cable = *i;
2595 
2596  if (cable->carriesData())
2597  {
2598  VuoCompilerPort *inputPort = static_cast<VuoCompilerPort *>(cable->getBase()->getToPort()->getCompiler());
2599  shouldSummarizeOutput = BinaryOperator::Create(Instruction::Or, shouldSummarizeOutput, shouldSummarizeInput[inputPort], "", currentBlock);
2600  }
2601  }
2602 
2603  BasicBlock *summaryBlock = BasicBlock::Create(module->getContext(), "outputSummary", function, NULL);
2604  BasicBlock *sendOutputBlock = BasicBlock::Create(module->getContext(), "sendOutput", function, NULL);
2605  BranchInst::Create(summaryBlock, sendOutputBlock, shouldSummarizeOutput, currentBlock);
2606 
2607  // sentData = true;
2608  new StoreInst(trueValue, sentDataVariable, summaryBlock);
2609 
2610  // dataSummary = <type>_getSummary(portValue);
2611  VuoCompilerType *type = outputPort->getDataVuoType()->getCompiler();
2612  Value *dataSummaryValue = type->generateSummaryFromValueFunctionCall(module, summaryBlock, dataPointer);
2613  new StoreInst(dataSummaryValue, dataSummaryVariable, summaryBlock);
2614 
2615  BranchInst::Create(sendOutputBlock, summaryBlock);
2616  currentBlock = sendOutputBlock;
2617  }
2618 
2619  if (shouldSendTelemetry && outputNode != graph->getPublishedInputNode())
2620  {
2621  Value *sentDataValue = new LoadInst(sentDataVariable, "", false, currentBlock);
2622  Value *dataSummaryValue = new LoadInst(dataSummaryVariable, "", false, currentBlock);
2623 
2624  Constant *outputPortIdentifierValue = constantsCache->get(outputPort->getIdentifier());
2625 
2626  VuoCompilerCodeGenUtilities::generateSendOutputPortsUpdated(module, currentBlock, compositionStateValue, outputPortIdentifierValue,
2627  transmittedEventValue, sentDataValue, dataSummaryValue);
2628  }
2629  }
2630 
2631  // If the output port should transmit an event...
2632  bool alwaysTransmitsEvent = (dynamic_cast<VuoCompilerTriggerPort *>(outputPort) || ! requiresEvent);
2633  BasicBlock *transmissionBlock = NULL;
2634  BasicBlock *noTransmissionBlock = NULL;
2635  if (alwaysTransmitsEvent)
2636  {
2637  transmissionBlock = currentBlock;
2638  }
2639  else
2640  {
2641  transmissionBlock = BasicBlock::Create(module->getContext(), "transmission", function, NULL);
2642  noTransmissionBlock = BasicBlock::Create(module->getContext(), "noTransmission", function, NULL);
2643 
2644  ConstantInt *zeroValue = ConstantInt::get(static_cast<IntegerType *>(eventValue->getType()), 0);
2645  ICmpInst *eventValueIsTrue = new ICmpInst(*currentBlock, ICmpInst::ICMP_NE, eventValue, zeroValue, "");
2646  BranchInst::Create(transmissionBlock, noTransmissionBlock, eventValueIsTrue, currentBlock);
2647  }
2648 
2649  // ... then transmit the event and data (if any) to each connected input port.
2650  for (set<VuoCompilerCable *>::iterator i = outgoingCables.begin(); i != outgoingCables.end(); ++i)
2651  {
2652  VuoCompilerCable *cable = *i;
2653 
2654  VuoCompilerNode *inputNode = cable->getBase()->getToNode()->getCompiler();
2655  Value *inputNodeContextValue = inputNode->generateGetContext(module, transmissionBlock, compositionStateValue);
2656  VuoCompilerInputEventPort *inputPort = static_cast<VuoCompilerInputEventPort *>( cable->getBase()->getToPort()->getCompiler() );
2657  Value *inputPortContextValue = inputPort->generateGetPortContext(module, transmissionBlock, inputNodeContextValue);
2658 
2659  Value *transmittedDataPointer = (cable->carriesData() ? dataPointer : NULL);
2660 
2661  cable->generateTransmission(module, transmissionBlock, inputNodeContextValue, inputPortContextValue, transmittedDataPointer, requiresEvent);
2662 
2663  if (shouldSendTelemetry && inputNode != graph->getPublishedInputNode())
2664  {
2665  // char *inputDataSummary = NULL;
2666  AllocaInst *inputDataSummaryVariable = new AllocaInst(pointerToCharType, 0, "inputDataSummary", transmissionBlock);
2667  new StoreInst(ConstantPointerNull::get(pointerToCharType), inputDataSummaryVariable, transmissionBlock);
2668 
2669  // bool receivedData = false;
2670  AllocaInst *receivedDataVariable = new AllocaInst(boolType, 0, "receivedData", transmissionBlock);
2671  new StoreInst(falseValue, receivedDataVariable, transmissionBlock);
2672 
2673  VuoType *inputDataType = inputPort->getDataVuoType();
2674  if (inputDataType)
2675  {
2676  BasicBlock *summaryBlock = BasicBlock::Create(module->getContext(), "inputSummary", function, NULL);
2677  BasicBlock *sendInputBlock = BasicBlock::Create(module->getContext(), "sendInput", function, NULL);
2678  BranchInst::Create(summaryBlock, sendInputBlock, shouldSummarizeInput[inputPort], transmissionBlock);
2679 
2680  Value *inputDataSummaryValue;
2681  if (transmittedDataPointer)
2682  {
2683  // receivedData = true;
2684  new StoreInst(trueValue, receivedDataVariable, summaryBlock);
2685 
2686  // inputDataSummary = dataSummary;
2687  inputDataSummaryValue = new LoadInst(dataSummaryVariable, "", false, summaryBlock);
2688  }
2689  else
2690  {
2691  // inputDataSummary = <Type>_getSummary(inputData);
2692  Value *inputDataPointer = VuoCompilerCodeGenUtilities::generateGetPortContextDataVariableAsVoidPointer(module, summaryBlock, inputPortContextValue);
2693  inputDataSummaryValue = inputDataType->getCompiler()->generateSummaryFromValueFunctionCall(module, summaryBlock, inputDataPointer);
2694  }
2695  new StoreInst(inputDataSummaryValue, inputDataSummaryVariable, summaryBlock);
2696 
2697  BranchInst::Create(sendInputBlock, summaryBlock);
2698  transmissionBlock = sendInputBlock;
2699  }
2700 
2701  Value *receivedDataValue = new LoadInst(receivedDataVariable, "", false, transmissionBlock);
2702  Value *inputDataSummaryValue = new LoadInst(inputDataSummaryVariable, "", false, transmissionBlock);
2703 
2704  Constant *inputPortIdentifierValue = constantsCache->get(inputPort->getIdentifier());
2705 
2706  VuoCompilerCodeGenUtilities::generateSendInputPortsUpdated(module, transmissionBlock, compositionStateValue, inputPortIdentifierValue,
2707  transmittedEventValue, receivedDataValue, inputDataSummaryValue);
2708 
2709  if (inputDataType && ! transmittedDataPointer)
2710  {
2711  // free(inputDataSummary);
2712  VuoCompilerCodeGenUtilities::generateFreeCall(module, transmissionBlock, inputDataSummaryValue);
2713  }
2714  }
2715  }
2716 
2717  if (alwaysTransmitsEvent)
2718  {
2719  currentBlock = transmissionBlock;
2720  }
2721  else
2722  {
2723  BranchInst::Create(noTransmissionBlock, transmissionBlock);
2724  currentBlock = noTransmissionBlock;
2725  }
2726 
2727  if (shouldSendTelemetry && dataPointer)
2728  {
2729  // free(dataSummary)
2730  Function *freeFunction = VuoCompilerCodeGenUtilities::getFreeFunction(module);
2731  LoadInst *dataSummaryValue = new LoadInst(dataSummaryVariable, "", false, currentBlock);
2732  CallInst::Create(freeFunction, dataSummaryValue, "", currentBlock);
2733  }
2734 }
2735 
2740 void VuoCompilerBitcodeGenerator::generateTransmissionFromNode(Function *function, BasicBlock *&currentBlock,
2741  Value *compositionStateValue, Value *nodeContextValue,
2742  VuoCompilerNode *node, bool requiresEvent, bool shouldSendTelemetry)
2743 {
2744  vector<VuoPort *> outputPorts = node->getBase()->getOutputPorts();
2745  for (vector<VuoPort *>::iterator i = outputPorts.begin(); i != outputPorts.end(); ++i)
2746  {
2747  // If the output port is a trigger port, do nothing.
2748  VuoCompilerOutputEventPort *outputEventPort = dynamic_cast<VuoCompilerOutputEventPort *>((*i)->getCompiler());
2749  if (! outputEventPort)
2750  continue;
2751 
2752  Value *portContextValue = outputEventPort->generateGetPortContext(module, currentBlock, nodeContextValue);
2753  Value *outputEventValue = outputEventPort->generateLoadEvent(module, currentBlock, nodeContextValue, portContextValue);
2754 
2755  BasicBlock *telemetryBlock = NULL;
2756  BasicBlock *noTelemetryBlock = NULL;
2757  if (requiresEvent)
2758  {
2759  telemetryBlock = BasicBlock::Create(module->getContext(), "", function, NULL);
2760  noTelemetryBlock = BasicBlock::Create(module->getContext(), "", function, NULL);
2761 
2762  // If the output port isn't transmitting an event, do nothing.
2763  ConstantInt *zeroValue = ConstantInt::get(static_cast<IntegerType *>(outputEventValue->getType()), 0);
2764  ICmpInst *eventValueIsTrue = new ICmpInst(*currentBlock, ICmpInst::ICMP_NE, outputEventValue, zeroValue, "");
2765  BranchInst::Create(telemetryBlock, noTelemetryBlock, eventValueIsTrue, currentBlock);
2766  }
2767  else
2768  {
2769  telemetryBlock = currentBlock;
2770  }
2771 
2772  // Transmit the data through the output port to each connected input port.
2773  VuoCompilerOutputData *outputData = outputEventPort->getData();
2774  Value *outputDataPointer = (outputData ?
2775  outputEventPort->generateRetrieveData(module, telemetryBlock, nodeContextValue, portContextValue) :
2776  NULL);
2777  generateTransmissionFromOutputPort(function, telemetryBlock, compositionStateValue,
2778  node, outputEventPort, outputEventValue, outputDataPointer, requiresEvent, shouldSendTelemetry);
2779 
2780  if (requiresEvent)
2781  {
2782  BranchInst::Create(noTelemetryBlock, telemetryBlock);
2783  currentBlock = noTelemetryBlock;
2784  }
2785  else
2786  {
2787  currentBlock = telemetryBlock;
2788  }
2789  }
2790 }
2791 
2796 void VuoCompilerBitcodeGenerator::generateTelemetryFromPublishedOutputNode(Function *function, BasicBlock *&currentBlock, Value *compositionStateValue,
2797  Value *nodeContextValue, VuoCompilerNode *node)
2798 {
2799  IntegerType *boolType = IntegerType::get(module->getContext(), 1);
2800  PointerType *pointerToCharType = PointerType::get(IntegerType::get(module->getContext(), 8), 0);
2801 
2802  for (auto inputPort : node->getBase()->getInputPorts())
2803  {
2804  // If the published output port is for internal use only, do nothing.
2805  if (inputPort == graph->getGatherPortOnPublishedOutputNode())
2806  continue;
2807 
2808  VuoCompilerInputEventPort *inputEventPort = dynamic_cast<VuoCompilerInputEventPort *>(inputPort->getCompiler());
2809 
2810  BasicBlock *telemetryBlock = BasicBlock::Create(module->getContext(), "", function, NULL);
2811  BasicBlock *noTelemetryBlock = BasicBlock::Create(module->getContext(), "", function, NULL);
2812 
2813  // If the published output port isn't transmitting an event, do nothing.
2814  Value *eventValue = inputEventPort->generateLoadEvent(module, currentBlock, nodeContextValue);
2815  ConstantInt *zeroValue = ConstantInt::get(static_cast<IntegerType *>(eventValue->getType()), 0);
2816  ICmpInst *eventValueIsTrue = new ICmpInst(*currentBlock, ICmpInst::ICMP_NE, eventValue, zeroValue, "");
2817  BranchInst::Create(telemetryBlock, noTelemetryBlock, eventValueIsTrue, currentBlock);
2818 
2819  VuoCompilerInputData *data = inputEventPort->getData();
2820  Value *dataPointer = data ? inputEventPort->generateRetrieveData(module, telemetryBlock, nodeContextValue) : NULL;
2821  Constant *trueValue = ConstantInt::get(boolType, 1);
2822  Constant *falseValue = ConstantInt::get(boolType, 0);
2823 
2824  Value *sentDataValue = NULL;
2825  Value *dataSummaryValue = NULL;
2826  if (dataPointer)
2827  {
2828  // sentData = true;
2829  sentDataValue = trueValue;
2830 
2831  // dataSummary = <type>_getSummary(portValue);
2832  VuoCompilerType *type = inputEventPort->getDataVuoType()->getCompiler();
2833  dataSummaryValue = type->generateSummaryFromValueFunctionCall(module, telemetryBlock, dataPointer);
2834  }
2835  else
2836  {
2837  // sentData = false;
2838  sentDataValue = falseValue;
2839 
2840  // dataSummary = NULL;
2841  dataSummaryValue = ConstantPointerNull::get(pointerToCharType);
2842  }
2843 
2844  Constant *portIdentifierValue = constantsCache->get(inputEventPort->getBase()->getClass()->getName());
2845  VuoCompilerCodeGenUtilities::generateSendPublishedOutputPortsUpdated(module, telemetryBlock, compositionStateValue, portIdentifierValue,
2846  sentDataValue, dataSummaryValue);
2847 
2848  VuoCompilerCodeGenUtilities::generateFreeCall(module, telemetryBlock, dataSummaryValue);
2849 
2850  BranchInst::Create(noTelemetryBlock, telemetryBlock);
2851  currentBlock = noTelemetryBlock;
2852  }
2853 }
2854 
2861 void VuoCompilerBitcodeGenerator::generateDataOnlyTransmissionFromNode(Function *function, BasicBlock *&currentBlock, Value *compositionStateValue,
2862  VuoCompilerNode *node, bool shouldWaitForDownstreamNodes,
2863  bool shouldUpdateTriggers, bool shouldSendTelemetry)
2864 {
2865  vector<VuoCompilerNode *> downstreamNodes = graph->getNodesDownstreamViaDataOnlyTransmission(node);
2866  if (downstreamNodes.empty())
2867  return;
2868 
2869  if (shouldWaitForDownstreamNodes)
2870  {
2871  // Claim the nodes downstream via data-only transmission.
2872  generateLockNodes(module, currentBlock, compositionStateValue, downstreamNodes, nullptr);
2873  }
2874 
2875  // For this node and each node downstream via data-only transmission...
2876  vector<VuoCompilerNode *> nodesToVisit = downstreamNodes;
2877  nodesToVisit.insert(nodesToVisit.begin(), node);
2878  for (VuoCompilerNode *visitedNode : nodesToVisit)
2879  {
2880  if (graph->mayTransmitDataOnly(visitedNode))
2881  {
2882  Value *nodeContextValue = visitedNode->generateGetContext(module, currentBlock, compositionStateValue);
2883 
2884  // Simulate an event having just hit all input ports of the node (necessary due to published input node's doors).
2885  vector<VuoPort *> inputPorts = visitedNode->getBase()->getInputPorts();
2886  for (size_t i = VuoNodeClass::unreservedInputPortStartIndex; i < inputPorts.size(); ++i)
2887  {
2888  VuoCompilerInputEventPort *inputEventPort = static_cast<VuoCompilerInputEventPort *>(inputPorts[i]->getCompiler());
2889  inputEventPort->generateStoreEvent(module, currentBlock, nodeContextValue, true);
2890  }
2891 
2892  // Call the node's event function, and send telemetry if needed.
2893  generateNodeExecution(function, currentBlock, compositionStateValue, visitedNode, false);
2894 
2895  // Transmit data through the node's outgoing cables, and send telemetry for port updates if needed.
2896  generateTransmissionFromNode(function, currentBlock, compositionStateValue, nodeContextValue, visitedNode, false, shouldSendTelemetry);
2897 
2898  // Reset the node's event inputs and outputs.
2899  VuoCompilerCodeGenUtilities::generateResetNodeContextEvents(module, currentBlock, nodeContextValue);
2900  }
2901 
2902  if (visitedNode != node)
2903  {
2904  if (shouldUpdateTriggers)
2905  {
2906  // Call the downstream node's trigger update function.
2907  visitedNode->generateCallbackUpdateFunctionCall(module, currentBlock, compositionStateValue);
2908  }
2909 
2910  if (shouldWaitForDownstreamNodes)
2911  {
2912  // Signal the downstream node.
2913  generateUnlockNodes(module, currentBlock, compositionStateValue, vector<VuoCompilerNode *>(1, visitedNode));
2914  }
2915  }
2916  }
2917 }
2918 
2922 void VuoCompilerBitcodeGenerator::generateNodeExecution(Function *function, BasicBlock *&currentBlock,
2923  Value *compositionStateValue, VuoCompilerNode *node,
2924  bool shouldSendTelemetry)
2925 {
2926  Value *nodeIdentifierValue = constantsCache->get(node->getIdentifier());
2927 
2928  if (shouldSendTelemetry)
2929  {
2930  // Send telemetry indicating that the node's execution has started.
2931  VuoCompilerCodeGenUtilities::generateSendNodeExecutionStarted(module, currentBlock, compositionStateValue, nodeIdentifierValue);
2932  }
2933 
2934  // Call the node's event function.
2935  if (debugMode)
2936  VuoCompilerCodeGenUtilities::generatePrint(module, currentBlock, node->getBase()->getTitle() + "\n");
2937  node->generateEventFunctionCall(module, function, currentBlock, compositionStateValue);
2938 
2939  if (shouldSendTelemetry)
2940  {
2941  // Send telemetry indicating that the node's execution has finished.
2942  VuoCompilerCodeGenUtilities::generateSendNodeExecutionFinished(module, currentBlock, compositionStateValue, nodeIdentifierValue);
2943  }
2944 }
2945 
2949 void VuoCompilerBitcodeGenerator::generateAllocation(void)
2950 {
2951 #ifdef VUO_PRO
2952  generateAllocation_Pro();
2953 #endif
2954 
2955  {
2956  Constant *value = constantsCache->get(VuoCompilerComposition::topLevelCompositionIdentifier);
2957  new GlobalVariable(*module, value->getType(), true, GlobalValue::ExternalLinkage, value, "vuoTopLevelCompositionIdentifier");
2958  }
2959 }
2960 
2968 void VuoCompilerBitcodeGenerator::generateSetupFunction(bool isStatefulComposition)
2969 {
2970  Function *function = VuoCompilerCodeGenUtilities::getSetupFunction(module);
2971  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
2972 
2973  Value *topLevelRuntimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, block);
2974  Value *topLevelCompositionIdentifierValue = constantsCache->get(VuoCompilerComposition::topLevelCompositionIdentifier);
2975  Value *topLevelCompositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, topLevelRuntimeStateValue, topLevelCompositionIdentifierValue);
2976 
2977  // Top__compositionAddNodeMetadata(compositionState);
2978 
2979  Function *compositionCreateAndRegisterMetadataFunction = VuoCompilerCodeGenUtilities::getCompositionAddNodeMetadataFunction(module);
2980  CallInst::Create(compositionCreateAndRegisterMetadataFunction, topLevelCompositionStateValue, "", block);
2981 
2982  // vuoInitContextForTopLevelComposition(compositionState, hasInstanceData, publishedOutputPortCount);
2983 
2984  size_t publishedOutputPortCount = composition->getBase()->getPublishedOutputPorts().size();
2985  VuoCompilerCodeGenUtilities::generateInitContextForTopLevelComposition(module, block, topLevelCompositionStateValue,
2986  isStatefulComposition, publishedOutputPortCount);
2987 
2988  // Set each published input port to its initial value.
2989 
2990  Function *compositionSetPublishedInputPortValueFunction = VuoCompilerCodeGenUtilities::getCompositionSetPublishedInputPortValueFunction(module);
2991  Value *falseValue = ConstantInt::get(compositionSetPublishedInputPortValueFunction->getFunctionType()->getParamType(3), 0);
2992 
2993  for (VuoPublishedPort *publishedInputPort : composition->getBase()->getPublishedInputPorts())
2994  {
2995  string name = publishedInputPort->getClass()->getName();
2996  string initialValue = static_cast<VuoCompilerPublishedPort *>(publishedInputPort->getCompiler())->getInitialValue();
2997 
2998  vector<Value *> args;
2999  args.push_back(topLevelCompositionStateValue);
3000  args.push_back( constantsCache->get(name) );
3001  args.push_back( constantsCache->get(initialValue) );
3002  args.push_back(falseValue);
3003  CallInst::Create(compositionSetPublishedInputPortValueFunction, args, "", block);
3004  }
3005 
3006  // Top__compositionPerformDataOnlyTransmissions(compositionState);
3007 
3008  Function *compositionPerformDataOnlyTransmissionsFunction = VuoCompilerCodeGenUtilities::getCompositionPerformDataOnlyTransmissionsFunction(module);
3009  CallInst::Create(compositionPerformDataOnlyTransmissionsFunction, topLevelCompositionStateValue, "", block);
3010 
3011  // Update the function pointers for all trigger functions in the top-level composition.
3012 
3013  for (map<VuoCompilerTriggerPort *, Function *>::iterator i = topLevelTriggerFunctions.begin(); i != topLevelTriggerFunctions.end(); ++i)
3014  {
3015  VuoCompilerTriggerPort *trigger = i->first;
3016  Function *function = i->second;
3017 
3018  VuoCompilerNode *node = graph->getNodeForTriggerPort(trigger);
3019  Value *nodeContextValue = node->generateGetContext(module, block, topLevelCompositionStateValue);
3020  trigger->generateStoreFunction(module, block, nodeContextValue, function);
3021  }
3022 
3023  // Update the function pointers for all trigger functions in subcompositions.
3024 
3025  for (map<string, map<size_t, map<VuoCompilerTriggerDescription *, Function *> > >::iterator i = subcompositionTriggerFunctions.begin(); i != subcompositionTriggerFunctions.end(); ++i)
3026  {
3027  string compositionIdentifier = i->first;
3028 
3029  for (map<size_t, map<VuoCompilerTriggerDescription *, Function *> >::iterator j = i->second.begin(); j != i->second.end(); ++j)
3030  {
3031  size_t nodeIndex = j->first;
3032 
3033  for (map<VuoCompilerTriggerDescription *, Function *>::iterator k = j->second.begin(); k != j->second.end(); ++k)
3034  {
3035  VuoCompilerTriggerDescription *trigger = k->first;
3036  Function *function = k->second;
3037 
3038  Value *compositionIdentifierValue = constantsCache->get(compositionIdentifier);
3039  Value *compositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, topLevelRuntimeStateValue, compositionIdentifierValue);
3040 
3041  int portContextIndex = trigger->getPortContextIndex();
3042  Value *nodeContextValue = VuoCompilerCodeGenUtilities::generateGetNodeContext(module, block, compositionStateValue, nodeIndex);
3043  Value *portContextValue = VuoCompilerCodeGenUtilities::generateGetNodeContextPortContext(module, block, nodeContextValue, portContextIndex);
3044  VuoCompilerCodeGenUtilities::generateSetPortContextTriggerFunction(module, block, portContextValue, function);
3045 
3046  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, compositionStateValue);
3047  }
3048  }
3049  }
3050 
3051  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, topLevelCompositionStateValue);
3052 
3053  ReturnInst::Create(module->getContext(), block);
3054 }
3055 
3062 void VuoCompilerBitcodeGenerator::generateCleanupFunction(void)
3063 {
3064  Function *function = VuoCompilerCodeGenUtilities::getCleanupFunction(module);
3065  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
3066 
3067  Value *topLevelRuntimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, block);
3068  Value *topLevelCompositionIdentifierValue = constantsCache->get(VuoCompilerComposition::topLevelCompositionIdentifier);
3069  Value *topLevelCompositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, topLevelRuntimeStateValue, topLevelCompositionIdentifierValue);
3070 
3071  VuoCompilerCodeGenUtilities::generateFiniContextForTopLevelComposition(module, block, topLevelCompositionStateValue);
3072 
3073  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, topLevelCompositionStateValue);
3074 
3075  ReturnInst::Create(module->getContext(), block);
3076 }
3077 
3083 void VuoCompilerBitcodeGenerator::generateInstanceInitFunction(bool isStatefulComposition)
3084 {
3085  Function *function = VuoCompilerCodeGenUtilities::getInstanceInitFunction(module);
3086  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
3087 
3088  if (isStatefulComposition)
3089  {
3090  map<VuoPort *, size_t> indexOfParameter;
3091  Function *nodeInstanceInitFunction = VuoCompilerCodeGenUtilities::getNodeInstanceInitFunction(module, moduleKey, true,
3093  vector<VuoPort *>(),
3094  indexOfParameter, constantsCache);
3095 
3096  Value *topLevelRuntimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, block);
3097  Value *topLevelCompositionIdentifierValue = constantsCache->get(VuoCompilerComposition::topLevelCompositionIdentifier);
3098  Value *topLevelCompositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, topLevelRuntimeStateValue, topLevelCompositionIdentifierValue);
3099 
3100  CallInst::Create(nodeInstanceInitFunction, topLevelCompositionStateValue, "", block);
3101 
3102  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, topLevelCompositionStateValue);
3103  }
3104 
3105  ReturnInst::Create(module->getContext(), block);
3106 }
3107 
3113 void VuoCompilerBitcodeGenerator::generateInstanceFiniFunction(bool isStatefulComposition)
3114 {
3115  Function *function = VuoCompilerCodeGenUtilities::getInstanceFiniFunction(module);
3116  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
3117 
3118  if (isStatefulComposition)
3119  {
3120  Function *nodeInstanceFiniFunction = VuoCompilerCodeGenUtilities::getNodeInstanceFiniFunction(module, moduleKey,
3122  constantsCache);
3123 
3124  Value *topLevelRuntimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, block);
3125  Value *topLevelCompositionIdentifierValue = constantsCache->get(VuoCompilerComposition::topLevelCompositionIdentifier);
3126  Value *topLevelCompositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, topLevelRuntimeStateValue, topLevelCompositionIdentifierValue);
3127 
3128  PointerType *instanceDataType = static_cast<PointerType *>( nodeInstanceFiniFunction->getFunctionType()->getParamType(1) );
3129  ConstantPointerNull *nullInstanceDataValue = ConstantPointerNull::get(instanceDataType);
3130 
3131  vector<Value *> args;
3132  args.push_back(topLevelCompositionStateValue);
3133  args.push_back(nullInstanceDataValue);
3134  CallInst::Create(nodeInstanceFiniFunction, args, "", block);
3135 
3136  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, topLevelCompositionStateValue);
3137  }
3138 
3139  ReturnInst::Create(module->getContext(), block);
3140 }
3141 
3147 void VuoCompilerBitcodeGenerator::generateInstanceTriggerStartFunction(bool isStatefulComposition)
3148 {
3150  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
3151 
3152  if (isStatefulComposition)
3153  {
3154  map<VuoPort *, size_t> indexOfParameter;
3155  Function *nodeInstanceTriggerStartFunction = VuoCompilerCodeGenUtilities::getNodeInstanceTriggerStartFunction(module, moduleKey,
3157  vector<VuoPort *>(),
3158  indexOfParameter,
3159  constantsCache);
3160 
3161  Value *topLevelRuntimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, block);
3162  Value *topLevelCompositionIdentifierValue = constantsCache->get(VuoCompilerComposition::topLevelCompositionIdentifier);
3163  Value *topLevelCompositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, topLevelRuntimeStateValue, topLevelCompositionIdentifierValue);
3164 
3165  PointerType *instanceDataType = static_cast<PointerType *>( nodeInstanceTriggerStartFunction->getFunctionType()->getParamType(1) );
3166  ConstantPointerNull *nullInstanceDataValue = ConstantPointerNull::get(instanceDataType);
3167 
3168  vector<Value *> args;
3169  args.push_back(topLevelCompositionStateValue);
3170  args.push_back(nullInstanceDataValue);
3171  CallInst::Create(nodeInstanceTriggerStartFunction, args, "", block);
3172 
3173  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, topLevelCompositionStateValue);
3174  }
3175 
3176  ReturnInst::Create(module->getContext(), block);
3177 }
3178 
3184 void VuoCompilerBitcodeGenerator::generateInstanceTriggerStopFunction(bool isStatefulComposition)
3185 {
3187  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
3188 
3189  {
3190  Function *nodeInstanceTriggerStopFunction = VuoCompilerCodeGenUtilities::getNodeInstanceTriggerStopFunction(module, moduleKey,
3192  constantsCache);
3193 
3194  Value *topLevelRuntimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, block);
3195  Value *topLevelCompositionIdentifierValue = constantsCache->get(VuoCompilerComposition::topLevelCompositionIdentifier);
3196  Value *topLevelCompositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, topLevelRuntimeStateValue, topLevelCompositionIdentifierValue);
3197 
3198  PointerType *instanceDataType = static_cast<PointerType *>( nodeInstanceTriggerStopFunction->getFunctionType()->getParamType(1) );
3199  ConstantPointerNull *nullInstanceDataValue = ConstantPointerNull::get(instanceDataType);
3200 
3201  vector<Value *> args;
3202  args.push_back(topLevelCompositionStateValue);
3203  args.push_back(nullInstanceDataValue);
3204  CallInst::Create(nodeInstanceTriggerStopFunction, args, "", block);
3205 
3206  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, topLevelCompositionStateValue);
3207  }
3208 
3209  ReturnInst::Create(module->getContext(), block);
3210 }
3211 
3217 void VuoCompilerBitcodeGenerator::generateTriggerFunctions(void)
3218 {
3219  auto isSpinOffTrigger = [] (const string &nodeClassName)
3220  {
3221  return (VuoStringUtilities::beginsWith(nodeClassName, "vuo.event.spinOff") ||
3222  VuoStringUtilities::beginsWith(nodeClassName, "vuo.list.build") ||
3223  VuoStringUtilities::beginsWith(nodeClassName, "vuo.list.process"));
3224  };
3225 
3226  map<VuoCompilerTriggerPort *, Function *> workerFunctionForTrigger;
3227  for (VuoCompilerTriggerPort *trigger : graph->getTriggerPorts())
3228  {
3229  Function *workerFunction = generateTriggerWorkerFunction(trigger);
3230  workerFunctionForTrigger[trigger] = workerFunction;
3231  }
3232 
3233  if (isTopLevelComposition)
3234  {
3235  for (map<VuoCompilerTriggerPort *, Function *>::iterator i = workerFunctionForTrigger.begin(); i != workerFunctionForTrigger.end(); ++i)
3236  {
3237  VuoCompilerTriggerPort *trigger = i->first;
3238  Function *workerFunction = i->second;
3239 
3240  VuoType *dataType = trigger->getDataVuoType();
3241 
3242  VuoCompilerNode *node = graph->getNodeForTriggerPort(trigger);
3243  size_t triggerNodeIndex = node->getIndexInOrderedNodes();
3244 
3245  string portIdentifier = trigger->getIdentifier();
3246 
3247  int portContextIndex = trigger->getIndexInPortContexts();
3248 
3249  bool canDropEvents = (trigger->getBase()->getEventThrottling() == VuoPortClass::EventThrottling_Drop);
3250 
3251  bool isPublishedTrigger = (trigger == graph->getPublishedInputTrigger());
3252 
3253  bool isSpinOff = isSpinOffTrigger(node->getBase()->getNodeClass()->getClassName());
3254 
3255  int minThreadsNeeded, maxThreadsNeeded;
3256  graph->getWorkerThreadsNeeded(trigger, minThreadsNeeded, maxThreadsNeeded);
3257 
3258  int chainCount = (int)graph->getChains()[trigger].size();
3259 
3260  Function *function = generateTriggerSchedulerFunction(dataType, VuoCompilerComposition::topLevelCompositionIdentifier, triggerNodeIndex,
3261  portIdentifier, portContextIndex, canDropEvents, isPublishedTrigger, isSpinOff,
3262  minThreadsNeeded, maxThreadsNeeded, chainCount, workerFunction);
3263  topLevelTriggerFunctions[trigger] = function;
3264  }
3265 
3266  for (VuoCompilerNode *node : graph->getNodes())
3267  {
3268  VuoCompilerNodeClass *nodeClass = node->getBase()->getNodeClass()->getCompiler();
3269 
3271  node->getGraphvizIdentifier());
3272 
3273  vector<VuoCompilerTriggerDescription *> triggers = nodeClass->getTriggerDescriptions();
3274  for (vector<VuoCompilerTriggerDescription *>::iterator j = triggers.begin(); j != triggers.end(); ++j)
3275  {
3276  VuoCompilerTriggerDescription *trigger = *j;
3277 
3278  size_t triggerNodeIndex = trigger->getNodeIndex();
3279  string triggerNodeIdentifier = trigger->getNodeIdentifier();
3280  string portIdentifier = VuoStringUtilities::buildPortIdentifier(triggerNodeIdentifier, trigger->getPortName());
3281  int portContextIndex = trigger->getPortContextIndex();
3282  bool canDropEvents = (trigger->getEventThrottling() == VuoPortClass::EventThrottling_Drop);
3283  VuoType *dataType = trigger->getDataType();
3284  string subcompositionNodeClassName = trigger->getSubcompositionNodeClassName();
3285  VuoCompilerNodeClass *subcompositionNodeClass = (subcompositionNodeClassName.empty() ?
3286  nodeClass :
3287  compiler->getNodeClass(subcompositionNodeClassName));
3288  string subcompositionNodeIdentifier = trigger->getSubcompositionNodeIdentifier();
3289  string fullSubcompositionNodeIdentifier = (subcompositionNodeIdentifier.empty() ?
3290  nodeIdentifier :
3291  VuoStringUtilities::buildCompositionIdentifier(nodeIdentifier, subcompositionNodeIdentifier));
3292  bool isPublishedTrigger = (triggerNodeIdentifier == graph->getPublishedInputTriggerNodeIdentifier());
3293 
3294  bool isSpinOff = isSpinOffTrigger(trigger->getNodeClassName());
3295 
3296  int minThreadsNeeded, maxThreadsNeeded;
3297  if (isPublishedTrigger)
3298  minThreadsNeeded = maxThreadsNeeded = -1;
3299  else
3300  trigger->getWorkerThreadsNeeded(minThreadsNeeded, maxThreadsNeeded);
3301 
3302  int chainCount = trigger->getChainCount();
3303 
3304  Function *workerFunctionSrc = subcompositionNodeClass->getTriggerWorkerFunction(portIdentifier);
3305  Function *workerFunction = VuoCompilerModule::declareFunctionInModule(module, workerFunctionSrc);
3306 
3307  Function *function = generateTriggerSchedulerFunction(dataType, fullSubcompositionNodeIdentifier, triggerNodeIndex,
3308  portIdentifier, portContextIndex, canDropEvents, isPublishedTrigger, isSpinOff,
3309  minThreadsNeeded, maxThreadsNeeded, chainCount, workerFunction);
3310 
3311  subcompositionTriggerFunctions[fullSubcompositionNodeIdentifier][triggerNodeIndex][trigger] = function;
3312  }
3313  }
3314  }
3315 }
3316 
3360 Function * VuoCompilerBitcodeGenerator::generateTriggerSchedulerFunction(VuoType *dataType,
3361  string compositionIdentifier, size_t nodeIndex,
3362  string portIdentifier, int portContextIndex,
3363  bool canDropEvents, bool isPublishedInputTrigger, bool isSpinOff,
3364  int minThreadsNeeded, int maxThreadsNeeded, int chainCount,
3365  Function *workerFunction)
3366 {
3367  string functionName = VuoStringUtilities::prefixSymbolName(workerFunction->getName().str(),
3368  VuoStringUtilities::transcodeToIdentifier(compositionIdentifier));
3369  FunctionType *functionType = VuoCompilerCodeGenUtilities::getFunctionType(module, dataType);
3370  Function *function = Function::Create(functionType, GlobalValue::InternalLinkage, functionName, module);
3371 
3372  if (dataType)
3373  dataType->getCompiler()->copyFunctionParameterAttributes(function);
3374 
3375  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, NULL);
3376  BasicBlock *finalBlock = BasicBlock::Create(module->getContext(), "final", function, NULL);
3377  BasicBlock *scheduleBlock = BasicBlock::Create(module->getContext(), "schedule", function, NULL);
3378 
3379  Value *runtimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, initialBlock);
3380  Value *compositionIdentifierValue = constantsCache->get(compositionIdentifier);
3381 
3382  Value *compositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, initialBlock, runtimeStateValue, compositionIdentifierValue);
3383  VuoCompilerCodeGenUtilities::generateRegisterCall(module, initialBlock, compositionStateValue, VuoCompilerCodeGenUtilities::getFreeFunction(module));
3384  VuoCompilerCodeGenUtilities::generateRetainCall(module, initialBlock, compositionStateValue);
3385 
3386  Value *nodeContextValue = VuoCompilerCodeGenUtilities::generateGetNodeContext(module, initialBlock, compositionStateValue, nodeIndex);
3387  Value *portContextValue = VuoCompilerCodeGenUtilities::generateGetNodeContextPortContext(module, initialBlock, nodeContextValue, portContextIndex);
3388 
3389  if (canDropEvents)
3390  {
3391  BasicBlock *checkEventDropBlock = BasicBlock::Create(module->getContext(), "checkEventDrop", function, NULL);
3392  BranchInst::Create(checkEventDropBlock, initialBlock);
3393 
3394  // Do a non-blocking wait on the trigger's semaphore to check if it's already claimed. If so...
3395  Value *retValue = VuoCompilerTriggerPort::generateNonBlockingWaitForSemaphore(module, checkEventDropBlock, portContextValue);
3396  Constant *zeroValue = ConstantInt::get(retValue->getType(), 0);
3397  ICmpInst *isTriggerAvailableValue = new ICmpInst(*checkEventDropBlock, ICmpInst::ICMP_EQ, retValue, zeroValue, "");
3398  BasicBlock *dropEventBlock = BasicBlock::Create(module->getContext(), "dropEvent", function, NULL);
3399  BranchInst::Create(scheduleBlock, dropEventBlock, isTriggerAvailableValue, checkEventDropBlock);
3400 
3401  // Release the data value.
3402  if (dataType)
3403  VuoCompilerTriggerPort::generateDataValueDiscardFromScheduler(module, function, dropEventBlock, dataType);
3404 
3405  // Send telemetry that the event has been dropped.
3406  Constant *portIdentifierValue = constantsCache->get(portIdentifier);
3407  VuoCompilerCodeGenUtilities::generateSendEventDropped(module, dropEventBlock, compositionStateValue, portIdentifierValue);
3408 
3409  VuoCompilerCodeGenUtilities::generateReleaseCall(module, dropEventBlock, compositionStateValue);
3410 
3411  BranchInst::Create(finalBlock, dropEventBlock);
3412  }
3413  else
3414  {
3415  BranchInst::Create(scheduleBlock, initialBlock);
3416  }
3417 
3418  // Enter the trigger's dispatch group for tracking workers scheduled.
3419  Value *triggerWorkersScheduledValue = VuoCompilerCodeGenUtilities::getTriggerWorkersScheduledValue(module, scheduleBlock, compositionStateValue);
3420  VuoCompilerCodeGenUtilities::generateEnterDispatchGroup(module, scheduleBlock, triggerWorkersScheduledValue);
3421 
3422  Value *eventIdValue;
3423  if (! isPublishedInputTrigger)
3424  {
3425  // Get a unique ID for this event.
3426  eventIdValue = VuoCompilerCodeGenUtilities::generateGetNextEventId(module, scheduleBlock, compositionStateValue);
3427 
3428  // If this trigger fires in response to an input event, and the original event came from the published input trigger,
3429  // associate the new (spun off) event's ID with the original event.
3430  if (isSpinOff)
3431  {
3432  Value *compositionContextValue = VuoCompilerCodeGenUtilities::generateGetCompositionContext(module, scheduleBlock, compositionStateValue);
3433  VuoCompilerCodeGenUtilities::generateSpunOffExecutingEvent(module, scheduleBlock, compositionContextValue, eventIdValue);
3434  }
3435  }
3436  else
3437  {
3438  // Use the event ID from the parent composition or `firePublishedInputTrigger()`.
3439  Value *compositionContextValue = VuoCompilerCodeGenUtilities::generateGetCompositionContext(module, scheduleBlock, compositionStateValue);
3440  eventIdValue = VuoCompilerCodeGenUtilities::generateGetOneExecutingEvent(module, scheduleBlock, compositionContextValue);
3441  }
3442 
3443  // Schedule the trigger's worker function via `vuoScheduleTriggerWorker()`.
3444  VuoCompilerTriggerPort::generateScheduleWorker(module, function, scheduleBlock,
3445  compositionStateValue, eventIdValue, portContextValue, dataType,
3446  minThreadsNeeded, maxThreadsNeeded, chainCount, workerFunction);
3447  BranchInst::Create(finalBlock, scheduleBlock);
3448 
3449  ReturnInst::Create(module->getContext(), finalBlock);
3450 
3451  return function;
3452 }
3453 
3598 Function * VuoCompilerBitcodeGenerator::generateTriggerWorkerFunction(VuoCompilerTriggerPort *trigger)
3599 {
3601  Function *function = trigger->getWorkerFunction(module, functionName, true);
3602 
3603  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, NULL);
3604  BasicBlock *triggerBlock = BasicBlock::Create(module->getContext(), "trigger", function, NULL);
3605  BasicBlock *finalBlock = BasicBlock::Create(module->getContext(), "final", function, NULL);
3606 
3607  Value *compositionStateValue = trigger->generateCompositionStateValue(module, initialBlock, function);
3608  Value *compositionContextValue = VuoCompilerCodeGenUtilities::generateGetCompositionContext(module, initialBlock, compositionStateValue);
3609  Value *eventIdValue = trigger->generateEventIdValue(module, initialBlock, function);
3610 
3611  VuoCompilerNode *triggerNode = graph->getNodeForTriggerPort(trigger);
3612  Value *triggerNodeContextValue = triggerNode->generateGetContext(module, initialBlock, compositionStateValue);
3613  Value *triggerWorkersScheduledValue = VuoCompilerCodeGenUtilities::getTriggerWorkersScheduledValue(module, initialBlock, compositionStateValue);
3614  bool canDropEvents = (trigger->getBase()->getEventThrottling() == VuoPortClass::EventThrottling_Drop);
3615 
3616  bool isPublishedInputTrigger = (trigger == graph->getPublishedInputTrigger());
3617  bool isNodeEventForSubcomposition = (! isTopLevelComposition && isPublishedInputTrigger);
3618 
3619  if (! isNodeEventForSubcomposition)
3620  {
3621  // Check if `isPaused` is true. If so...
3622  BasicBlock *isPausedBlock = BasicBlock::Create(module->getContext(), "isPaused", function, NULL);
3623  ICmpInst *isPausedValueIsTrue = VuoCompilerCodeGenUtilities::generateIsPausedComparison(module, initialBlock, compositionStateValue);
3624  BranchInst::Create(isPausedBlock, triggerBlock, isPausedValueIsTrue, initialBlock);
3625 
3626  // Release the data value.
3627  trigger->generateDataValueDiscardFromWorker(module, isPausedBlock, function);
3628 
3629  // Wait for the published output node's semaphore, if not already claimed in `firePublishedInputPortEvent()`.
3630  VuoCompilerNode *publishedOutputNode = graph->getPublishedOutputNode();
3631  vector<VuoCompilerNode *> publishedOutputNodeVector(1, publishedOutputNode);
3632  if (publishedOutputNode && ! isPublishedInputTrigger)
3633  generateLockNodes(module, isPausedBlock, compositionStateValue, publishedOutputNodeVector);
3634 
3635  // Call `vuoSendEventFinished()`.
3636  VuoCompilerCodeGenUtilities::generateSendEventFinished(module, isPausedBlock, compositionStateValue, eventIdValue);
3637 
3638  if (isPublishedInputTrigger)
3639  {
3640  // Signal the semaphores claimed in `firePublishedInputPortEvent()`.
3641  vector<VuoCompilerNode *> triggerWaitNodes = getNodesToWaitOnBeforeTransmission(trigger);
3642  generateUnlockNodes(module, isPausedBlock, compositionStateValue, triggerWaitNodes);
3643  }
3644 
3645  // Signal the published output node's semaphore.
3646  if (publishedOutputNode)
3647  generateUnlockNodes(module, isPausedBlock, compositionStateValue, publishedOutputNodeVector);
3648 
3649  if (canDropEvents)
3650  // Signal the trigger's semaphore for event dropping.
3651  trigger->generateSignalForSemaphore(module, isPausedBlock, triggerNodeContextValue);
3652 
3653  // Leave the trigger's dispatch group for tracking workers scheduled.
3654  VuoCompilerCodeGenUtilities::generateLeaveDispatchGroup(module, isPausedBlock, triggerWorkersScheduledValue);
3655 
3656  // Call `vuoReturnThreadsForTriggerWorker()`.
3657  VuoCompilerCodeGenUtilities::generateReturnThreadsForTriggerWorker(module, isPausedBlock, eventIdValue, compositionStateValue);
3658 
3659  BranchInst::Create(finalBlock, isPausedBlock);
3660  // Otherwise...
3661  }
3662  else
3663  {
3664  BranchInst::Create(triggerBlock, initialBlock);
3665  }
3666 
3667  if (isPublishedInputTrigger)
3668  {
3669  if (! isNodeEventForSubcomposition)
3670  {
3671  // Signal the published output node if it was waited on in `firePublishedInputPortEvent()` just to track event start/finished.
3672  vector<VuoCompilerNode *> triggerWaitNodes = getNodesToWaitOnBeforeTransmission(trigger);
3673  VuoCompilerNode *publishedOutputNode = graph->getPublishedOutputNode();
3674  if (find(triggerWaitNodes.begin(), triggerWaitNodes.end(), publishedOutputNode) == triggerWaitNodes.end())
3675  {
3676  vector<VuoCompilerNode *> publishedOutputNodeVector(1, publishedOutputNode);
3677  generateUnlockNodes(module, triggerBlock, compositionStateValue, publishedOutputNodeVector);
3678  }
3679  }
3680  }
3681  else
3682  {
3683  // Claim the semaphores of all necessary downstream nodes.
3684  vector<VuoCompilerNode *> triggerWaitNodes = getNodesToWaitOnBeforeTransmission(trigger);
3685  generateLockNodes(module, triggerBlock, compositionStateValue, triggerWaitNodes, eventIdValue);
3686 
3687  // Update the trigger's data value.
3688  Value *triggerDataValue = trigger->generateDataValueUpdate(module, triggerBlock, function, triggerNodeContextValue);
3689 
3690  // Transmit events and data (if any) out of the trigger port, and send telemetry for port updates.
3691  Value *triggerDataPointer = triggerDataValue ? VuoCompilerCodeGenUtilities::generatePointerToValue(triggerBlock, triggerDataValue) : nullptr;
3692  generateTransmissionFromOutputPort(function, triggerBlock, compositionStateValue, triggerNode, trigger, NULL, triggerDataPointer);
3693  }
3694 
3695  // If the trigger node isn't downstream of the trigger, signal the trigger node's semaphore.
3696  vector<VuoCompilerNode *> downstreamNodes = graph->getNodesDownstream(trigger);
3697  if (find(downstreamNodes.begin(), downstreamNodes.end(), triggerNode) == downstreamNodes.end())
3698  generateUnlockNodes(module, triggerBlock, compositionStateValue, vector<VuoCompilerNode *>(1, triggerNode));
3699 
3700  if (canDropEvents)
3701  // Signal the trigger's semaphore for event dropping.
3702  trigger->generateSignalForSemaphore(module, triggerBlock, triggerNodeContextValue);
3703 
3704  // Leave the trigger's dispatch group for tracking workers scheduled.
3705  VuoCompilerCodeGenUtilities::generateLeaveDispatchGroup(module, triggerBlock, triggerWorkersScheduledValue);
3706 
3707 
3708  // Schedule the chain worker function for each chain immediately downstream of the trigger.
3709 
3710  map<VuoCompilerChain *, vector<VuoCompilerChain *> > chainsImmediatelyDownstream;
3711  map<VuoCompilerChain *, vector<VuoCompilerChain *> > chainsImmediatelyUpstream;
3712  set<VuoCompilerChain *> chainsScheduled;
3713 
3714  vector<VuoCompilerChain *> allChains = chainsForTrigger[trigger];
3715 
3716  if (! allChains.empty())
3717  {
3718  // Organize the chains so it's easy to look up what's downstream/upstream of what.
3719  for (vector<VuoCompilerChain *>::iterator i = allChains.begin(); i != allChains.end(); ++i)
3720  {
3721  VuoCompilerChain *chain = *i;
3722  VuoCompilerNode *firstNodeInThisChain = chain->getNodes().front();
3723 
3724  for (vector<VuoCompilerChain *>::iterator j = allChains.begin(); j != allChains.end(); ++j)
3725  {
3726  VuoCompilerChain *otherChain = *j;
3727 
3728  if (chain == otherChain)
3729  break; // Any chains after this are downstream.
3730 
3731  VuoCompilerNode *lastNodeInOtherChain = otherChain->getNodes().back();
3732 
3733  if (graph->mayTransmit(lastNodeInOtherChain, firstNodeInThisChain, trigger))
3734  {
3735  chainsImmediatelyUpstream[chain].push_back(otherChain);
3736  chainsImmediatelyDownstream[otherChain].push_back(chain);
3737  }
3738  }
3739  }
3740 
3741  // Create the context to pass to the chain workers.
3742  Value *contextValue = VuoCompilerChain::generateMakeContext(module, triggerBlock, compositionStateValue, eventIdValue);
3743 
3744  // Find all chains immediately downstream of the trigger (i.e., chains that have no other chains upstream).
3745  vector<VuoCompilerChain *> firstChains;
3746  for (vector<VuoCompilerChain *>::iterator i = allChains.begin(); i != allChains.end(); ++i)
3747  {
3748  VuoCompilerChain *chain = *i;
3749  map<VuoCompilerChain *, vector<VuoCompilerChain *> >::iterator upstreamIter = chainsImmediatelyUpstream.find(chain);
3750  if (upstreamIter == chainsImmediatelyUpstream.end())
3751  firstChains.push_back(chain);
3752  }
3753 
3754  // Choose one chain to execute in the trigger worker, to reduce overhead creating/destroying threads.
3755  VuoCompilerChain *chainToExecute = firstChains.back();
3756  firstChains.pop_back();
3757  chainsScheduled.insert(chainToExecute);
3758  size_t chainIndex = find(allChains.begin(), allChains.end(), chainToExecute) - allChains.begin();
3759  VuoCompilerCodeGenUtilities::generateRetainCall(module, triggerBlock, contextValue);
3760 
3761  // Call `vuoGrantThreadsToChain()` for the chosen chain.
3762  int minThreadsNeeded, maxThreadsNeeded;
3763  graph->getWorkerThreadsNeeded(chainToExecute, minThreadsNeeded, maxThreadsNeeded);
3764  VuoCompilerCodeGenUtilities::generateGrantThreadsToChain(module, triggerBlock, minThreadsNeeded, maxThreadsNeeded,
3765  eventIdValue, compositionStateValue, chainIndex);
3766 
3767  // Schedule the rest of the chains immediately downstream of the trigger.
3768  generateAndScheduleChainWorkerFunctions(triggerBlock, compositionStateValue, contextValue, firstChains, trigger,
3769  allChains, chainsImmediatelyDownstream, chainsImmediatelyUpstream, chainsScheduled);
3770 
3771  // Execute the chosen chain.
3772  generateChainExecution(function, triggerBlock, compositionStateValue, contextValue, eventIdValue, chainToExecute, trigger,
3773  allChains, chainsImmediatelyDownstream, chainsImmediatelyUpstream, chainsScheduled);
3774  VuoCompilerCodeGenUtilities::generateReleaseCall(module, triggerBlock, contextValue);
3775  }
3776  else
3777  {
3778  // Call `vuoReturnThreadsForTriggerWorker()`.
3779  VuoCompilerCodeGenUtilities::generateReturnThreadsForTriggerWorker(module, triggerBlock, eventIdValue, compositionStateValue);
3780 
3781  if (isNodeEventForSubcomposition)
3782  {
3783  // Leave the dispatch group waited on by `nodeEvent()`/`nodeInstanceEvent()`.
3784  Value *subcompositionOutputGroupValue = VuoCompilerCodeGenUtilities::generateGetNodeContextExecutingGroup(module, triggerBlock, compositionContextValue);
3785  VuoCompilerCodeGenUtilities::generateLeaveDispatchGroup(module, triggerBlock, subcompositionOutputGroupValue);
3786  }
3787  }
3788 
3789  BranchInst::Create(finalBlock, triggerBlock);
3790 
3791  // Free the trigger worker's context.
3792  trigger->generateFreeContext(module, finalBlock, function);
3793  VuoCompilerCodeGenUtilities::generateReleaseCall(module, finalBlock, compositionStateValue);
3794 
3795  ReturnInst::Create(module->getContext(), finalBlock);
3796 
3797  return function;
3798 }
3799 
3803 void VuoCompilerBitcodeGenerator::generateAndScheduleChainWorkerFunctions(BasicBlock *schedulerBlock,
3804  Value *compositionStateValueInScheduler, Value *contextValueInScheduler,
3805  const vector<VuoCompilerChain *> &chainsToSchedule, VuoCompilerTriggerPort *trigger,
3806  const vector<VuoCompilerChain *> &allChains,
3807  const map<VuoCompilerChain *, vector<VuoCompilerChain *> > &chainsImmediatelyDownstream,
3808  const map<VuoCompilerChain *, vector<VuoCompilerChain *> > &chainsImmediatelyUpstream,
3809  set<VuoCompilerChain *> &chainsScheduled)
3810 {
3811  // Find the chains in chainsToSchedule that haven't already been scheduled.
3812  vector<VuoCompilerChain *> uniqueChainsToSchedule;
3813  for (vector<VuoCompilerChain *>::const_iterator i = chainsToSchedule.begin(); i != chainsToSchedule.end(); ++i)
3814  {
3815  VuoCompilerChain *chain = *i;
3816  if (chainsScheduled.find(chain) == chainsScheduled.end())
3817  {
3818  uniqueChainsToSchedule.push_back(chain);
3819  chainsScheduled.insert(chain);
3820  }
3821  }
3822 
3823  // Retain the context once for each chain to be scheduled.
3824  for (vector<VuoCompilerChain *>::const_iterator i = uniqueChainsToSchedule.begin(); i != uniqueChainsToSchedule.end(); ++i)
3825  VuoCompilerCodeGenUtilities::generateRetainCall(module, schedulerBlock, contextValueInScheduler);
3826 
3827  // Schedule each chain.
3828  for (vector<VuoCompilerChain *>::const_iterator i = uniqueChainsToSchedule.begin(); i != uniqueChainsToSchedule.end(); ++i)
3829  {
3830  VuoCompilerChain *chain = *i;
3831  generateAndScheduleChainWorkerFunction(schedulerBlock, compositionStateValueInScheduler, contextValueInScheduler,
3832  chain, trigger, allChains, chainsImmediatelyDownstream, chainsImmediatelyUpstream,
3833  chainsScheduled);
3834  }
3835 }
3836 
3840 void VuoCompilerBitcodeGenerator::generateAndScheduleChainWorkerFunction(BasicBlock *schedulerBlock,
3841  Value *compositionStateValueInScheduler, Value *contextValueInScheduler,
3842  VuoCompilerChain *chain, VuoCompilerTriggerPort *trigger,
3843  const vector<VuoCompilerChain *> &allChains,
3844  const map<VuoCompilerChain *, vector<VuoCompilerChain *> > &chainsImmediatelyDownstream,
3845  const map<VuoCompilerChain *, vector<VuoCompilerChain *> > &chainsImmediatelyUpstream,
3846  set<VuoCompilerChain *> &chainsScheduled)
3847 {
3848  int minThreadsNeeded, maxThreadsNeeded;
3849  graph->getWorkerThreadsNeeded(chain, minThreadsNeeded, maxThreadsNeeded);
3850 
3851  size_t chainIndex = find(allChains.begin(), allChains.end(), chain) - allChains.begin();
3852 
3853  vector<VuoCompilerChain *> upstreamChains;
3854  map<VuoCompilerChain *, vector<VuoCompilerChain *> >::const_iterator upstreamChainsIter = chainsImmediatelyUpstream.find(chain);
3855  if (upstreamChainsIter != chainsImmediatelyUpstream.end())
3856  upstreamChains = upstreamChainsIter->second;
3857 
3858  vector<size_t> upstreamChainIndices;
3859  for (vector<VuoCompilerChain *>::iterator i = upstreamChains.begin(); i != upstreamChains.end(); ++i)
3860  upstreamChainIndices.push_back( find(allChains.begin(), allChains.end(), *i) - allChains.begin() );
3861 
3862  // Call `vuoScheduleChainWorker` for the worker function implemented below.
3863  Function *chainWorker = chain->generateScheduleWorker(module, schedulerBlock, compositionStateValueInScheduler, contextValueInScheduler,
3864  trigger->getIdentifier(), minThreadsNeeded, maxThreadsNeeded, chainIndex,
3865  upstreamChainIndices);
3866 
3867  BasicBlock *chainBlock = BasicBlock::Create(module->getContext(), "", chainWorker, 0);
3868  Value *contextValueInChainWorker = chainWorker->arg_begin();
3869  Value *compositionStateValueInChainWorker = chain->generateCompositionStateValue(module, chainBlock, contextValueInChainWorker);
3870  Value *eventIdValue = chain->generateEventIdValue(module, chainBlock, contextValueInChainWorker);
3871 
3872  // Execute the chain.
3873  generateChainExecution(chainWorker, chainBlock, compositionStateValueInChainWorker, contextValueInChainWorker, eventIdValue, chain, trigger,
3874  allChains, chainsImmediatelyDownstream, chainsImmediatelyUpstream, chainsScheduled);
3875 
3876  // Release the chain worker's context.
3877  VuoCompilerCodeGenUtilities::generateReleaseCall(module, chainBlock, contextValueInChainWorker);
3878 
3879  ReturnInst::Create(module->getContext(), chainBlock);
3880 }
3881 
3885 void VuoCompilerBitcodeGenerator::generateChainExecution(Function *function, BasicBlock *&block,
3886  Value *compositionStateValue, Value *contextValue,
3887  Value *eventIdValue, VuoCompilerChain *chain, VuoCompilerTriggerPort *trigger,
3888  const vector<VuoCompilerChain *> &allChains,
3889  const map<VuoCompilerChain *, vector<VuoCompilerChain *> > &chainsImmediatelyDownstream,
3890  const map<VuoCompilerChain *, vector<VuoCompilerChain *> > &chainsImmediatelyUpstream,
3891  set<VuoCompilerChain *> &chainsScheduled)
3892 {
3893  size_t chainIndex = find(allChains.begin(), allChains.end(), chain) - allChains.begin();
3894  Value *chainIndexValue = ConstantInt::get(eventIdValue->getType(), chainIndex);
3895 
3896  // For each node in the chain...
3897  vector<VuoCompilerNode *> chainNodes = chain->getNodes();
3898  for (vector<VuoCompilerNode *>::iterator i = chainNodes.begin(); i != chainNodes.end(); ++i)
3899  {
3900  VuoCompilerNode *node = *i;
3901 
3902  Function *nodeExecutionFunction = executionFunctionForNode[node];
3903  if (! nodeExecutionFunction)
3904  {
3905  nodeExecutionFunction = generateNodeExecutionFunction(module, node);
3906  executionFunctionForNode[node] = nodeExecutionFunction;
3907  }
3908 
3909  Function *nodeTransmissionFunction = transmissionFunctionForNode[node];
3910  if (! nodeTransmissionFunction)
3911  {
3912  nodeTransmissionFunction = generateNodeTransmissionFunction(module, node);
3913  transmissionFunctionForNode[node] = nodeTransmissionFunction;
3914  }
3915 
3916  // If the event hit the node, call its event function and send telemetry.
3917  vector<Value *> nodeExecutionArgs;
3918  nodeExecutionArgs.push_back(compositionStateValue);
3919  nodeExecutionArgs.push_back(eventIdValue);
3920  nodeExecutionArgs.push_back(chainIndexValue);
3921  CallInst *isHitValue = CallInst::Create(nodeExecutionFunction, nodeExecutionArgs, "", block);
3922 
3923  // Whether or not the event hit the node, wait on any necessary downstream nodes.
3924  if (! (graph->isRepeatedInFeedbackLoop(node, trigger) && chain->isLastNodeInLoop()))
3925  {
3926  vector<VuoCompilerNode *> outputNodes = getNodesToWaitOnBeforeTransmission(trigger, node);
3927  generateLockNodes(module, block, compositionStateValue, outputNodes, eventIdValue);
3928  }
3929 
3930  // If the event hit the node, transmit events and data through its output cables and send telemetry.
3931  vector<Value *> nodeTransmissionArgs;
3932  nodeTransmissionArgs.push_back(compositionStateValue);
3933  nodeTransmissionArgs.push_back(isHitValue);
3934  CallInst::Create(nodeTransmissionFunction, nodeTransmissionArgs, "", block);
3935 
3936  // Whether or not the event hit the node, if this was the last time this event could reach the node,
3937  // signal the node's semaphore.
3938  if (! (graph->isRepeatedInFeedbackLoop(node, trigger) && ! chain->isLastNodeInLoop()))
3939  {
3940  // Special case: If this is the published output node in a subcomposition,
3941  // the node's semaphore is signaled in the node's execution function or the subcomposition's nodeEvent()/nodeInstanceEvent().
3942  if (! (! isTopLevelComposition && node == graph->getPublishedOutputNode()))
3943  generateUnlockNodes(module, block, compositionStateValue, vector<VuoCompilerNode *>(1, node));
3944  }
3945  }
3946 
3947  // Schedule any chains immediately downstream, if this chain is the one responsible for doing so.
3948  vector<VuoCompilerChain *> downstreamChains;
3949  map<VuoCompilerChain *, vector<VuoCompilerChain *> >::const_iterator downstreamChainsIter = chainsImmediatelyDownstream.find(chain);
3950  if (downstreamChainsIter != chainsImmediatelyDownstream.end())
3951  downstreamChains = downstreamChainsIter->second;
3952  if (! downstreamChains.empty())
3953  {
3954  vector<size_t> downstreamChainIndices;
3955  for (vector<VuoCompilerChain *>::iterator i = downstreamChains.begin(); i != downstreamChains.end(); ++i)
3956  downstreamChainIndices.push_back( find(allChains.begin(), allChains.end(), *i) - allChains.begin() );
3957 
3958  vector<VuoCompilerChain *> nextChains;
3959  for (vector<VuoCompilerChain *>::iterator i = downstreamChains.begin(); i != downstreamChains.end(); ++i)
3960  {
3961  VuoCompilerChain *downstreamChain = *i;
3962  nextChains.push_back(downstreamChain);
3963  }
3964 
3965  generateAndScheduleChainWorkerFunctions(block, compositionStateValue, contextValue, nextChains, trigger, allChains,
3966  chainsImmediatelyDownstream, chainsImmediatelyUpstream, chainsScheduled);
3967  }
3968 
3969  // Return the threads used by this chain to the thread pool.
3970  VuoCompilerCodeGenUtilities::generateReturnThreadsForChainWorker(module, block, eventIdValue, compositionStateValue, chainIndexValue);
3971 }
3972 
4018 Function * VuoCompilerBitcodeGenerator::generateNodeExecutionFunction(Module *module, VuoCompilerNode *node)
4019 {
4020  string functionName = node->getIdentifier() + "__execute";
4021  PointerType *pointerToCompositionStateType = PointerType::get(VuoCompilerCodeGenUtilities::getCompositionStateType(module), 0);
4022  Type *boolType = IntegerType::get(module->getContext(), 1);
4023  Type *eventIdType = VuoCompilerCodeGenUtilities::generateNoEventIdConstant(module)->getType();
4024  vector<Type *> params;
4025  params.push_back(pointerToCompositionStateType);
4026  params.push_back(eventIdType);
4027  params.push_back(eventIdType);
4028  FunctionType *functionType = FunctionType::get(boolType, params, false);
4029  Function *function = Function::Create(functionType, GlobalValue::InternalLinkage, functionName, module);
4030 
4031  Function::arg_iterator args = function->arg_begin();
4032  Value *compositionStateValue = args++;
4033  compositionStateValue->setName("compositionState");
4034  Value *eventIdValue = args++;
4035  eventIdValue->setName("eventId");
4036  Value *chainIndexValue = args++;
4037  chainIndexValue->setName("chainIndex");
4038 
4039  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, NULL);
4040  BasicBlock *finalBlock = BasicBlock::Create(module->getContext(), "final", function, NULL);
4041 
4042  Value *nodeContextValue = node->generateGetContext(module, initialBlock, compositionStateValue);
4043  Value *isHitValue = node->generateReceivedEventCondition(module, initialBlock, nodeContextValue);
4044 
4045  if (node == graph->getPublishedOutputNode())
4046  {
4047  if (isTopLevelComposition)
4048  {
4049  VuoCompilerCodeGenUtilities::generateSendEventFinished(module, initialBlock, compositionStateValue, eventIdValue);
4050 
4051  BranchInst::Create(finalBlock, initialBlock);
4052  }
4053  else
4054  {
4055  // Call the trigger functions for any published trigger ports that the event has hit.
4056 
4057  BasicBlock *currBlock = initialBlock;
4058 
4059  Value *compositionContextValue = VuoCompilerCodeGenUtilities::generateGetCompositionContext(module, currBlock, compositionStateValue);
4060 
4061  vector<VuoPublishedPort *> publishedInputPorts = composition->getBase()->getPublishedInputPorts();
4062  vector<VuoPublishedPort *> publishedOutputPorts = composition->getBase()->getPublishedOutputPorts();
4063 
4064  set<string> publishedOutputTriggerNames = graph->getPublishedOutputTriggers();
4065 
4066  for (size_t publishedPortIndex = 0; publishedPortIndex < publishedOutputPorts.size(); ++publishedPortIndex)
4067  {
4068  VuoPort *port = graph->getInputPortOnPublishedOutputNode(publishedPortIndex);
4069 
4070  Value *isPortHitValue = node->generateReceivedEventCondition(module, currBlock, nodeContextValue, vector<VuoPort *>(1, port));
4071 
4072  if (publishedOutputTriggerNames.find( port->getClass()->getName() ) != publishedOutputTriggerNames.end())
4073  {
4074  BasicBlock *triggerBlock = BasicBlock::Create(module->getContext(), "trigger", function, NULL);
4075  BasicBlock *nextBlock = BasicBlock::Create(module->getContext(), "next", function, NULL);
4076  BranchInst::Create(triggerBlock, nextBlock, isPortHitValue, currBlock);
4077 
4078  VuoCompilerInputEventPort *eventPort = static_cast<VuoCompilerInputEventPort *>( port->getCompiler() );
4079  VuoType *dataType = eventPort->getDataVuoType();
4080 
4081  FunctionType *triggerFunctionType = VuoCompilerCodeGenUtilities::getFunctionType(module, dataType);
4082 
4083  vector<Value *> args;
4084  if (dataType)
4085  {
4086  Value *dataPointer = eventPort->generateRetrieveData(module, triggerBlock, nodeContextValue);
4087  args = dataType->getCompiler()->convertPortDataToArgs(module, triggerBlock, dataPointer, triggerFunctionType, 0, false);
4088  }
4089 
4090  int indexInSubcompositionPorts = VuoNodeClass::unreservedInputPortStartIndex + publishedInputPorts.size() +
4091  VuoNodeClass::unreservedOutputPortStartIndex + publishedPortIndex;
4092 
4093  Value *portContextValue = VuoCompilerCodeGenUtilities::generateGetNodeContextPortContext(module, triggerBlock, compositionContextValue, indexInSubcompositionPorts);
4094  Value *triggerFunction = VuoCompilerCodeGenUtilities::generateGetPortContextTriggerFunction(module, triggerBlock, portContextValue, triggerFunctionType);
4095 
4096  CallInst *triggerFunctionCall = CallInst::Create(triggerFunction, args, "", triggerBlock);
4097  if (dataType)
4098  dataType->getCompiler()->copyFunctionParameterAttributes(module, triggerFunctionCall);
4099 
4100  BranchInst::Create(nextBlock, triggerBlock);
4101 
4102  currBlock = nextBlock;
4103  }
4104  else
4105  {
4106  VuoCompilerCodeGenUtilities::generateSetNodeContextOutputEvent(module, currBlock, compositionContextValue, publishedPortIndex, isPortHitValue);
4107  }
4108  }
4109 
4110  // If this event (which may or may not have actually hit the published output node) is from
4111  // nodeEvent()/nodeInstanceEvent() or an event spun off of it, and is the final one to complete, then...
4112 
4113  Value *subcompositionFinishedValue = VuoCompilerCodeGenUtilities::generateFinishedExecutingEvent(module, currBlock, compositionContextValue, eventIdValue);
4114  ConstantInt *falseValue = ConstantInt::get(static_cast<IntegerType *>(subcompositionFinishedValue->getType()), 0);
4115  ICmpInst *subcompositionFinishedIsTrue = new ICmpInst(*currBlock, ICmpInst::ICMP_NE, subcompositionFinishedValue, falseValue, "");
4116  BasicBlock *leaveBlock = BasicBlock::Create(module->getContext(), "leave", function, NULL);
4117  BasicBlock *signalBlock = BasicBlock::Create(module->getContext(), "signal", function, NULL);
4118  BranchInst::Create(leaveBlock, signalBlock, subcompositionFinishedIsTrue, currBlock);
4119 
4120  // Leave the dispatch group waited on by nodeEvent()/nodeInstanceEvent().
4121 
4122  Value *subcompositionOutputGroupValue = VuoCompilerCodeGenUtilities::generateGetNodeContextExecutingGroup(module, leaveBlock, compositionContextValue);
4123  VuoCompilerCodeGenUtilities::generateLeaveDispatchGroup(module, leaveBlock, subcompositionOutputGroupValue);
4124  BranchInst::Create(finalBlock, leaveBlock);
4125 
4126  // Otherwise, signal the published output node's semaphore so that the remaining events can claim it.
4127  // (For the final event, the published output node's semaphore is signaled in nodeEvent()/nodeInstanceEvent().)
4128 
4129  generateUnlockNodes(module, signalBlock, compositionStateValue, vector<VuoCompilerNode *>(1, node));
4130  BranchInst::Create(finalBlock, signalBlock);
4131  }
4132  }
4133  else
4134  {
4135  // If the node received an event, then...
4136  BasicBlock *executeBlock = BasicBlock::Create(module->getContext(), "execute", function, NULL);
4137  BranchInst::Create(executeBlock, finalBlock, isHitValue, initialBlock);
4138 
4139  if (node->getBase()->getNodeClass()->getCompiler()->isSubcomposition())
4140  {
4141  // Pass the event ID to the subcomposition.
4142  VuoCompilerCodeGenUtilities::generateStartedExecutingEvent(module, executeBlock, nodeContextValue, eventIdValue);
4143 
4144  // Pass the chain's reserved threads to the subcomposition.
4145  Value *compositionIdentifierValue = VuoCompilerCodeGenUtilities::generateGetCompositionStateCompositionIdentifier(module, executeBlock, compositionStateValue);
4146  Value *subcompositionIdentifierValue = node->generateSubcompositionIdentifierValue(module, executeBlock, compositionIdentifierValue);
4148  eventIdValue, compositionStateValue, chainIndexValue,
4149  subcompositionIdentifierValue);
4150  VuoCompilerCodeGenUtilities::generateFreeCall(module, executeBlock, subcompositionIdentifierValue);
4151  }
4152 
4153  // Call the node's event function, and send telemetry that the node's execution has started and finished.
4154  bool shouldSendTelemetry = (node != graph->getPublishedInputNode());
4155  generateNodeExecution(function, executeBlock, compositionStateValue, node, shouldSendTelemetry);
4156  BranchInst::Create(finalBlock, executeBlock);
4157  }
4158 
4159  ReturnInst::Create(module->getContext(), isHitValue, finalBlock);
4160 
4161  return function;
4162 }
4163 
4188 Function * VuoCompilerBitcodeGenerator::generateNodeTransmissionFunction(Module *module, VuoCompilerNode *node)
4189 {
4190  string functionName = node->getIdentifier() + "__transmit";
4191  PointerType *pointerToCompositionStateType = PointerType::get(VuoCompilerCodeGenUtilities::getCompositionStateType(module), 0);
4192  Type *boolType = IntegerType::get(module->getContext(), 1);
4193  vector<Type *> params;
4194  params.push_back(pointerToCompositionStateType);
4195  params.push_back(boolType);
4196  FunctionType *functionType = FunctionType::get(Type::getVoidTy(module->getContext()), params, false);
4197  Function *function = Function::Create(functionType, GlobalValue::InternalLinkage, functionName, module);
4198 
4199  Function::arg_iterator args = function->arg_begin();
4200  Value *compositionStateValue = args++;
4201  compositionStateValue->setName("compositionState");
4202  Value *isHitValue = args++;
4203  isHitValue->setName("isHit");
4204 
4205  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, NULL);
4206  BasicBlock *transmitBlock = BasicBlock::Create(module->getContext(), "transmit", function, NULL);
4207  BasicBlock *finalBlock = BasicBlock::Create(module->getContext(), "final", function, NULL);
4208 
4209  // If the node received an event, then...
4210  BranchInst::Create(transmitBlock, finalBlock, isHitValue, initialBlock);
4211 
4212  Value *nodeContextValue = node->generateGetContext(module, transmitBlock, compositionStateValue);
4213 
4214  if (node == graph->getPublishedOutputNode())
4215  {
4216  if (isTopLevelComposition)
4217  generateTelemetryFromPublishedOutputNode(function, transmitBlock, compositionStateValue, nodeContextValue, node);
4218  }
4219  else
4220  {
4221  // Transmit events and data through the node's outgoing cables, and send telemetry for port updates.
4222  generateTransmissionFromNode(function, transmitBlock, compositionStateValue, nodeContextValue, node);
4223  }
4224 
4225  // Reset the node's event inputs and outputs.
4226  VuoCompilerCodeGenUtilities::generateResetNodeContextEvents(module, transmitBlock, nodeContextValue);
4227 
4228  BranchInst::Create(finalBlock, transmitBlock);
4229  ReturnInst::Create(module->getContext(), finalBlock);
4230 
4231  return function;
4232 }
4233 
4238 {
4239  this->debugMode = debugMode;
4240 }