Vuo  2.2.0
VuoCompilerBitcodeGenerator.cc
Go to the documentation of this file.
1 
10 #include <sstream>
11 #include "VuoCable.hh"
12 #include "VuoCompiler.hh"
14 #include "VuoCompilerCable.hh"
15 #include "VuoCompilerChain.hh"
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("", getGlobalContext());
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  FunctionType *functionType = VuoCompilerCodeGenUtilities::getFunctionType(&module, dataType);
423  PointerType *pointerToFunctionType = PointerType::get(functionType, 0);
424  VuoCompilerTriggerPortClass *modelTriggerPortClass = new VuoCompilerTriggerPortClass(portName, pointerToFunctionType);
425  modelTriggerPortClass->setDataVuoType(dataType);
426  VuoCompilerPort *modelTriggerPort = modelTriggerPortClass->newPort();
427  modelOutputPorts[i] = modelTriggerPort->getBase();
428  }
429  }
430 }
431 
435 void VuoCompilerBitcodeGenerator::makeDependencies(void)
436 {
437  // Make sure all loading of dependencies for makeDependencies_Pro() happens before we get on llvmQueue.
438  dependencies = compiler->getDirectDependenciesForComposition(composition);
439 
440 #if VUO_PRO
441  makeDependencies_Pro();
442 #endif
443 
444  // Make sure all subcompositions needed by generateTriggerFunctions() are loaded before we get on llvmQueue.
445  compiler->getDependenciesForComposition(composition);
446 }
447 
456 {
457  bool isStatefulComposition = false;
458  for (VuoCompilerNode *node : graph->getNodes())
459  {
460  if (node->getBase()->getNodeClass()->getCompiler()->isStateful())
461  {
462  isStatefulComposition = true;
463  break;
464  }
465  }
466 
467  module = new Module(moduleKey, getGlobalContext());
468  constantsCache = new VuoCompilerConstantsCache(module);
469 
470  for (VuoCompilerNode *node : orderedNodes)
471  node->setConstantsCache(constantsCache);
472 
473  generateCompositionMetadata();
474 
475  generateTriggerFunctions();
476 
477  if (! isTopLevelComposition)
478  generateNodeEventFunction(isStatefulComposition);
479 
480  if (isStatefulComposition)
481  {
482  generateNodeInstanceInitFunction();
483  generateNodeInstanceFiniFunction();
484  generateNodeInstanceTriggerStartFunction();
485  if (! isTopLevelComposition)
486  generateNodeInstanceTriggerUpdateFunction();
487  }
488 
489  generateNodeInstanceTriggerStopFunction();
490 
491  generateCompositionReleasePortDataFunction();
492 
493  generateCompositionGetPortValueFunction();
494  generateCompositionSetPortValueFunction();
495  generateCompositionFireTriggerPortEventFunction();
496 
497  generateCompositionSetPublishedInputPortValueFunction();
498 
499  generateCompositionCreateContextForNodeFunction();
500  generateCompositionAddNodeMetadataFunction();
501  generateCompositionPerformDataOnlyTransmissionsFunction();
502 
503  if (isTopLevelComposition)
504  {
505  generateShouldShowSplashWindowFunction(compiler->shouldShowSplashWindow());
506 
507  generateAllocation();
508  generateSetupFunction(isStatefulComposition);
509  generateCleanupFunction();
510 
511  generateInstanceInitFunction(isStatefulComposition);
512  generateInstanceFiniFunction(isStatefulComposition);
513  generateInstanceTriggerStartFunction(isStatefulComposition);
514  generateInstanceTriggerStopFunction(isStatefulComposition);
515 
516  generateSetInputPortValueFunction();
517 
518  generateGetPublishedPortCountFunction(true);
519  generateGetPublishedPortCountFunction(false);
520  generateGetPublishedPortNamesFunction(true);
521  generateGetPublishedPortNamesFunction(false);
522  generateGetPublishedPortTypesFunction(true);
523  generateGetPublishedPortTypesFunction(false);
524  generateGetPublishedPortDetailsFunction(true);
525  generateGetPublishedPortDetailsFunction(false);
526  generateGetPublishedPortValueFunction(true);
527  generateGetPublishedPortValueFunction(false);
528  generateSetPublishedInputPortValueFunction();
529  generateFirePublishedInputPortEventFunction();
530  }
531 
532  composition->setModule(module);
533 
534  delete constantsCache;
535  constantsCache = nullptr;
536 
537  return module;
538 }
539 
543 void VuoCompilerBitcodeGenerator::generateCompositionMetadata(void)
544 {
545  json_object *metadataJson = json_object_new_object();
546  json_object *nodeMetadataJson = json_object_new_object();
547 
548  string title = composition->getBase()->getMetadata()->getCustomizedName();
549  if (title.empty())
550  {
551  string nodeClassNamePart = VuoStringUtilities::split(moduleKey, '.').back();
552  title = VuoStringUtilities::expandCamelCase(nodeClassNamePart);
553  }
554  json_object_object_add(metadataJson, "title", json_object_new_string(title.c_str()));
555 
556  string description = composition->getBase()->getMetadata()->getDescription();
557  json_object_object_add(metadataJson, "description", json_object_new_string(description.c_str()));
558 
559  json_object *keywordsJson = json_object_new_array();
560  for (const string &keyword : composition->getBase()->getMetadata()->getKeywords())
561  json_object_array_add(keywordsJson, json_object_new_string(keyword.c_str()));
562  json_object_object_add(metadataJson, "keywords", keywordsJson);
563 
564  string version = composition->getBase()->getMetadata()->getVersion();
565  if (! version.empty())
566  json_object_object_add(metadataJson, "version", json_object_new_string(version.c_str()));
567 
568  json_object *dependenciesJson = json_object_new_array();
569  for (const string &dependency : dependencies)
570  json_object_array_add(dependenciesJson, json_object_new_string(dependency.c_str()));
571  json_object_object_add(metadataJson, "dependencies", dependenciesJson);
572 
573  if (! isTopLevelComposition)
574  {
575 #if VUO_PRO
576  generateCompositionMetadata_Pro(nodeMetadataJson);
577 #endif
578 
579  json_object *triggersJson = json_object_new_array();
580  for (VuoCompilerTriggerPort *trigger : graph->getTriggerPorts())
581  {
582  VuoCompilerNode *triggerNode = graph->getNodeForTriggerPort(trigger);
583  json_object *t = VuoCompilerTriggerDescription::getJson(triggerNode, trigger, graph);
584  json_object_array_add(triggersJson, t);
585  }
586  for (VuoCompilerNode *node : graph->getNodes())
587  {
588  VuoCompilerNodeClass *nodeClass = node->getBase()->getNodeClass()->getCompiler();
589  vector<VuoCompilerTriggerDescription *> triggersInSubcomposition = nodeClass->getTriggerDescriptions();
590  for (VuoCompilerTriggerDescription *triggerInSubcomposition : triggersInSubcomposition)
591  {
592  json_object *t = triggerInSubcomposition->getJsonWithinSubcomposition(node);
593  json_object_array_add(triggersJson, t);
594  }
595  }
596  json_object_object_add(nodeMetadataJson, "triggers", triggersJson);
597 
598  json_object *nodesJson = json_object_new_object();
599  for (VuoCompilerNode *node : orderedNodes)
600  {
601  json_object *nodeClassNameJson = json_object_new_string(node->getBase()->getNodeClass()->getClassName().c_str());
602  json_object_object_add(nodesJson, node->getIdentifier().c_str(), nodeClassNameJson);
603  }
604  json_object_object_add(nodeMetadataJson, "nodes", nodesJson);
605  }
606 
607  json_object_object_add(metadataJson, "node", nodeMetadataJson);
608 
609  string metadata = json_object_to_json_string_ext(metadataJson, JSON_C_TO_STRING_PLAIN);
610  json_object_put(metadataJson);
611 
612  VuoCompilerCodeGenUtilities::generateModuleMetadata(module, metadata, moduleKey);
613 }
614 
620 void VuoCompilerBitcodeGenerator::generateShouldShowSplashWindowFunction(bool shouldShow)
621 {
622  IntegerType *returnType = IntegerType::get(module->getContext(), 8);
623  FunctionType *functionType = FunctionType::get(returnType, false);
624  Function *function = Function::Create(functionType, GlobalValue::ExternalLinkage, "vuoShouldShowSplashWindow", module);
625  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
626  Value *boolValue = ConstantInt::get(returnType, shouldShow);
627  ReturnInst::Create(module->getContext(), boolValue, block);
628 }
629 
636 void VuoCompilerBitcodeGenerator::generateCompositionAddNodeMetadataFunction(void)
637 {
639  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
640 
641  Function::arg_iterator args = function->arg_begin();
642  Value *compositionStateValue = args++;
643  compositionStateValue->setName("compositionState");
644 
645  Function *compositionCreateContextForNodeFunction = VuoCompilerCodeGenUtilities::getCompositionCreateContextForNodeFunction(module);
646  Function *compositionSetPortValueFunction = VuoCompilerCodeGenUtilities::getCompositionSetPortValueFunction(module);
647  Function *compositionGetPortValueFunction = VuoCompilerCodeGenUtilities::getCompositionGetPortValueFunction(module);
648  Function *compositionFireTriggerPortEventFunction = VuoCompilerCodeGenUtilities::getCompositionFireTriggerPortEventFunction(module);
649  Function *releasePortDataFunction = VuoCompilerCodeGenUtilities::getCompositionReleasePortDataFunction(module);
650 
651  for (vector<VuoCompilerNode *>::iterator i = orderedNodes.begin(); i != orderedNodes.end(); ++i)
652  {
653  VuoCompilerNode *node = *i;
654 
655  node->generateAddMetadata(module, block, compositionStateValue, orderedTypes, compositionCreateContextForNodeFunction,
656  compositionSetPortValueFunction, compositionGetPortValueFunction, compositionFireTriggerPortEventFunction,
657  releasePortDataFunction);
658  }
659 
660  ReturnInst::Create(module->getContext(), block);
661 }
662 
669 void VuoCompilerBitcodeGenerator::generateCompositionCreateContextForNodeFunction(void)
670 {
672  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, NULL);
673  BasicBlock *finalBlock = BasicBlock::Create(module->getContext(), "final", function, NULL);
674 
675  Function::arg_iterator args = function->arg_begin();
676  Value *nodeIndexValue = args++;
677  nodeIndexValue->setName("nodeIndex");
678 
679  PointerType *pointerToNodeContext = PointerType::get(VuoCompilerCodeGenUtilities::getNodeContextType(module), 0);
680  AllocaInst *nodeContextVariable = new AllocaInst(pointerToNodeContext, "nodeContext", initialBlock);
681 
682  vector< pair<BasicBlock *, BasicBlock *> > blocksForIndex;
683 
684  for (size_t i = 0; i < orderedNodes.size(); ++i)
685  {
686  VuoCompilerNode *node = orderedNodes[i];
687 
688  BasicBlock *block = BasicBlock::Create(module->getContext(), node->getIdentifier(), function, NULL);
689  Value *nodeContextValue = node->generateCreateContext(module, block);
690  new StoreInst(nodeContextValue, nodeContextVariable, block);
691 
692  blocksForIndex.push_back(make_pair(block, block));
693  }
694 
695  VuoCompilerCodeGenUtilities::generateIndexMatchingCode(module, function, initialBlock, finalBlock, nodeIndexValue, blocksForIndex);
696 
697  Value *nodeContextValue = new LoadInst(nodeContextVariable, "", false, finalBlock);
698  ReturnInst::Create(module->getContext(), nodeContextValue, finalBlock);
699 }
700 
709 void VuoCompilerBitcodeGenerator::generateCompositionPerformDataOnlyTransmissionsFunction(void)
710 {
712  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
713 
714  Function::arg_iterator args = function->arg_begin();
715  Value *compositionStateValue = args++;
716  compositionStateValue->setName("compositionState");
717 
718  // Copy data along cables supporting data-only transmission at this level of the composition.
719 
721  generateDataOnlyTransmissionFromNode(function, block, compositionStateValue, node, false, false, false);
722 
723  // For each subcomposition node…
724 
725  for (VuoCompilerNode *node : orderedNodes)
726  {
727  Function *subcompositionFunctionSrc = node->getBase()->getNodeClass()->getCompiler()->getCompositionPerformDataOnlyTransmissionsFunction();
728  if (subcompositionFunctionSrc)
729  {
730  Value *runtimeStateValue = VuoCompilerCodeGenUtilities::generateGetCompositionStateRuntimeState(module, block, compositionStateValue);
731  Value *compositionIdentifierValue = VuoCompilerCodeGenUtilities::generateGetCompositionStateCompositionIdentifier(module, block, compositionStateValue);
732  Value *subcompositionIdentifierValue = node->generateSubcompositionIdentifierValue(module, block, compositionIdentifierValue);
733  Value *subcompositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, runtimeStateValue, subcompositionIdentifierValue);
734  Value *subcompositionStateValueDst = VuoCompilerCodeGenUtilities::convertArgumentToParameterType(subcompositionStateValue, subcompositionFunctionSrc, 0, nullptr, module, block);
735 
736  // Copy the subcomposition node's input port values to the subcomposition's published input node's input ports.
737 
738  Function *setPublishedInputPortValueFunctionSrc = node->getBase()->getNodeClass()->getCompiler()->getCompositionSetPublishedInputPortValueFunction();
739  Function *setPublishedInputPortValueFunctionDst = VuoCompilerModule::declareFunctionInModule(module, setPublishedInputPortValueFunctionSrc);
740  Value *falseValue = ConstantInt::get(setPublishedInputPortValueFunctionDst->getFunctionType()->getParamType(3), 0);
741 
742  for (VuoPort *inputPort : node->getBase()->getInputPorts())
743  {
744  VuoCompilerInputEventPort *inputEventPort = static_cast<VuoCompilerInputEventPort *>(inputPort->getCompiler());
745  VuoCompilerInputData *inputData = inputEventPort->getData();
746  if (inputData)
747  {
748  Value *inputPortNameValue = constantsCache->get(inputPort->getClass()->getName());
749  Value *dataValue = constantsCache->get(inputData->getInitialValue());
750 
751  vector<Value *> args;
752  args.push_back(subcompositionStateValueDst);
753  args.push_back(inputPortNameValue);
754  args.push_back(dataValue);
755  args.push_back(falseValue);
756  CallInst::Create(setPublishedInputPortValueFunctionDst, args, "", block);
757  }
758  }
759 
760  // Call recursively for the subcomposition.
761 
762  Function *subcompositionFunctionDst = VuoCompilerModule::declareFunctionInModule(module, subcompositionFunctionSrc);
763  CallInst::Create(subcompositionFunctionDst, subcompositionStateValueDst, "", block);
764 
765  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, subcompositionStateValue);
766  VuoCompilerCodeGenUtilities::generateFreeCall(module, block, subcompositionIdentifierValue);
767  }
768  }
769 
770  ReturnInst::Create(module->getContext(), block);
771 }
772 
778 void VuoCompilerBitcodeGenerator::generateCompositionReleasePortDataFunction(void)
779 {
781  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, NULL);
782  BasicBlock *finalBlock = BasicBlock::Create(module->getContext(), "final", function, NULL);
783 
784  Function::arg_iterator args = function->arg_begin();
785  Value *portAddressAsVoidPointer = args++;
786  portAddressAsVoidPointer->setName("portData");
787  Value *typeIndexValue = args++;
788  typeIndexValue->setName("typeIndex");
789 
790  vector< pair<BasicBlock *, BasicBlock *> > blocksForIndex;
791 
792  for (vector<VuoCompilerType *>::iterator i = orderedTypes.begin(); i != orderedTypes.end(); ++i)
793  {
794  VuoCompilerType *type = *i;
795 
796  BasicBlock *block = BasicBlock::Create(module->getContext(), type->getBase()->getModuleKey(), function, NULL);
797  Value *portAddress = new BitCastInst(portAddressAsVoidPointer, PointerType::get(type->getType(), 0), "", block);
798  Value *portValue = new LoadInst(portAddress, "", false, block);
799  type->generateReleaseCall(module, block, portValue);
800 
801  blocksForIndex.push_back(make_pair(block, block));
802  }
803 
804  VuoCompilerCodeGenUtilities::generateIndexMatchingCode(module, function, initialBlock, finalBlock, typeIndexValue, blocksForIndex);
805 
806  ReturnInst::Create(module->getContext(), finalBlock);
807 }
808 
812 void VuoCompilerBitcodeGenerator::generateSetInputDataFromNodeFunctionArguments(Function *function, BasicBlock *&block, Value *compositionStateValue,
813  map<VuoPort *, size_t> indexOfParameter,
814  map<VuoPort *, size_t> indexOfEventParameter,
815  bool shouldWaitForDataOnlyDownstreamNodes,
816  bool shouldUpdateTriggers, bool shouldSendTelemetry)
817 {
818  VuoCompilerNode *publishedInputNode = graph->getPublishedInputNode();
819  if (! publishedInputNode)
820  return;
821 
822  Value *publishedNodeContextValue = publishedInputNode->generateGetContext(module, block, compositionStateValue);
823 
824  vector<VuoPublishedPort *> publishedInputPorts = composition->getBase()->getPublishedInputPorts();
825  vector<VuoCompilerInputEventPort *> inputEventPorts;
826 
827  // Copy data from the function arguments to the published input node's input ports.
828 
829  for (size_t i = 0; i < publishedInputPorts.size(); ++i)
830  {
831  VuoPublishedPort *publishedInputPort = publishedInputPorts[i];
832 
833  VuoPort *inputPort = graph->getInputPortOnPublishedInputNode(i);
834  VuoCompilerInputEventPort *inputEventPort = static_cast<VuoCompilerInputEventPort *>( inputPort->getCompiler() );
835  inputEventPorts.push_back(inputEventPort);
836 
837  if (publishedInputPort->getClass()->getPortType() == VuoPortClass::dataAndEventPort)
838  {
839  size_t dataArgIndex = indexOfParameter[ modelInputPorts[i] ];
840  VuoCompilerType *type = static_cast<VuoCompilerPort *>( publishedInputPort->getCompiler() )->getDataVuoType()->getCompiler();
841 
842  // If the argument is a struct that would normally be passed "byval", it's not "byval" here.
843  // Instead, the Vuo compiler has implemented the "byval" semantics in the caller, which
844  // has passed a struct pointer that is effectively passed by value but not marked as such.
845  //
846  // This is a workaround for a bug where LLVM would sometimes give the node function body
847  // an invalid value for a "byval" struct argument. https://b33p.net/kosada/node/11386
848  Value *dataArg;
849  if (type->getType()->isStructTy() &&
850  type->getFunctionParameterAttributes().hasAttrSomewhere(Attribute::ByVal))
851  {
852  Value *argAsPointerToOtherType = VuoCompilerCodeGenUtilities::getArgumentAtIndex(function, dataArgIndex);
853  Value *argAsPointer = new BitCastInst(argAsPointerToOtherType, type->getType()->getPointerTo(), "", block);
854  dataArg = new LoadInst(argAsPointer, "", block);
855  }
856  else
857  {
858  dataArg = VuoCompilerCodeGenUtilities::unlowerArgument(type, function, dataArgIndex, module, block);
859  }
860 
861  inputEventPort->generateReplaceData(module, block, publishedNodeContextValue, dataArg);
862  }
863  }
864 
865  // Transmit data through the published input node and onward through the published input cables.
866  // (This temporarily sets an event on all of the published input node's input ports.)
867 
868  generateDataOnlyTransmissionFromNode(function, block, compositionStateValue, publishedInputNode,
869  shouldWaitForDataOnlyDownstreamNodes, shouldUpdateTriggers, shouldSendTelemetry);
870 
871  // Copy events from the function arguments to the published input node's input ports.
872 
873  for (size_t i = 0; i < publishedInputPorts.size(); ++i)
874  {
875  VuoCompilerInputEventPort *inputEventPort = inputEventPorts[i];
876 
877  map<VuoPort *, size_t> *indexMap = (inputEventPort->getBase()->getClass()->getPortType() == VuoPortClass::dataAndEventPort ?
878  &indexOfEventParameter :
879  &indexOfParameter);
880 
881  auto foundIndex = indexMap->find( modelInputPorts[i] );
882  if (foundIndex != indexMap->end())
883  {
884  size_t eventArgIndex = foundIndex->second;
885  Value *eventArg = VuoCompilerCodeGenUtilities::getArgumentAtIndex(function, eventArgIndex);
886 
887  inputEventPort->generateStoreEvent(module, block, publishedNodeContextValue, eventArg);
888  }
889  }
890 }
891 
900 void VuoCompilerBitcodeGenerator::generateNodeEventFunction(bool isStatefulComposition)
901 {
902  vector<VuoPort *> modelPorts;
903  modelPorts.insert(modelPorts.end(), modelInputPorts.begin(), modelInputPorts.end());
904  modelPorts.insert(modelPorts.end(), modelOutputPorts.begin(), modelOutputPorts.end());
905 
906  vector<VuoPublishedPort *> publishedInputPorts = composition->getBase()->getPublishedInputPorts();
907  vector<VuoPublishedPort *> publishedOutputPorts = composition->getBase()->getPublishedOutputPorts();
908  vector<VuoPublishedPort *> publishedPorts;
909  publishedPorts.insert(publishedPorts.end(), publishedInputPorts.begin(), publishedInputPorts.end());
910  publishedPorts.insert(publishedPorts.end(), publishedOutputPorts.begin(), publishedOutputPorts.end());
911 
912  map<VuoPort *, string> displayNamesForPorts;
913  map<VuoPort *, json_object *> detailsForPorts;
914  for (size_t i = 0; i < modelPorts.size(); ++i)
915  {
916  VuoPort *modelPort = modelPorts[i];
917  VuoPublishedPort *publishedPort = publishedPorts[i];
918 
919  string portName = modelPort->getClass()->getName();
920  bool isAllCaps = true;
921  for (size_t j = 0; j < portName.length(); ++j)
922  if (! isupper(portName[j]))
923  {
924  isAllCaps = false;
925  break;
926  }
927  if (isAllCaps)
928  displayNamesForPorts[modelPort] = portName;
929 
930  detailsForPorts[modelPort] = static_cast<VuoCompilerPortClass *>( publishedPort->getClass()->getCompiler() )->getDetails();
931  }
932 
933  map<VuoPort *, string> defaultValuesForInputPorts;
934  map<VuoPort *, VuoPortClass::EventBlocking> eventBlockingForInputPorts;
935  for (size_t i = 0; i < publishedInputPorts.size(); ++i)
936  {
937  VuoPublishedPort *publishedInputPort = publishedInputPorts[i];
938 
939  string defaultValue = static_cast<VuoCompilerPublishedPort *>( publishedInputPort->getCompiler() )->getInitialValue();
940  if (! defaultValue.empty())
941  defaultValuesForInputPorts[publishedInputPort] = defaultValue;
942 
943  eventBlockingForInputPorts[publishedInputPort] = graph->getPublishedInputEventBlocking(i);
944  }
945 
946  map<VuoPort *, size_t> indexOfParameter;
947  map<VuoPort *, size_t> indexOfEventParameter;
948  Function *function = VuoCompilerCodeGenUtilities::getNodeEventFunction(module, moduleKey, true, isStatefulComposition,
950  modelInputPorts, modelOutputPorts,
951  detailsForPorts, displayNamesForPorts,
952  defaultValuesForInputPorts, eventBlockingForInputPorts,
953  indexOfParameter, indexOfEventParameter, constantsCache);
954  BasicBlock *block = &(function->getEntryBlock());
955 
957  if (! trigger)
958  {
959  ReturnInst::Create(module->getContext(), block);
960  return;
961  }
962 
963  VuoCompilerNode *triggerNode = graph->getNodeForTriggerPort(trigger);
964 
965  Value *compositionStateValue = function->arg_begin();
966  Value *compositionContextValue = VuoCompilerCodeGenUtilities::generateGetCompositionContext(module, block, compositionStateValue);
967 
968  // Get the event ID passed down from the composition containing this subcomposition node.
969 
970  Value *eventIdValue = VuoCompilerCodeGenUtilities::generateGetOneExecutingEvent(module, block, compositionContextValue);
971 
972  // Claim all necessary downstream nodes.
973 
974  vector<VuoCompilerNode *> triggerWaitNodes = getNodesToWaitOnBeforeTransmission(trigger);
975  generateLockNodes(module, block, compositionStateValue, triggerWaitNodes, eventIdValue);
976 
977  // Set the data and event for each input port on the published input node from the input arguments.
978 
979  bool hasClaimedNodesDownstreamOfPublishedInputNode = (triggerWaitNodes.size() > 2);
980  generateSetInputDataFromNodeFunctionArguments(function, block, compositionStateValue, indexOfParameter, indexOfEventParameter,
981  ! hasClaimedNodesDownstreamOfPublishedInputNode, true, true);
982 
983  // Wait for the event to reach the published output node (if any) and all other leaf nodes — part 1.
984 
985  Value *subcompositionOutputGroupValue = VuoCompilerCodeGenUtilities::generateGetNodeContextExecutingGroup(module, block, compositionContextValue);
986  VuoCompilerCodeGenUtilities::generateEnterDispatchGroup(module, block, subcompositionOutputGroupValue);
987 
988  // Fire an event from the published input trigger.
989 
990  Value *triggerNodeContextValue = triggerNode->generateGetContext(module, block, compositionStateValue);
991  Value *triggerFunctionValue = trigger->generateLoadFunction(module, block, triggerNodeContextValue);
992  CallInst::Create(triggerFunctionValue, "", block);
993 
994  // Wait for the event to reach the published output node (if any) and all other leaf nodes — part 2.
995 
996  VuoCompilerCodeGenUtilities::generateWaitForDispatchGroup(module, block, subcompositionOutputGroupValue);
997 
998  // Set each output argument from the published output port values.
999 
1000  VuoCompilerNode *publishedOutputNode = graph->getPublishedOutputNode();
1001  Value *publishedOutputNodeContext = publishedOutputNode->generateGetContext(module, block, compositionStateValue);
1002  for (size_t i = 0; i < modelOutputPorts.size(); ++i)
1003  {
1004  VuoPort *modelOutputPort = modelOutputPorts[i];
1005  VuoPortClass::PortType portType = modelOutputPort->getClass()->getPortType();
1006 
1007  if (portType == VuoPortClass::dataAndEventPort || portType == VuoPortClass::eventOnlyPort)
1008  {
1009  VuoPort *inputPort = graph->getInputPortOnPublishedOutputNode(i);
1010  bool hasEventParameter = false;
1011  size_t eventIndex = 0;
1012 
1013  if (portType == VuoPortClass::dataAndEventPort)
1014  {
1015  size_t index = indexOfParameter[ modelOutputPort ];
1016  Value *outputArg = VuoCompilerCodeGenUtilities::getArgumentAtIndex(function, index);
1017 
1018  Value *value = static_cast<VuoCompilerEventPort *>( inputPort->getCompiler() )->generateLoadData(module, block, publishedOutputNodeContext);
1019  new StoreInst(value, outputArg, block);
1020 
1021  map<VuoPort *, size_t>::iterator iter = indexOfEventParameter.find(modelOutputPort);
1022  if (iter != indexOfEventParameter.end())
1023  {
1024  hasEventParameter = true;
1025  eventIndex = iter->second;
1026  }
1027  }
1028  else
1029  {
1030  hasEventParameter = true;
1031  eventIndex = indexOfParameter[ modelOutputPort ];
1032  }
1033 
1034  if (hasEventParameter)
1035  {
1036  Value *outputArg = VuoCompilerCodeGenUtilities::getArgumentAtIndex(function, eventIndex);
1037 
1038  Value *eventValue = VuoCompilerCodeGenUtilities::generateGetNodeContextOutputEvent(module, block, compositionContextValue, i);
1039  new StoreInst(eventValue, outputArg, block);
1040  }
1041  }
1042  }
1043 
1044  // Signal the published output node.
1045 
1046  generateUnlockNodes(module, block, compositionStateValue, vector<VuoCompilerNode *>(1, publishedOutputNode));
1047 
1048  ReturnInst::Create(module->getContext(), block);
1049 }
1050 
1056 void VuoCompilerBitcodeGenerator::generateNodeInstanceInitFunction(void)
1057 {
1058  vector<VuoPort *> inputPorts;
1059  if (! isTopLevelComposition)
1060  inputPorts = modelInputPorts;
1061 
1062  map<VuoPort *, size_t> indexOfParameter;
1063  Function *function = VuoCompilerCodeGenUtilities::getNodeInstanceInitFunction(module, moduleKey, true,
1065  inputPorts, indexOfParameter, constantsCache);
1066  BasicBlock *block = &(function->getEntryBlock());
1067 
1068  Value *compositionStateValue = function->arg_begin();
1069 
1070  if (! isTopLevelComposition)
1071  generateSetInputDataFromNodeFunctionArguments(function, block, compositionStateValue, indexOfParameter, map<VuoPort *, size_t>(),
1072  false, false, false);
1073 
1074  for (VuoCompilerNode *node : graph->getNodes())
1075  {
1076  if (node->getBase()->getNodeClass()->getCompiler()->isStateful())
1077  {
1078  BasicBlock *initBlock = NULL;
1079  BasicBlock *nextBlock = NULL;
1080  Value *replacementJsonValue = NULL;
1082  compositionStateValue, block, initBlock, nextBlock,
1083  constantsCache, replacementJsonValue);
1084 
1085  node->generateInitFunctionCall(module, initBlock, compositionStateValue);
1086 
1087  VuoCompilerCodeGenUtilities::generateJsonObjectPut(module, initBlock, replacementJsonValue);
1088 
1089  BranchInst::Create(nextBlock, initBlock);
1090  block = nextBlock;
1091  }
1092  }
1093 
1094  PointerType *instanceDataType = static_cast<PointerType *>( function->getReturnType() );
1095  ConstantPointerNull *nullInstanceDataValue = ConstantPointerNull::get(instanceDataType);
1096  ReturnInst::Create(module->getContext(), nullInstanceDataValue, block);
1097 }
1098 
1105 void VuoCompilerBitcodeGenerator::generateNodeInstanceFiniFunction(void)
1106 {
1107  Function *function = VuoCompilerCodeGenUtilities::getNodeInstanceFiniFunction(module, moduleKey,
1109  constantsCache);
1110  BasicBlock *block = &(function->getEntryBlock());
1111 
1112  Value *compositionStateValue = function->arg_begin();
1113 
1114  for (VuoCompilerNode *node : graph->getNodes())
1115  {
1116  if (node->getBase()->getNodeClass()->getCompiler()->isStateful())
1117  {
1118  BasicBlock *finiBlock = NULL;
1119  BasicBlock *nextBlock = NULL;
1120  Value *replacementJsonValue = NULL;
1122  compositionStateValue, block, finiBlock, nextBlock,
1123  constantsCache, replacementJsonValue);
1124 
1125  node->generateFiniFunctionCall(module, finiBlock, compositionStateValue);
1126 
1127  VuoCompilerCodeGenUtilities::generateJsonObjectPut(module, finiBlock, replacementJsonValue);
1128 
1129  BranchInst::Create(nextBlock, finiBlock);
1130  block = nextBlock;
1131  }
1132  }
1133 
1134  ReturnInst::Create(module->getContext(), block);
1135 }
1136 
1144 void VuoCompilerBitcodeGenerator::generateNodeInstanceTriggerStartFunction(void)
1145 {
1146  vector<VuoPort *> inputPorts;
1147  if (! isTopLevelComposition)
1148  inputPorts = modelInputPorts;
1149 
1150  map<VuoPort *, size_t> indexOfParameter;
1151  Function *function = VuoCompilerCodeGenUtilities::getNodeInstanceTriggerStartFunction(module, moduleKey,
1153  inputPorts, indexOfParameter, constantsCache);
1154  BasicBlock *block = &(function->getEntryBlock());
1155 
1156  Value *compositionStateValue = function->arg_begin();
1157 
1158  if (! isTopLevelComposition)
1159  generateSetInputDataFromNodeFunctionArguments(function, block, compositionStateValue, indexOfParameter, map<VuoPort *, size_t>(),
1160  false, false, false);
1161 
1162  // Since a node's nodeInstanceTriggerStart() function can generate an event,
1163  // make sure trigger functions wait until all nodes' init functions have completed.
1164  generateLockNodes(module, block, compositionStateValue, orderedNodes);
1165 
1166  for (VuoCompilerNode *node : graph->getNodes())
1167  {
1168  if (node->getBase()->getNodeClass()->getCompiler()->isStateful())
1169  {
1170  // { /* call nodeInstanceTriggerStart() for node */ }
1171  node->generateCallbackStartFunctionCall(module, block, compositionStateValue);
1172  }
1173  }
1174 
1175  generateUnlockNodes(module, block, compositionStateValue, orderedNodes);
1176 
1177  ReturnInst::Create(module->getContext(), block);
1178 }
1179 
1185 void VuoCompilerBitcodeGenerator::generateNodeInstanceTriggerStopFunction(void)
1186 {
1187  Function *function = VuoCompilerCodeGenUtilities::getNodeInstanceTriggerStopFunction(module, moduleKey,
1189  constantsCache);
1190  BasicBlock *block = &(function->getEntryBlock());
1191 
1192  Value *compositionStateValue = function->arg_begin();
1193 
1194  // Stop all triggers from firing events — call nodeInstanceTriggerStop() for each stateful node.
1195  generateLockNodes(module, block, compositionStateValue, orderedNodes);
1196  for (VuoCompilerNode *node : graph->getNodes())
1197  {
1198  if (node->getBase()->getNodeClass()->getCompiler()->isStateful())
1199  node->generateCallbackStopFunctionCall(module, block, compositionStateValue);
1200  }
1201  generateUnlockNodes(module, block, compositionStateValue, orderedNodes);
1202 
1203  if (isTopLevelComposition)
1204  {
1205  // Wait for any scheduled trigger workers to launch events into the composition.
1206  Value *triggerWorkersScheduledValue = VuoCompilerCodeGenUtilities::getTriggerWorkersScheduledValue(module, block, compositionStateValue);
1207  VuoCompilerCodeGenUtilities::generateWaitForDispatchGroup(module, block, triggerWorkersScheduledValue);
1208 
1209  // Wait for any in-progress events to travel through the composition.
1210  generateLockNodes(module, block, compositionStateValue, orderedNodes);
1211  generateUnlockNodes(module, block, compositionStateValue, orderedNodes);
1212  }
1213 
1214  ReturnInst::Create(module->getContext(), block);
1215 }
1216 
1222 void VuoCompilerBitcodeGenerator::generateNodeInstanceTriggerUpdateFunction(void)
1223 {
1224  map<VuoPort *, size_t> indexOfParameter;
1225  Function *function = VuoCompilerCodeGenUtilities::getNodeInstanceTriggerUpdateFunction(module, moduleKey,
1227  modelInputPorts, indexOfParameter, constantsCache);
1228  BasicBlock *block = &(function->getEntryBlock());
1229 
1230  Value *compositionStateValue = function->arg_begin();
1231 
1233  if (! trigger)
1234  {
1235  ReturnInst::Create(module->getContext(), block);
1236  return;
1237  }
1238 
1239  vector<VuoCompilerNode *> triggerWaitNodes = getNodesToWaitOnBeforeTransmission(trigger);
1240  generateLockNodes(module, block, compositionStateValue, triggerWaitNodes);
1241 
1242  bool hasClaimedNodesDownstreamOfPublishedInputNode = (triggerWaitNodes.size() > 2);
1243  generateSetInputDataFromNodeFunctionArguments(function, block, compositionStateValue, indexOfParameter, map<VuoPort *, size_t>(),
1244  ! hasClaimedNodesDownstreamOfPublishedInputNode, true, true);
1245 
1246  generateUnlockNodes(module, block, compositionStateValue, triggerWaitNodes);
1247 
1248  ReturnInst::Create(module->getContext(), block);
1249 }
1250 
1254 void VuoCompilerBitcodeGenerator::generateLockNodes(Module *module, BasicBlock *block,
1255  Value *compositionStateValue, vector<VuoCompilerNode *> nodes,
1256  Value *eventIdValue)
1257 {
1258  if (nodes.empty())
1259  return;
1260 
1261  if (! eventIdValue)
1262  eventIdValue = VuoCompilerCodeGenUtilities::generateGetNextEventId(module, block, compositionStateValue);
1263 
1264  if (nodes.size() == 1)
1265  {
1266  size_t nodeIndex = nodes[0]->getIndexInOrderedNodes();
1267  VuoCompilerCodeGenUtilities::generateLockNode(module, block, compositionStateValue, nodeIndex, eventIdValue);
1268  }
1269  else
1270  {
1271  sortNodes(nodes);
1272 
1273  vector<size_t> nodeIndices;
1274  std::transform(nodes.begin(), nodes.end(), std::back_inserter(nodeIndices), [](VuoCompilerNode *n) { return n->getIndexInOrderedNodes(); });
1275 
1276  VuoCompilerCodeGenUtilities::generateLockNodes(module, block, compositionStateValue, nodeIndices, eventIdValue, constantsCache);
1277  }
1278 }
1279 
1283 void VuoCompilerBitcodeGenerator::generateUnlockNodes(Module *module, BasicBlock *block, Value *compositionStateValue,
1284  vector<VuoCompilerNode *> nodes)
1285 {
1286  if (nodes.empty())
1287  return;
1288 
1289  if (nodes.size() == 1)
1290  {
1291  size_t nodeIndex = nodes[0]->getIndexInOrderedNodes();
1292  VuoCompilerCodeGenUtilities::generateUnlockNode(module, block, compositionStateValue, nodeIndex);
1293  }
1294  else
1295  {
1296  vector<size_t> nodeIndices;
1297  std::transform(nodes.begin(), nodes.end(), std::back_inserter(nodeIndices), [](VuoCompilerNode *n) { return n->getIndexInOrderedNodes(); });
1298 
1299  VuoCompilerCodeGenUtilities::generateUnlockNodes(module, block, compositionStateValue, nodeIndices, constantsCache);
1300  }
1301 }
1302 
1367 void VuoCompilerBitcodeGenerator::generateCompositionGetPortValueFunction(void)
1368 {
1370 
1371  Function::arg_iterator args = function->arg_begin();
1372  Value *compositionStateValue = args++;
1373  compositionStateValue->setName("compositionState");
1374  Value *portIdentifierValue = args++;
1375  portIdentifierValue->setName("portIdentifier");
1376  Value *serializationTypeValue = args++;
1377  serializationTypeValue->setName("serializationType");
1378  Value *isThreadSafeValue = args++;
1379  isThreadSafeValue->setName("isThreadSafe");
1380 
1381 
1382  // char *ret = NULL;
1383 
1384  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, 0);
1385  PointerType *pointerToCharType = PointerType::get(IntegerType::get(module->getContext(), 8), 0);
1386 
1387  AllocaInst *retVariable = new AllocaInst(pointerToCharType, "ret", initialBlock);
1388  ConstantPointerNull *nullPointerToChar = ConstantPointerNull::get(pointerToCharType);
1389  new StoreInst(nullPointerToChar, retVariable, false, initialBlock);
1390 
1391  // void *portAddress = vuoGetDataForPort(compositionState, portIdentifier);
1392 
1393  Value *portAddressAsVoidPointer = VuoCompilerCodeGenUtilities::generateGetDataForPort(module, initialBlock, compositionStateValue, portIdentifierValue);
1394 
1395  // if (portAddress != NULL)
1396 
1397  BasicBlock *checkWaitBlock = BasicBlock::Create(module->getContext(), "checkWait", function, 0);
1398  BasicBlock *finalBlock = BasicBlock::Create(module->getContext(), "final", function, 0);
1399 
1400  ConstantPointerNull *nullPortAddress = ConstantPointerNull::get(static_cast<PointerType *>(portAddressAsVoidPointer->getType()));
1401  ICmpInst *portAddressNotEqualsNull = new ICmpInst(*initialBlock, ICmpInst::ICMP_NE, portAddressAsVoidPointer, nullPortAddress, "");
1402  BranchInst::Create(checkWaitBlock, finalBlock, portAddressNotEqualsNull, initialBlock);
1403 
1404  // unsigned long typeIndex = vuoGetTypeIndexForPort(compositionState, portIdentifier);
1405  // unsigned long nodeIndex = vuoGetNodeIndexForPort(compositionState, portIdentifier);
1406 
1407  Value *typeIndexValue = VuoCompilerCodeGenUtilities::generateGetTypeIndexForPort(module, checkWaitBlock, compositionStateValue, portIdentifierValue);
1408  Value *nodeIndexValue = VuoCompilerCodeGenUtilities::generateGetNodeIndexForPort(module, checkWaitBlock, compositionStateValue, portIdentifierValue);
1409 
1410  // if (isThreadSafe)
1411  // {
1412  // unsigned long eventId = vuoGetNextEventId();
1413  // vuoLockNode(compositionState, nodeIndex, eventId);
1414  // }
1415 
1416  BasicBlock *waitBlock = BasicBlock::Create(module->getContext(), "wait", function, 0);
1417  BasicBlock *checkTypeIndexBlock = BasicBlock::Create(module->getContext(), "checkTypeIndex", function, 0);
1418  ConstantInt *falseValue = ConstantInt::get(static_cast<IntegerType *>(isThreadSafeValue->getType()), 0);
1419  ICmpInst *isThreadSafeEqualsTrue = new ICmpInst(*checkWaitBlock, ICmpInst::ICMP_NE, isThreadSafeValue, falseValue, "");
1420  BranchInst::Create(waitBlock, checkTypeIndexBlock, isThreadSafeEqualsTrue, checkWaitBlock);
1421 
1422  Value *eventIdValue = VuoCompilerCodeGenUtilities::generateGetNextEventId(module, waitBlock, compositionStateValue);
1423  VuoCompilerCodeGenUtilities::generateLockNode(module, waitBlock, compositionStateValue, nodeIndexValue, eventIdValue);
1424  BranchInst::Create(checkTypeIndexBlock, waitBlock);
1425 
1426 
1427  // if (typeIndex == 0)
1428  // {
1429  // VuoImage portValue = (VuoImage)(*portAddress);
1430  // if (serializationType == 0)
1431  // ret = VuoImage_getSummary(portValue);
1432  // else if (serializationType == 1)
1433  // ret = VuoImage_getString(portValue);
1434  // else
1435  // ret = VuoImage_getInterprocessString(portValue);
1436  // }
1437  // else if (typeIndex == 3)
1438  // {
1439  // VuoReal portValue = (VuoReal)(*portAddress);
1440  // if (serializationType == 0)
1441  // ret = VuoReal_getSummary(portValue);
1442  // else
1443  // ret = VuoReal_getString(portValue);
1444  // }
1445  // else if ...
1446 
1447  vector< pair<BasicBlock *, BasicBlock *> > blocksForIndex;
1448  for (size_t i = 0; i < orderedTypes.size(); ++i)
1449  {
1450  VuoCompilerType *type = orderedTypes[i];
1451 
1452  string typeName = type->getBase()->getModuleKey();
1453  bool hasInterprocess = type->hasInterprocessStringFunction();
1454 
1455  BasicBlock *checkSummaryBlock = BasicBlock::Create(module->getContext(), typeName + "_checkSummary", function, 0);
1456  BasicBlock *summaryBlock = BasicBlock::Create(module->getContext(), typeName + "_summary", function, 0);
1457  BasicBlock *checkStringBlock = NULL;
1458  BasicBlock *stringBlock = BasicBlock::Create(module->getContext(), typeName + "_string", function, 0);
1459  BasicBlock *interprocessBlock = NULL;
1460  BasicBlock *typeFinalBlock = BasicBlock::Create(module->getContext(), typeName + "_final", function, 0);
1461 
1462  BasicBlock *firstStringBlock = NULL;
1463  if (hasInterprocess)
1464  {
1465  checkStringBlock = BasicBlock::Create(module->getContext(), typeName + "_checkString", function, 0);
1466  interprocessBlock = BasicBlock::Create(module->getContext(), typeName + "_interprocess", function, 0);
1467  firstStringBlock = checkStringBlock;
1468  }
1469  else
1470  {
1471  firstStringBlock = stringBlock;
1472  }
1473 
1474  PointerType *pointerToType = PointerType::get(type->getType(), 0);
1475  Value *portAddress = new BitCastInst(portAddressAsVoidPointer, pointerToType, "", checkSummaryBlock);
1476  Value *portValue = new LoadInst(portAddress, "", false, checkSummaryBlock);
1477 
1478  ConstantInt *zeroValue = ConstantInt::get(static_cast<IntegerType *>(serializationTypeValue->getType()), 0);
1479  ICmpInst *serializationTypeEqualsZero = new ICmpInst(*checkSummaryBlock, ICmpInst::ICMP_EQ, serializationTypeValue, zeroValue, "");
1480  BranchInst::Create(summaryBlock, firstStringBlock, serializationTypeEqualsZero, checkSummaryBlock);
1481 
1482  Value *summaryValue = type->generateSummaryFromValueFunctionCall(module, summaryBlock, portValue);
1483  new StoreInst(summaryValue, retVariable, summaryBlock);
1484  BranchInst::Create(typeFinalBlock, summaryBlock);
1485 
1486  if (hasInterprocess)
1487  {
1488  ConstantInt *oneValue = ConstantInt::get(static_cast<IntegerType *>(serializationTypeValue->getType()), 1);
1489  ICmpInst *serializationTypeEqualsOne = new ICmpInst(*checkStringBlock, ICmpInst::ICMP_EQ, serializationTypeValue, oneValue, "");
1490  BranchInst::Create(stringBlock, interprocessBlock, serializationTypeEqualsOne, checkStringBlock);
1491  }
1492 
1493  Value *stringValue = type->generateStringFromValueFunctionCall(module, stringBlock, portValue);
1494  new StoreInst(stringValue, retVariable, stringBlock);
1495  BranchInst::Create(typeFinalBlock, stringBlock);
1496 
1497  if (hasInterprocess)
1498  {
1499  Value *interprocessValue = type->generateInterprocessStringFromValueFunctionCall(module, interprocessBlock, portValue);
1500  new StoreInst(interprocessValue, retVariable, interprocessBlock);
1501  BranchInst::Create(typeFinalBlock, interprocessBlock);
1502  }
1503 
1504  blocksForIndex.push_back( make_pair(checkSummaryBlock, typeFinalBlock) );
1505  }
1506 
1507  BasicBlock *checkSignalBlock = BasicBlock::Create(module->getContext(), "checkSignal", function, 0);
1508  VuoCompilerCodeGenUtilities::generateIndexMatchingCode(module, function, checkTypeIndexBlock, checkSignalBlock, typeIndexValue, blocksForIndex);
1509 
1510 
1511  // if (isThreadSafe)
1512  // vuoUnlockNode(compositionState, nodeIndex);
1513 
1514  BasicBlock *signalBlock = BasicBlock::Create(module->getContext(), "signal", function, 0);
1515  BranchInst::Create(signalBlock, finalBlock, isThreadSafeEqualsTrue, checkSignalBlock);
1516 
1517  VuoCompilerCodeGenUtilities::generateUnlockNode(module, signalBlock, compositionStateValue, nodeIndexValue);
1518  BranchInst::Create(finalBlock, signalBlock);
1519 
1520 
1521  // return ret;
1522 
1523  LoadInst *retValue = new LoadInst(retVariable, "", false, finalBlock);
1524  ReturnInst::Create(module->getContext(), retValue, finalBlock);
1525 }
1526 
1605 void VuoCompilerBitcodeGenerator::generateCompositionSetPortValueFunction(void)
1606 {
1608 
1609  Function::arg_iterator args = function->arg_begin();
1610  Value *compositionStateValue = args++;
1611  compositionStateValue->setName("compositionState");
1612  Value *portIdentifierValue = args++;
1613  portIdentifierValue->setName("portIdentifier");
1614  Value *valueAsStringValue = args++;
1615  valueAsStringValue->setName("valueAsString");
1616  Value *isThreadSafeValue = args++;
1617  isThreadSafeValue->setName("isThreadSafe");
1618  Value *shouldUpdateTriggersValue = args++;
1619  shouldUpdateTriggersValue->setName("shouldUpdateTriggers");
1620  Value *shouldSendTelemetryValue = args++;
1621  shouldSendTelemetryValue->setName("shouldSendTelemetry");
1622  Value *hasOldValue = args++;
1623  hasOldValue->setName("hasOldValue");
1624  Value *hasNewValue = args++;
1625  hasNewValue->setName("hasNewValue");
1626 
1627 
1628  // void *portAddress = vuoGetDataForPort(compositionState, portIdentifier);
1629 
1630  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, 0);
1631  Value *portAddressAsVoidPointer = VuoCompilerCodeGenUtilities::generateGetDataForPort(module, initialBlock, compositionStateValue, portIdentifierValue);
1632 
1633  // if (portAddress != NULL)
1634 
1635  BasicBlock *checkWaitBlock = BasicBlock::Create(module->getContext(), "checkWait", function, 0);
1636  BasicBlock *finalBlock = BasicBlock::Create(module->getContext(), "final", function, 0);
1637 
1638  ConstantPointerNull *nullPortAddress = ConstantPointerNull::get(static_cast<PointerType *>(portAddressAsVoidPointer->getType()));
1639  ICmpInst *portAddressNotEqualsNull = new ICmpInst(*initialBlock, ICmpInst::ICMP_NE, portAddressAsVoidPointer, nullPortAddress, "");
1640  BranchInst::Create(checkWaitBlock, finalBlock, portAddressNotEqualsNull, initialBlock);
1641 
1642  // dispatch_semaphore_t nodeSemaphore = vuoGetNodeSemaphoreForPort(compositionState, portIdentifier);
1643  // unsigned long typeIndex = vuoGetTypeIndexForPort(compositionState, portIdentifier);
1644  // unsigned long nodeIndex = vuoGetNodeIndexForPort(compositionState, portIdentifier);
1645  // char *summary = NULL;
1646 
1647  Value *typeIndexValue = VuoCompilerCodeGenUtilities::generateGetTypeIndexForPort(module, checkWaitBlock, compositionStateValue, portIdentifierValue);
1648  Value *nodeIndexValue = VuoCompilerCodeGenUtilities::generateGetNodeIndexForPort(module, checkWaitBlock, compositionStateValue, portIdentifierValue);
1649 
1650  PointerType *pointerToCharType = PointerType::get(IntegerType::get(module->getContext(), 8), 0);
1651  AllocaInst *summaryVariable = new AllocaInst(pointerToCharType, "summary", checkWaitBlock);
1652  ConstantPointerNull *nullSummary = ConstantPointerNull::get(pointerToCharType);
1653  new StoreInst(nullSummary, summaryVariable, false, checkWaitBlock);
1654 
1655  // if (isThreadSafe)
1656  // {
1657  // unsigned long eventId = vuoGetNextEventId();
1658  // vuoLockNode(compositionState, nodeIndex, eventId);
1659  // }
1660 
1661  BasicBlock *waitBlock = BasicBlock::Create(module->getContext(), "wait", function, 0);
1662  BasicBlock *checkTypeIndexBlock = BasicBlock::Create(module->getContext(), "checkTypeIndex", function, 0);
1663  ConstantInt *falseArgValue = ConstantInt::get(static_cast<IntegerType *>(isThreadSafeValue->getType()), 0);
1664  ICmpInst *isThreadSafeEqualsTrue = new ICmpInst(*checkWaitBlock, ICmpInst::ICMP_NE, isThreadSafeValue, falseArgValue, "");
1665  BranchInst::Create(waitBlock, checkTypeIndexBlock, isThreadSafeEqualsTrue, checkWaitBlock);
1666 
1667  Value *eventIdValue = VuoCompilerCodeGenUtilities::generateGetNextEventId(module, waitBlock, compositionStateValue);
1668  VuoCompilerCodeGenUtilities::generateLockNode(module, waitBlock, compositionStateValue, nodeIndexValue, eventIdValue);
1669  BranchInst::Create(checkTypeIndexBlock, waitBlock);
1670 
1671 
1672  // if (typeIndex == 0)
1673  // {
1674  // VuoText oldPortValue;
1675  // if (hasOldValue)
1676  // oldPortValue = *((VuoText *)portAddress);
1677  // if (hasNewValue)
1678  // {
1679  // VuoText portValue = VuoText_makeFromString(valueAsString);
1680  // *((VuoText *)portAddress) = portValue;
1681  // VuoRetain(portValue);
1682  // if (shouldSendTelemetry)
1683  // summary = VuoText_getSummary(portValue);
1684  // }
1685  // if (hasOldValue)
1686  // VuoRelease(oldPortValue);
1687  // }
1688  // else if (typeIndex == 1)
1689  // {
1690  // if (hasNewValue)
1691  // {
1692  // VuoReal portValue = VuoReal_makeFromString(valueAsString);
1693  // *((VuoReal *)portAddress) = portValue;
1694  // if (shouldSendTelemetry)
1695  // summary = VuoReal_getSummary(portValue);
1696  // }
1697  // }
1698  // else if ...
1699 
1700  ICmpInst *hasOldValueIsTrue = new ICmpInst(*checkTypeIndexBlock, ICmpInst::ICMP_NE, hasOldValue, falseArgValue, "");
1701  ICmpInst *hasNewValueIsTrue = new ICmpInst(*checkTypeIndexBlock, ICmpInst::ICMP_NE, hasNewValue, falseArgValue, "");
1702  ICmpInst *shouldSendTelemetryIsTrue = new ICmpInst(*checkTypeIndexBlock, ICmpInst::ICMP_NE, shouldSendTelemetryValue, falseArgValue, "");
1703 
1704  vector< pair<BasicBlock *, BasicBlock *> > blocksForTypeIndex;
1705  for (size_t i = 0; i < orderedTypes.size(); ++i)
1706  {
1707  VuoCompilerType *type = orderedTypes[i];
1708 
1709  BasicBlock *typeInitialBlock = BasicBlock::Create(module->getContext(), type->getBase()->getModuleKey() + "_initial", function, 0);
1710  Value *portAddress = new BitCastInst(portAddressAsVoidPointer, PointerType::get(type->getType(), 0), "", typeInitialBlock);
1711 
1712  BasicBlock *typeFinalBlock = BasicBlock::Create(module->getContext(), type->getBase()->getModuleKey() + "_final", function, 0);
1713 
1714  BasicBlock *setNewValueBlock = BasicBlock::Create(module->getContext(), "setNewValue", function, 0);
1715  Value *portValue = type->generateValueFromStringFunctionCall(module, setNewValueBlock, valueAsStringValue);
1716  new StoreInst(portValue, portAddress, false, setNewValueBlock);
1717  type->generateRetainCall(module, setNewValueBlock, portValue);
1718 
1719  BasicBlock *summaryBlock = BasicBlock::Create(module->getContext(), "summary", function, 0);
1720  Value *summaryValue = type->generateSummaryFromValueFunctionCall(module, summaryBlock, portValue);
1721  new StoreInst(summaryValue, summaryVariable, false, summaryBlock);
1722 
1724  {
1725  BasicBlock *saveOldValueBlock = BasicBlock::Create(module->getContext(), "saveOldValue", function, 0);
1726  BasicBlock *checkNewValueBlock = BasicBlock::Create(module->getContext(), "checkNewValue", function, 0);
1727  BasicBlock *checkOldValueBlock = BasicBlock::Create(module->getContext(), "checkOldValue", function, 0);
1728  BasicBlock *releaseOldValueBlock = BasicBlock::Create(module->getContext(), "releaseOldValue", function, 0);
1729 
1730  AllocaInst *oldPortValueVariable = new AllocaInst(type->getType(), "oldPortValue", typeInitialBlock);
1731  BranchInst::Create(saveOldValueBlock, checkNewValueBlock, hasOldValueIsTrue, typeInitialBlock);
1732 
1733  Value *oldPortValue = new LoadInst(portAddress, "", false, saveOldValueBlock);
1734  new StoreInst(oldPortValue, oldPortValueVariable, false, saveOldValueBlock);
1735  BranchInst::Create(checkNewValueBlock, saveOldValueBlock);
1736 
1737  BranchInst::Create(setNewValueBlock, checkOldValueBlock, hasNewValueIsTrue, checkNewValueBlock);
1738 
1739  BranchInst::Create(summaryBlock, checkOldValueBlock, shouldSendTelemetryIsTrue, setNewValueBlock);
1740 
1741  BranchInst::Create(checkOldValueBlock, summaryBlock);
1742 
1743  BranchInst::Create(releaseOldValueBlock, typeFinalBlock, hasOldValueIsTrue, checkOldValueBlock);
1744 
1745  oldPortValue = new LoadInst(oldPortValueVariable, "", false, releaseOldValueBlock);
1746  type->generateReleaseCall(module, releaseOldValueBlock, oldPortValue);
1747  BranchInst::Create(typeFinalBlock, releaseOldValueBlock);
1748  }
1749  else
1750  {
1751  BranchInst::Create(setNewValueBlock, typeFinalBlock, hasNewValueIsTrue, typeInitialBlock);
1752 
1753  BranchInst::Create(summaryBlock, typeFinalBlock, shouldSendTelemetryIsTrue, setNewValueBlock);
1754 
1755  BranchInst::Create(typeFinalBlock, summaryBlock);
1756  }
1757 
1758  blocksForTypeIndex.push_back( make_pair(typeInitialBlock, typeFinalBlock) );
1759  }
1760 
1761  BasicBlock *checkUpdateBlock = BasicBlock::Create(module->getContext(), "checkUpdate", function, 0);
1762  VuoCompilerCodeGenUtilities::generateIndexMatchingCode(module, function, checkTypeIndexBlock, checkUpdateBlock, typeIndexValue, blocksForTypeIndex);
1763 
1764 
1765  // if (shouldUpdateTriggers)
1766  // {
1767  // if (nodeIndex == 0)
1768  // {
1769  // Top__FirePeriodically2__fired(...);
1770  // }
1771  // else if ...
1772  // }
1773 
1774  Constant *zeroValue = ConstantInt::get(shouldUpdateTriggersValue->getType(), 0);
1775  ICmpInst *shouldUpdateTriggersIsTrue = new ICmpInst(*checkUpdateBlock, ICmpInst::ICMP_NE, shouldUpdateTriggersValue, zeroValue, "");
1776  BasicBlock *updateTriggersBlock = BasicBlock::Create(module->getContext(), "updateTriggers", function, 0);
1777  BasicBlock *checkSendBlock = BasicBlock::Create(module->getContext(), "checkSend", function, 0);
1778  BranchInst::Create(updateTriggersBlock, checkSendBlock, shouldUpdateTriggersIsTrue, checkUpdateBlock);
1779 
1780  vector< pair<BasicBlock *, BasicBlock *> > blocksForNodeIndex;
1781  for (size_t i = 0; i < orderedNodes.size(); ++i)
1782  {
1783  VuoCompilerNode *node = orderedNodes[i];
1784  BasicBlock *currentBlock = BasicBlock::Create(module->getContext(), node->getIdentifier(), function, 0);
1785  BasicBlock *origCurrentBlock = currentBlock;
1786 
1787  node->generateCallbackUpdateFunctionCall(module, currentBlock, compositionStateValue);
1788 
1789  generateDataOnlyTransmissionFromNode(function, currentBlock, compositionStateValue, node, true, true, true);
1790 
1791  blocksForNodeIndex.push_back( make_pair(origCurrentBlock, currentBlock) );
1792  }
1793 
1794  BasicBlock *checkSignalBlock = BasicBlock::Create(module->getContext(), "checkSignal", function, 0);
1795  VuoCompilerCodeGenUtilities::generateIndexMatchingCode(module, function, updateTriggersBlock, checkSignalBlock, nodeIndexValue, blocksForNodeIndex);
1796 
1797 
1798  // if (isThreadSafe)
1799  // vuoUnlockNode(compositionState, nodeIndex);
1800 
1801  BasicBlock *signalBlock = BasicBlock::Create(module->getContext(), "signal", function, 0);
1802  BranchInst::Create(signalBlock, checkSendBlock, isThreadSafeEqualsTrue, checkSignalBlock);
1803 
1804  VuoCompilerCodeGenUtilities::generateUnlockNode(module, signalBlock, compositionStateValue, nodeIndexValue);
1805  BranchInst::Create(checkSendBlock, signalBlock);
1806 
1807 
1808  // if (shouldSendTelemetry)
1809  // {
1810  // sendInputPortsUpdated(portIdentifier, false, true, summary);
1811  // free(summary);
1812  // }
1813 
1814  BasicBlock *sendBlock = BasicBlock::Create(module->getContext(), "send", function, 0);
1815  BranchInst::Create(sendBlock, finalBlock, shouldSendTelemetryIsTrue, checkSendBlock);
1816 
1817  Value *summaryValue = new LoadInst(summaryVariable, "", false, sendBlock);
1818 
1819  VuoCompilerCodeGenUtilities::generateSendInputPortsUpdated(module, sendBlock, compositionStateValue, portIdentifierValue,
1820  false, true, summaryValue);
1821 
1822  VuoCompilerCodeGenUtilities::generateFreeCall(module, sendBlock, summaryValue);
1823  BranchInst::Create(finalBlock, sendBlock);
1824 
1825  ReturnInst::Create(module->getContext(), finalBlock);
1826 }
1827 
1833 void VuoCompilerBitcodeGenerator::generateSetInputPortValueFunction(void)
1834 {
1835  Function *function = VuoCompilerCodeGenUtilities::getSetInputPortValueFunction(module);
1836  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
1837 
1838  Function::arg_iterator args = function->arg_begin();
1839  Value *portIdentifierValue = args++;
1840  portIdentifierValue->setName("portIdentifier");
1841  Value *valueAsStringValue = args++;
1842  valueAsStringValue->setName("valueAsString");
1843 
1844  Function *compositionSetPortValueFunction = VuoCompilerCodeGenUtilities::getCompositionSetPortValueFunction(module);
1845 
1846  Value *topLevelRuntimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, block);
1847  Value *topLevelCompositionIdentifierValue = constantsCache->get(VuoCompilerComposition::topLevelCompositionIdentifier);
1848  Value *compositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, topLevelRuntimeStateValue, topLevelCompositionIdentifierValue);
1849 
1850  Value *trueValue = ConstantInt::get(compositionSetPortValueFunction->getFunctionType()->getParamType(3), 1);
1851 
1852  vector<Value *> compositionArgs;
1853  compositionArgs.push_back(compositionStateValue);
1854  compositionArgs.push_back(portIdentifierValue);
1855  compositionArgs.push_back(valueAsStringValue);
1856  compositionArgs.push_back(trueValue);
1857  compositionArgs.push_back(trueValue);
1858  compositionArgs.push_back(trueValue);
1859  compositionArgs.push_back(trueValue);
1860  compositionArgs.push_back(trueValue);
1861  CallInst::Create(compositionSetPortValueFunction, compositionArgs, "", block);
1862 
1863  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, compositionStateValue);
1864 
1865  ReturnInst::Create(module->getContext(), block);
1866 }
1867 
1887 void VuoCompilerBitcodeGenerator::generateCompositionFireTriggerPortEventFunction(void)
1888 {
1890 
1891  Function::arg_iterator args = function->arg_begin();
1892  Value *compositionStateValue = args++;
1893  compositionStateValue->setName("compositionState");
1894  Value *portIdentifierValue = args++;
1895  portIdentifierValue->setName("portIdentifier");
1896 
1897  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, 0);
1898 
1899  map<string, pair<BasicBlock *, BasicBlock *> > blocksForString;
1900  for (VuoCompilerTriggerPort *trigger : graph->getTriggerPorts())
1901  {
1902  VuoCompilerNode *triggerNode = graph->getNodeForTriggerPort(trigger);
1903 
1904  string currentPortIdentifier = trigger->getIdentifier();
1905 
1906  BasicBlock *currentBlock = BasicBlock::Create(module->getContext(), currentPortIdentifier, function, 0);
1907  BasicBlock *origCurrentBlock = currentBlock;
1908 
1909  Value *nodeContextValue = triggerNode->generateGetContext(module, currentBlock, compositionStateValue);
1910  Value *triggerFunctionValue = trigger->generateLoadFunction(module, currentBlock, nodeContextValue);
1911 
1912  vector<Value *> triggerArgs;
1913  AttributeSet triggerParamAttributes;
1914  VuoType *dataType = trigger->getDataVuoType();
1915  if (dataType)
1916  {
1917  generateLockNodes(module, currentBlock, compositionStateValue, vector<VuoCompilerNode *>(1, triggerNode));
1918 
1919  Value *arg = trigger->generateLoadPreviousData(module, currentBlock, nodeContextValue);
1920 
1921  FunctionType *triggerFunctionType = trigger->getClass()->getFunctionType();
1922 
1923  Type *secondParam = NULL;
1924  dataType->getCompiler()->getFunctionParameterType(&secondParam);
1925 
1926  triggerParamAttributes = dataType->getCompiler()->getFunctionParameterAttributes();
1927  bool isByVal = triggerParamAttributes.hasAttrSomewhere(Attribute::ByVal);
1928 
1929  Value *secondArg = NULL;
1930  Value **secondArgIfNeeded = (secondParam ? &secondArg : NULL);
1931  arg = VuoCompilerCodeGenUtilities::convertArgumentToParameterType(arg, triggerFunctionType, 0, isByVal, secondArgIfNeeded, module, currentBlock);
1932 
1933  triggerArgs.push_back(arg);
1934  if (secondParam)
1935  triggerArgs.push_back(secondArg);
1936  }
1937 
1938  CallInst *call = CallInst::Create(triggerFunctionValue, triggerArgs, "", currentBlock);
1939  if (dataType)
1940  call->setAttributes(VuoCompilerCodeGenUtilities::copyAttributesToIndex(triggerParamAttributes, 1));
1941 
1942  if (dataType)
1943  generateUnlockNodes(module, currentBlock, compositionStateValue, vector<VuoCompilerNode *>(1, triggerNode));
1944 
1945  blocksForString[currentPortIdentifier] = make_pair(origCurrentBlock, currentBlock);
1946  }
1947 
1948  BasicBlock *finalBlock = BasicBlock::Create(module->getContext(), "final", function, 0);
1949 
1950  ReturnInst::Create(module->getContext(), finalBlock);
1951 
1952  VuoCompilerCodeGenUtilities::generateStringMatchingCode(module, function, initialBlock, finalBlock, portIdentifierValue, blocksForString, constantsCache);
1953 }
1954 
1970 void VuoCompilerBitcodeGenerator::generateGetPublishedPortCountFunction(bool input)
1971 {
1972  size_t count;
1973  string functionName;
1974  if (input)
1975  {
1976  count = composition->getBase()->getPublishedInputPorts().size();
1977  functionName = "getPublishedInputPortCount";
1978  }
1979  else
1980  {
1981  count = composition->getBase()->getPublishedOutputPorts().size();
1982  functionName = "getPublishedOutputPortCount";
1983  }
1984 
1985  Function *function = module->getFunction(functionName);
1986  if (! function)
1987  {
1988  vector<Type *> functionParams;
1989  FunctionType *functionType = FunctionType::get(IntegerType::get(module->getContext(), 32), functionParams, false);
1990  function = Function::Create(functionType, GlobalValue::ExternalLinkage, functionName, module);
1991  }
1992 
1993  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, 0);
1994  ConstantInt *countConstant = ConstantInt::get(module->getContext(), APInt(32, count));
1995  ReturnInst::Create(module->getContext(), countConstant, block);
1996 }
1997 
2013 void VuoCompilerBitcodeGenerator::generateGetPublishedPortNamesFunction(bool input)
2014 {
2015  string functionName;
2016  vector<VuoPublishedPort *> publishedPorts;
2017  if (input)
2018  {
2019  functionName = "getPublishedInputPortNames";
2020  publishedPorts = composition->getBase()->getPublishedInputPorts();
2021  }
2022  else
2023  {
2024  functionName = "getPublishedOutputPortNames";
2025  publishedPorts = composition->getBase()->getPublishedOutputPorts();
2026  }
2027 
2028  vector<string> names;
2029  for (vector<VuoPublishedPort *>::iterator i = publishedPorts.begin(); i != publishedPorts.end(); ++i)
2030  {
2031  names.push_back( (*i)->getClass()->getName() );
2032  }
2033 
2034  generateFunctionReturningStringArray(functionName, names);
2035 }
2036 
2052 void VuoCompilerBitcodeGenerator::generateGetPublishedPortTypesFunction(bool input)
2053 {
2054  string functionName;
2055  vector<VuoPublishedPort *> publishedPorts;
2056  if (input)
2057  {
2058  functionName = "getPublishedInputPortTypes";
2059  publishedPorts = composition->getBase()->getPublishedInputPorts();
2060  }
2061  else
2062  {
2063  functionName = "getPublishedOutputPortTypes";
2064  publishedPorts = composition->getBase()->getPublishedOutputPorts();
2065  }
2066 
2067  vector<string> types;
2068  for (vector<VuoPublishedPort *>::iterator i = publishedPorts.begin(); i != publishedPorts.end(); ++i)
2069  {
2070  VuoCompilerPublishedPort *publishedPort = static_cast<VuoCompilerPublishedPort *>((*i)->getCompiler());
2071 
2072  VuoType *type = publishedPort->getDataVuoType();
2073  string typeName = type ? type->getModuleKey() : "";
2074  types.push_back(typeName);
2075  }
2076 
2077  generateFunctionReturningStringArray(functionName, types);
2078 }
2079 
2095 void VuoCompilerBitcodeGenerator::generateGetPublishedPortDetailsFunction(bool input)
2096 {
2097  string functionName;
2098  vector<VuoPublishedPort *> publishedPorts;
2099  if (input)
2100  {
2101  functionName = "getPublishedInputPortDetails";
2102  publishedPorts = composition->getBase()->getPublishedInputPorts();
2103  }
2104  else
2105  {
2106  functionName = "getPublishedOutputPortDetails";
2107  publishedPorts = composition->getBase()->getPublishedOutputPorts();
2108  }
2109 
2110  vector<string> details;
2111  for (vector<VuoPublishedPort *>::iterator i = publishedPorts.begin(); i != publishedPorts.end(); ++i)
2112  {
2113  VuoCompilerPublishedPort *publishedPort = static_cast<VuoCompilerPublishedPort *>((*i)->getCompiler());
2114 
2115  json_object *detailsObj = publishedPort->getDetails(input);
2116  string detailsSerialized = json_object_to_json_string_ext(detailsObj, JSON_C_TO_STRING_PLAIN);
2117  details.push_back(detailsSerialized);
2118 
2119  json_object_put(detailsObj);
2120  }
2121 
2122  generateFunctionReturningStringArray(functionName, details);
2123 }
2124 
2131 void VuoCompilerBitcodeGenerator::generateFunctionReturningStringArray(string functionName, vector<string> stringValues)
2132 {
2133  Function *function = module->getFunction(functionName);
2134  if (! function)
2135  {
2136  PointerType *pointerToChar = PointerType::get(IntegerType::get(module->getContext(), 8), 0);
2137  PointerType *pointerToPointerToChar = PointerType::get(pointerToChar, 0);
2138  vector<Type *> functionParams;
2139  FunctionType *functionType = FunctionType::get(pointerToPointerToChar, functionParams, false);
2140  function = Function::Create(functionType, GlobalValue::ExternalLinkage, functionName, module);
2141  }
2142 
2143  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, 0);
2144 
2145  Constant *stringArrayGlobalPointer = VuoCompilerCodeGenUtilities::generatePointerToConstantArrayOfStrings(module, stringValues);
2146  ReturnInst::Create(module->getContext(), stringArrayGlobalPointer, block);
2147 }
2148 
2158 void VuoCompilerBitcodeGenerator::generateFirePublishedInputPortEventFunction(void)
2159 {
2160  string functionName = "firePublishedInputPortEvent";
2161  Function *function = module->getFunction(functionName);
2162  if (! function)
2163  {
2164  PointerType *pointerToChar = PointerType::get(IntegerType::get(module->getContext(), 8), 0);
2165  PointerType *pointerToPointerToChar = PointerType::get(pointerToChar, 0);
2166  Type *countType = IntegerType::get(module->getContext(), 32);
2167 
2168  vector<Type *> functionParams;
2169  functionParams.push_back(pointerToPointerToChar);
2170  functionParams.push_back(countType);
2171  FunctionType *functionType = FunctionType::get(Type::getVoidTy(module->getContext()), functionParams, false);
2172  function = Function::Create(functionType, GlobalValue::ExternalLinkage, functionName, module);
2173  }
2174 
2175  Function::arg_iterator args = function->arg_begin();
2176  Value *namesValue = args++;
2177  namesValue->setName("names");
2178  Value *countValue = args++;
2179  countValue->setName("count");
2180 
2181  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, 0);
2182 
2184  if (! trigger)
2185  {
2186  ReturnInst::Create(module->getContext(), initialBlock);
2187  return;
2188  }
2189 
2190  VuoCompilerNode *triggerNode = graph->getNodeForTriggerPort(trigger);
2191 
2192  Value *runtimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, initialBlock);
2193  Value *compositionIdentifierValue = constantsCache->get(VuoCompilerComposition::topLevelCompositionIdentifier);
2194  Value *compositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, initialBlock, runtimeStateValue,
2195  compositionIdentifierValue);
2196 
2197  // Create an event ID so the nodes claimed by this function can be used (re-claimed) by the trigger worker.
2198 
2199  Value *eventIdValue = VuoCompilerCodeGenUtilities::generateGetNextEventId(module, initialBlock, compositionStateValue);
2200 
2201  // Claim all necessary downstream nodes —
2202  // including the published output node to synchronize access to the composition's node context when tracking events started/finished.
2203 
2204  vector<VuoCompilerNode *> triggerWaitNodes = getNodesToWaitOnBeforeTransmission(trigger);
2205 
2206  VuoCompilerNode *publishedOutputNode = graph->getPublishedOutputNode();
2207  if (find(triggerWaitNodes.begin(), triggerWaitNodes.end(), publishedOutputNode) == triggerWaitNodes.end())
2208  triggerWaitNodes.push_back(publishedOutputNode);
2209 
2210  generateLockNodes(module, initialBlock, compositionStateValue, triggerWaitNodes, eventIdValue);
2211 
2212  // Start tracking the event so we can later notify the runner when the event is finished.
2213 
2214  Value *compositionContextValue = VuoCompilerCodeGenUtilities::generateGetCompositionContext(module, initialBlock, compositionStateValue);
2215  VuoCompilerCodeGenUtilities::generateStartedExecutingEvent(module, initialBlock, compositionContextValue, eventIdValue);
2216 
2217  // Mark the selected input ports on the published input node as hit by an event.
2218  //
2219  // int i = 0;
2220  // while (i < count)
2221  // {
2222  // if (! strcmp(names[i], "firstPort"))
2223  // {
2224  // ...
2225  // }
2226  // else if (! strcmp(names[i], "secondPort"))
2227  // {
2228  // ...
2229  // }
2230  // i = i + 1;
2231  // }
2232  //
2233 
2234  VuoCompilerNode *publishedInputNode = graph->getPublishedInputNode();
2235  Value *publishedInputNodeContextValue = publishedInputNode->generateGetContext(module, initialBlock, compositionStateValue);
2236 
2237  Value *zeroValue = ConstantInt::get(static_cast<IntegerType *>(countValue->getType()), 0);
2238  AllocaInst *iterVariable = new AllocaInst(countValue->getType(), "i", initialBlock);
2239  new StoreInst(zeroValue, iterVariable, false, initialBlock);
2240 
2241  BasicBlock *loopConditionBlock = BasicBlock::Create(module->getContext(), "loopCondition", function, 0);
2242  BasicBlock *loopBeginBlock = BasicBlock::Create(module->getContext(), "loopBegin", function, 0);
2243  BasicBlock *loopEndBlock = BasicBlock::Create(module->getContext(), "loopEnd", function, 0);
2244  BasicBlock *fireBlock = BasicBlock::Create(module->getContext(), "fire", function, 0);
2245 
2246  BranchInst::Create(loopConditionBlock, initialBlock);
2247 
2248  Value *iterValue = new LoadInst(iterVariable, "", false, loopConditionBlock);
2249  ICmpInst *iterLessThanCount = new ICmpInst(*loopConditionBlock, ICmpInst::ICMP_ULT, iterValue, countValue, "");
2250  BranchInst::Create(loopBeginBlock, fireBlock, iterLessThanCount, loopConditionBlock);
2251 
2252  Value *iterNameValue = VuoCompilerCodeGenUtilities::generateGetArrayElement(module, loopBeginBlock, namesValue, iterValue);
2253 
2254  map<string, pair<BasicBlock *, BasicBlock *> > blocksForString;
2255 
2256  vector<VuoPublishedPort *> publishedInputPorts = composition->getBase()->getPublishedInputPorts();
2257  for (size_t i = 0; i < publishedInputPorts.size(); ++i)
2258  {
2259  string currentName = publishedInputPorts[i]->getClass()->getName();
2260  BasicBlock *currentBlock = BasicBlock::Create(module->getContext(), currentName, function, 0);
2261 
2262  VuoPort *port = graph->getInputPortOnPublishedInputNode(i);
2263  VuoCompilerInputEventPort *inputEventPort = static_cast<VuoCompilerInputEventPort *>(port->getCompiler());
2264  inputEventPort->generateStoreEvent(module, currentBlock, publishedInputNodeContextValue, true);
2265 
2266  blocksForString[currentName] = make_pair(currentBlock, currentBlock);
2267  }
2268 
2269  VuoCompilerCodeGenUtilities::generateStringMatchingCode(module, function, loopBeginBlock, loopEndBlock, iterNameValue, blocksForString, constantsCache);
2270 
2271  Value *oneValue = ConstantInt::get(static_cast<IntegerType *>(countValue->getType()), 1);
2272  Value *iterPlusOneValue = BinaryOperator::Create(Instruction::Add, iterValue, oneValue, "", loopEndBlock);
2273  new StoreInst(iterPlusOneValue, iterVariable, false, loopEndBlock);
2274 
2275  BranchInst::Create(loopConditionBlock, loopEndBlock);
2276 
2277  // Fire an event from the published input trigger.
2278 
2279  Value *triggerNodeContextValue = triggerNode->generateGetContext(module, fireBlock, compositionStateValue);
2280  Value *triggerFunctionValue = trigger->generateLoadFunction(module, fireBlock, triggerNodeContextValue);
2281  CallInst::Create(triggerFunctionValue, "", fireBlock);
2282 
2283  ReturnInst::Create(module->getContext(), fireBlock);
2284 }
2285 
2325 void VuoCompilerBitcodeGenerator::generateGetPublishedPortValueFunction(bool input)
2326 {
2327  Function *function = (input ?
2329  VuoCompilerCodeGenUtilities::getGetPublishedOutputPortValueFunction(module));
2330 
2331  Function::arg_iterator args = function->arg_begin();
2332  Value *portIdentifierValue = args++;
2333  portIdentifierValue->setName("portIdentifier");
2334  Value *shouldUseInterprocessSerializationValue = args++;
2335  shouldUseInterprocessSerializationValue->setName("shouldUseInterprocessSerialization");
2336 
2337  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, 0);
2338  PointerType *pointerToChar = PointerType::get(IntegerType::get(module->getContext(), 8), 0);
2339  AllocaInst *retVariable = new AllocaInst(pointerToChar, "ret", initialBlock);
2340  ConstantPointerNull *nullValue = ConstantPointerNull::get(pointerToChar);
2341  new StoreInst(nullValue, retVariable, false, initialBlock);
2342 
2343  Value *runtimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, initialBlock);
2344  Value *compositionIdentifierValue = constantsCache->get(VuoCompilerComposition::topLevelCompositionIdentifier);
2345  Value *compositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, initialBlock, runtimeStateValue,
2346  compositionIdentifierValue);
2347 
2348  vector<VuoPort *> inputPortsOnPublishedNode;
2349  if (input)
2350  {
2351  vector<VuoPublishedPort *> publishedPorts = composition->getBase()->getPublishedInputPorts();
2352  for (size_t i = 0; i < publishedPorts.size(); ++i)
2353  {
2354  VuoPort *port = graph->getInputPortOnPublishedInputNode(i);
2355  inputPortsOnPublishedNode.push_back(port);
2356  }
2357  }
2358  else
2359  {
2360  vector<VuoPublishedPort *> publishedPorts = composition->getBase()->getPublishedOutputPorts();
2361  for (size_t i = 0; i < publishedPorts.size(); ++i)
2362  {
2363  VuoPort *port = graph->getInputPortOnPublishedOutputNode(i);
2364  inputPortsOnPublishedNode.push_back(port);
2365  }
2366  }
2367 
2368  map<string, pair<BasicBlock *, BasicBlock *> > blocksForString;
2369  for (VuoPort *port : inputPortsOnPublishedNode)
2370  {
2371  string currentName = port->getClass()->getName();
2372  BasicBlock *currentBlock = BasicBlock::Create(module->getContext(), currentName, function, 0);
2373 
2374  string currentIdentifier = static_cast<VuoCompilerEventPort *>(port->getCompiler())->getIdentifier();
2375  Constant *currentIdentifierValue = constantsCache->get(currentIdentifier);
2376 
2377  Value *retValue = VuoCompilerCodeGenUtilities::generateGetInputPortString(module, currentBlock, compositionStateValue,
2378  currentIdentifierValue, shouldUseInterprocessSerializationValue);
2379  new StoreInst(retValue, retVariable, currentBlock);
2380 
2381  blocksForString[currentName] = make_pair(currentBlock, currentBlock);
2382  }
2383 
2384  BasicBlock *finalBlock = BasicBlock::Create(module->getContext(), "final", function, 0);
2385 
2386  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, finalBlock, compositionStateValue);
2387 
2388  LoadInst *retValue = new LoadInst(retVariable, "", false, finalBlock);
2389  ReturnInst::Create(module->getContext(), retValue, finalBlock);
2390 
2391  VuoCompilerCodeGenUtilities::generateStringMatchingCode(module, function, initialBlock, finalBlock, portIdentifierValue, blocksForString, constantsCache);
2392 }
2393 
2405 void VuoCompilerBitcodeGenerator::generateCompositionSetPublishedInputPortValueFunction(void)
2406 {
2408 
2409  Function::arg_iterator args = function->arg_begin();
2410  Value *compositionStateValue = args++;
2411  compositionStateValue->setName("compositionState");
2412  Value *publishedInputPortNameValue = args++;
2413  publishedInputPortNameValue->setName("publishedInputPortName");
2414  Value *valueAsStringValue = args++;
2415  valueAsStringValue->setName("valueAsString");
2416  Value *isCompositionRunningValue = args++;
2417  isCompositionRunningValue->setName("isCompositionRunning");
2418 
2419  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, 0);
2420 
2422  if (! trigger)
2423  {
2424  ReturnInst::Create(module->getContext(), initialBlock);
2425  return;
2426  }
2427 
2428  // const char *inputPortIdentifier = NULL;
2429 
2430  PointerType *pointerToCharType = PointerType::get(IntegerType::get(module->getContext(), 8), 0);
2431  AllocaInst *inputPortIdentifierVariable = new AllocaInst(pointerToCharType, "inputPortIdentifier", initialBlock);
2432  ConstantPointerNull *nullInputPortIdentifier = ConstantPointerNull::get(pointerToCharType);
2433  new StoreInst(nullInputPortIdentifier, inputPortIdentifierVariable, false, initialBlock);
2434 
2435  // if (! strcmp(publishedInputPortName, "firstName"))
2436  // inputPortIdentifier = "PublishedInputs__firstName";
2437  // else if (! strcmp(publishedInputPortName, "secondName"))
2438  // inputPortIdentifier = "PublishedInputs__secondName";
2439  // ...
2440 
2441  map<string, pair<BasicBlock *, BasicBlock *> > blocksForString;
2442  vector<VuoPublishedPort *> publishedInputPorts = composition->getBase()->getPublishedInputPorts();
2443  for (size_t i = 0; i < publishedInputPorts.size(); ++i)
2444  {
2445  string currPublishedInputPortName = publishedInputPorts[i]->getClass()->getName();
2446  BasicBlock *currBlock = BasicBlock::Create(module->getContext(), currPublishedInputPortName, function, 0);
2447 
2448  VuoPort *inputPort = graph->getInputPortOnPublishedInputNode(i);
2449  string inputPortIdentifier = static_cast<VuoCompilerPort *>(inputPort->getCompiler())->getIdentifier();
2450  Value *inputPortIdentifierValue = constantsCache->get(inputPortIdentifier);
2451 
2452  new StoreInst(inputPortIdentifierValue, inputPortIdentifierVariable, false, currBlock);
2453 
2454  blocksForString[currPublishedInputPortName] = make_pair(currBlock, currBlock);
2455  }
2456 
2457  BasicBlock *checkBlock = BasicBlock::Create(module->getContext(), "check", function, 0);
2458  BasicBlock *scheduleBlock = BasicBlock::Create(module->getContext(), "schedule", function, 0);
2459  BasicBlock *finalBlock = BasicBlock::Create(module->getContext(), "final", function, 0);
2460 
2461  VuoCompilerCodeGenUtilities::generateStringMatchingCode(module, function, initialBlock, checkBlock, publishedInputPortNameValue, blocksForString, constantsCache);
2462 
2463  // if (inputPortIdentifier != NULL)
2464  // {
2465 
2466  Value *inputPortIdentifierValue = new LoadInst(inputPortIdentifierVariable, "", false, checkBlock);
2467  ICmpInst *portIdentifierNotEqualsNull = new ICmpInst(*checkBlock, ICmpInst::ICMP_NE, inputPortIdentifierValue, nullInputPortIdentifier, "");
2468  BranchInst::Create(scheduleBlock, finalBlock, portIdentifierNotEqualsNull, checkBlock);
2469 
2470  // void **context = (void **)malloc(4 * sizeof(void *));
2471  // context[0] = (void *)compositionState;
2472  // context[1] = (void *)inputPortIdentifier;
2473  // context[2] = (void *)valueAsString;
2474  // context[3] = (void *)isCompositionRunning;
2475 
2476  Value *contextValue = VuoCompilerCodeGenUtilities::generateCreatePublishedInputWorkerContext(module, scheduleBlock, compositionStateValue,
2477  inputPortIdentifierValue, valueAsStringValue,
2478  isCompositionRunningValue);
2479 
2480  // dispatch_sync(PublishedInputsTrigger__queue, context, PublishedInputPorts__setWorker);
2481  // }
2482 
2483  VuoCompilerNode *triggerNode = graph->getNodeForTriggerPort(trigger);
2484  Value *nodeContextValue = triggerNode->generateGetContext(module, scheduleBlock, compositionStateValue);
2485  string workerFunctionName = VuoStringUtilities::transcodeToIdentifier(VuoNodeClass::publishedInputNodeClassName) + "__setWorker";
2486 
2487  Function *workerFunction = trigger->generateSynchronousSubmissionToDispatchQueue(module, scheduleBlock, nodeContextValue,
2488  workerFunctionName, contextValue);
2489 
2490  BranchInst::Create(finalBlock, scheduleBlock);
2491  ReturnInst::Create(module->getContext(), finalBlock);
2492 
2493  // void PublishedInputPorts__firstName__worker(void *context)
2494  // {
2495 
2496  Function *compositionSetPortValueFunction = VuoCompilerCodeGenUtilities::getCompositionSetPortValueFunction(module);
2497 
2498  Function::arg_iterator workerArgs = workerFunction->arg_begin();
2499  Value *contextValueInWorker = workerArgs++;
2500  contextValueInWorker->setName("context");
2501 
2502  BasicBlock *workerBlock = BasicBlock::Create(module->getContext(), "", workerFunction, 0);
2503 
2504  // VuoCompositionState *compositionState = (VuoCompositionState *)((void **)context)[0];
2505  // char *inputPortIdentifier = (char *)((void **)context)[1];
2506  // char *valueAsString = (char *)((void **)context)[2];
2507  // bool isCompositionRunning = (bool)((void **)context)[3];
2508 
2509  Type *voidPointerType = contextValueInWorker->getType();
2510  Type *voidPointerPointerType = PointerType::get(voidPointerType, 0);
2511  Type *compositionStatePointerType = PointerType::get(VuoCompilerCodeGenUtilities::getCompositionStateType(module), 0);
2512  Type *boolType = compositionSetPortValueFunction->getFunctionType()->getParamType(3);
2513 
2514  Value *contextValueAsVoidPointerArray = new BitCastInst(contextValueInWorker, voidPointerPointerType, "", workerBlock);
2515  Value *compositionStateAsVoidPointer = VuoCompilerCodeGenUtilities::generateGetArrayElement(module, workerBlock, contextValueAsVoidPointerArray, (size_t)0);
2516  Value *compositionStateValueInWorker = new BitCastInst(compositionStateAsVoidPointer, compositionStatePointerType, "", workerBlock);
2517 
2518  Value *inputPortIdentifierAsVoidPointer = VuoCompilerCodeGenUtilities::generateGetArrayElement(module, workerBlock, contextValueAsVoidPointerArray, 1);
2519  Value *inputPortIdentifierValueInWorker = new BitCastInst(inputPortIdentifierAsVoidPointer, pointerToCharType, "", workerBlock);
2520 
2521  Value *valueAsStringValueAsVoidPointer = VuoCompilerCodeGenUtilities::generateGetArrayElement(module, workerBlock, contextValueAsVoidPointerArray, 2);
2522  Value *valueAsStringValueInWorker = new BitCastInst(valueAsStringValueAsVoidPointer, pointerToCharType, "", workerBlock);
2523 
2524  Value *isCompositionRunningValueAsVoidPointer = VuoCompilerCodeGenUtilities::generateGetArrayElement(module, workerBlock, contextValueAsVoidPointerArray, 3);
2525  Value *isCompositionRunningValueInWorker = new PtrToIntInst(isCompositionRunningValueAsVoidPointer, boolType, "", workerBlock);
2526 
2527  // free(context);
2528 
2529  VuoCompilerCodeGenUtilities::generateFreeCall(module, workerBlock, contextValueInWorker);
2530 
2531  // compositionSetPortValue(compositionState, portIdentifier, valueAsString, isCompositionRunning, isCompositionRunning, isCompositionRunning, true, true);
2532  // }
2533 
2534  Value *trueValue = ConstantInt::get(boolType, 1);
2535 
2536  vector<Value *> setValueArgs;
2537  setValueArgs.push_back(compositionStateValueInWorker);
2538  setValueArgs.push_back(inputPortIdentifierValueInWorker);
2539  setValueArgs.push_back(valueAsStringValueInWorker);
2540  setValueArgs.push_back(isCompositionRunningValueInWorker);
2541  setValueArgs.push_back(isCompositionRunningValueInWorker);
2542  setValueArgs.push_back(isCompositionRunningValueInWorker);
2543  setValueArgs.push_back(trueValue);
2544  setValueArgs.push_back(trueValue);
2545  CallInst::Create(compositionSetPortValueFunction, setValueArgs, "", workerBlock);
2546 
2547  ReturnInst::Create(module->getContext(), workerBlock);
2548 }
2549 
2557 void VuoCompilerBitcodeGenerator::generateSetPublishedInputPortValueFunction(void)
2558 {
2560 
2561  Function::arg_iterator args = function->arg_begin();
2562  Value *publishedInputPortNameValue = args++;
2563  publishedInputPortNameValue->setName("publishedInputPortName");
2564  Value *valueAsStringValue = args++;
2565  valueAsStringValue->setName("valueAsString");
2566 
2567  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
2568 
2570 
2571  Value *topLevelRuntimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, block);
2572  Value *topLevelCompositionIdentifierValue = constantsCache->get(VuoCompilerComposition::topLevelCompositionIdentifier);
2573  Value *compositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, topLevelRuntimeStateValue, topLevelCompositionIdentifierValue);
2574  Value *trueValue = ConstantInt::get(compositionFunction->getFunctionType()->getParamType(3), 1);
2575 
2576  vector<Value *> compositionArgs;
2577  compositionArgs.push_back(compositionStateValue);
2578  compositionArgs.push_back(publishedInputPortNameValue);
2579  compositionArgs.push_back(valueAsStringValue);
2580  compositionArgs.push_back(trueValue);
2581  CallInst::Create(compositionFunction, compositionArgs, "", block);
2582 
2583  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, compositionStateValue);
2584 
2585  ReturnInst::Create(module->getContext(), block);
2586 }
2587 
2592 void VuoCompilerBitcodeGenerator::generateTransmissionFromOutputPort(Function *function, BasicBlock *&currentBlock,
2593  Value *compositionStateValue,
2594  VuoCompilerNode *outputNode, VuoCompilerPort *outputPort,
2595  Value *eventValue, Value *dataValue,
2596  bool requiresEvent, bool shouldSendTelemetry)
2597 {
2598  IntegerType *boolType = IntegerType::get(module->getContext(), 1);
2599  PointerType *pointerToCharType = PointerType::get(IntegerType::get(module->getContext(), 8), 0);
2600 
2601  set<VuoCompilerCable *> outgoingCables = graph->getOutgoingCables(outputPort);
2602 
2603  Constant *trueValue = ConstantInt::get(boolType, 1);
2604  Constant *falseValue = ConstantInt::get(boolType, 0);
2605  Constant *transmittedEventValue = (requiresEvent ? trueValue : falseValue);
2606 
2607  // char *dataSummary = NULL;
2608  AllocaInst *dataSummaryVariable = new AllocaInst(pointerToCharType, "dataSummary", currentBlock);
2609  new StoreInst(ConstantPointerNull::get(pointerToCharType), dataSummaryVariable, currentBlock);
2610 
2611  map<VuoCompilerPort *, ICmpInst *> shouldSummarizeInput;
2612  if (shouldSendTelemetry)
2613  {
2614  // bool sentData = false;
2615  AllocaInst *sentDataVariable = new AllocaInst(boolType, "sentData", currentBlock);
2616  new StoreInst(falseValue, sentDataVariable, currentBlock);
2617 
2618  for (set<VuoCompilerCable *>::iterator i = outgoingCables.begin(); i != outgoingCables.end(); ++i)
2619  {
2620  VuoCompilerCable *cable = *i;
2621 
2622  VuoCompilerPort *inputPort = static_cast<VuoCompilerPort *>(cable->getBase()->getToPort()->getCompiler());
2623  ICmpInst *shouldSendDataForInput = VuoCompilerCodeGenUtilities::generateShouldSendDataTelemetryComparison(module, currentBlock,
2624  inputPort->getIdentifier(),
2625  compositionStateValue,
2626  constantsCache);
2627  shouldSummarizeInput[inputPort] = shouldSendDataForInput;
2628  }
2629 
2630  if (dataValue)
2631  {
2632  Value *shouldSummarizeOutput = VuoCompilerCodeGenUtilities::generateShouldSendDataTelemetryComparison(module, currentBlock,
2633  outputPort->getIdentifier(),
2634  compositionStateValue,
2635  constantsCache);
2636 
2637  for (set<VuoCompilerCable *>::iterator i = outgoingCables.begin(); i != outgoingCables.end(); ++i)
2638  {
2639  VuoCompilerCable *cable = *i;
2640 
2641  if (cable->carriesData())
2642  {
2643  VuoCompilerPort *inputPort = static_cast<VuoCompilerPort *>(cable->getBase()->getToPort()->getCompiler());
2644  shouldSummarizeOutput = BinaryOperator::Create(Instruction::Or, shouldSummarizeOutput, shouldSummarizeInput[inputPort], "", currentBlock);
2645  }
2646  }
2647 
2648  BasicBlock *summaryBlock = BasicBlock::Create(module->getContext(), "outputSummary", function, NULL);
2649  BasicBlock *sendOutputBlock = BasicBlock::Create(module->getContext(), "sendOutput", function, NULL);
2650  BranchInst::Create(summaryBlock, sendOutputBlock, shouldSummarizeOutput, currentBlock);
2651 
2652  // sentData = true;
2653  new StoreInst(trueValue, sentDataVariable, summaryBlock);
2654 
2655  // dataSummary = <type>_getSummary(portValue);
2656  VuoCompilerType *type = outputPort->getDataVuoType()->getCompiler();
2657  Value *dataSummaryValue = type->generateSummaryFromValueFunctionCall(module, summaryBlock, dataValue);
2658  new StoreInst(dataSummaryValue, dataSummaryVariable, summaryBlock);
2659 
2660  BranchInst::Create(sendOutputBlock, summaryBlock);
2661  currentBlock = sendOutputBlock;
2662  }
2663 
2664  if (shouldSendTelemetry && outputNode != graph->getPublishedInputNode())
2665  {
2666  Value *sentDataValue = new LoadInst(sentDataVariable, "", false, currentBlock);
2667  Value *dataSummaryValue = new LoadInst(dataSummaryVariable, "", false, currentBlock);
2668 
2669  Constant *outputPortIdentifierValue = constantsCache->get(outputPort->getIdentifier());
2670 
2671  VuoCompilerCodeGenUtilities::generateSendOutputPortsUpdated(module, currentBlock, compositionStateValue, outputPortIdentifierValue,
2672  transmittedEventValue, sentDataValue, dataSummaryValue);
2673  }
2674  }
2675 
2676  // If the output port should transmit an event...
2677  bool alwaysTransmitsEvent = (dynamic_cast<VuoCompilerTriggerPort *>(outputPort) || ! requiresEvent);
2678  BasicBlock *transmissionBlock = NULL;
2679  BasicBlock *noTransmissionBlock = NULL;
2680  if (alwaysTransmitsEvent)
2681  {
2682  transmissionBlock = currentBlock;
2683  }
2684  else
2685  {
2686  transmissionBlock = BasicBlock::Create(module->getContext(), "transmission", function, NULL);
2687  noTransmissionBlock = BasicBlock::Create(module->getContext(), "noTransmission", function, NULL);
2688 
2689  ConstantInt *zeroValue = ConstantInt::get(static_cast<IntegerType *>(eventValue->getType()), 0);
2690  ICmpInst *eventValueIsTrue = new ICmpInst(*currentBlock, ICmpInst::ICMP_NE, eventValue, zeroValue, "");
2691  BranchInst::Create(transmissionBlock, noTransmissionBlock, eventValueIsTrue, currentBlock);
2692  }
2693 
2694  // ... then transmit the event and data (if any) to each connected input port.
2695  for (set<VuoCompilerCable *>::iterator i = outgoingCables.begin(); i != outgoingCables.end(); ++i)
2696  {
2697  VuoCompilerCable *cable = *i;
2698 
2699  VuoCompilerNode *inputNode = cable->getBase()->getToNode()->getCompiler();
2700  Value *inputNodeContextValue = inputNode->generateGetContext(module, transmissionBlock, compositionStateValue);
2701  VuoCompilerInputEventPort *inputPort = static_cast<VuoCompilerInputEventPort *>( cable->getBase()->getToPort()->getCompiler() );
2702  Value *inputPortContextValue = inputPort->generateGetPortContext(module, transmissionBlock, inputNodeContextValue);
2703 
2704  Value *transmittedDataValue = (cable->carriesData() ? dataValue : NULL);
2705 
2706  cable->generateTransmission(module, transmissionBlock, inputNodeContextValue, inputPortContextValue, transmittedDataValue, requiresEvent);
2707 
2708  if (shouldSendTelemetry && inputNode != graph->getPublishedInputNode())
2709  {
2710  // char *inputDataSummary = NULL;
2711  AllocaInst *inputDataSummaryVariable = new AllocaInst(pointerToCharType, "inputDataSummary", transmissionBlock);
2712  new StoreInst(ConstantPointerNull::get(pointerToCharType), inputDataSummaryVariable, transmissionBlock);
2713 
2714  // bool receivedData = false;
2715  AllocaInst *receivedDataVariable = new AllocaInst(boolType, "receivedData", transmissionBlock);
2716  new StoreInst(falseValue, receivedDataVariable, transmissionBlock);
2717 
2718  VuoType *inputDataType = inputPort->getDataVuoType();
2719  if (inputDataType)
2720  {
2721  BasicBlock *summaryBlock = BasicBlock::Create(module->getContext(), "inputSummary", function, NULL);
2722  BasicBlock *sendInputBlock = BasicBlock::Create(module->getContext(), "sendInput", function, NULL);
2723  BranchInst::Create(summaryBlock, sendInputBlock, shouldSummarizeInput[inputPort], transmissionBlock);
2724 
2725  Value *inputDataSummaryValue;
2726  if (transmittedDataValue)
2727  {
2728  // receivedData = true;
2729  new StoreInst(trueValue, receivedDataVariable, summaryBlock);
2730 
2731  // inputDataSummary = dataSummary;
2732  inputDataSummaryValue = new LoadInst(dataSummaryVariable, "", false, summaryBlock);
2733  }
2734  else
2735  {
2736  // inputDataSummary = <Type>_getSummary(inputData);
2737  Value *inputDataValue = inputPort->generateLoadData(module, summaryBlock, inputNodeContextValue, inputPortContextValue);
2738  inputDataSummaryValue = inputDataType->getCompiler()->generateSummaryFromValueFunctionCall(module, summaryBlock, inputDataValue);
2739  }
2740  new StoreInst(inputDataSummaryValue, inputDataSummaryVariable, summaryBlock);
2741 
2742  BranchInst::Create(sendInputBlock, summaryBlock);
2743  transmissionBlock = sendInputBlock;
2744  }
2745 
2746  Value *receivedDataValue = new LoadInst(receivedDataVariable, "", false, transmissionBlock);
2747  Value *inputDataSummaryValue = new LoadInst(inputDataSummaryVariable, "", false, transmissionBlock);
2748 
2749  Constant *inputPortIdentifierValue = constantsCache->get(inputPort->getIdentifier());
2750 
2751  VuoCompilerCodeGenUtilities::generateSendInputPortsUpdated(module, transmissionBlock, compositionStateValue, inputPortIdentifierValue,
2752  transmittedEventValue, receivedDataValue, inputDataSummaryValue);
2753 
2754  if (inputDataType && ! transmittedDataValue)
2755  {
2756  // free(inputDataSummary);
2757  VuoCompilerCodeGenUtilities::generateFreeCall(module, transmissionBlock, inputDataSummaryValue);
2758  }
2759  }
2760  }
2761 
2762  if (alwaysTransmitsEvent)
2763  {
2764  currentBlock = transmissionBlock;
2765  }
2766  else
2767  {
2768  BranchInst::Create(noTransmissionBlock, transmissionBlock);
2769  currentBlock = noTransmissionBlock;
2770  }
2771 
2772  if (shouldSendTelemetry && dataValue)
2773  {
2774  // free(dataSummary)
2775  Function *freeFunction = VuoCompilerCodeGenUtilities::getFreeFunction(module);
2776  LoadInst *dataSummaryValue = new LoadInst(dataSummaryVariable, "", false, currentBlock);
2777  CallInst::Create(freeFunction, dataSummaryValue, "", currentBlock);
2778  }
2779 }
2780 
2785 void VuoCompilerBitcodeGenerator::generateTransmissionFromNode(Function *function, BasicBlock *&currentBlock,
2786  Value *compositionStateValue, Value *nodeContextValue,
2787  VuoCompilerNode *node, bool requiresEvent, bool shouldSendTelemetry)
2788 {
2789  vector<VuoPort *> outputPorts = node->getBase()->getOutputPorts();
2790  for (vector<VuoPort *>::iterator i = outputPorts.begin(); i != outputPorts.end(); ++i)
2791  {
2792  // If the output port is a trigger port, do nothing.
2793  VuoCompilerOutputEventPort *outputEventPort = dynamic_cast<VuoCompilerOutputEventPort *>((*i)->getCompiler());
2794  if (! outputEventPort)
2795  continue;
2796 
2797  Value *portContextValue = outputEventPort->generateGetPortContext(module, currentBlock, nodeContextValue);
2798  Value *outputEventValue = outputEventPort->generateLoadEvent(module, currentBlock, nodeContextValue, portContextValue);
2799 
2800  BasicBlock *telemetryBlock = NULL;
2801  BasicBlock *noTelemetryBlock = NULL;
2802  if (requiresEvent)
2803  {
2804  telemetryBlock = BasicBlock::Create(module->getContext(), "", function, NULL);
2805  noTelemetryBlock = BasicBlock::Create(module->getContext(), "", function, NULL);
2806 
2807  // If the output port isn't transmitting an event, do nothing.
2808  ConstantInt *zeroValue = ConstantInt::get(static_cast<IntegerType *>(outputEventValue->getType()), 0);
2809  ICmpInst *eventValueIsTrue = new ICmpInst(*currentBlock, ICmpInst::ICMP_NE, outputEventValue, zeroValue, "");
2810  BranchInst::Create(telemetryBlock, noTelemetryBlock, eventValueIsTrue, currentBlock);
2811  }
2812  else
2813  {
2814  telemetryBlock = currentBlock;
2815  }
2816 
2817  // Transmit the data through the output port to each connected input port.
2818  VuoCompilerOutputData *outputData = outputEventPort->getData();
2819  Value *outputDataValue = (outputData ?
2820  outputEventPort->generateLoadData(module, telemetryBlock, nodeContextValue, portContextValue) :
2821  NULL);
2822  generateTransmissionFromOutputPort(function, telemetryBlock, compositionStateValue,
2823  node, outputEventPort, outputEventValue, outputDataValue, requiresEvent, shouldSendTelemetry);
2824 
2825  if (requiresEvent)
2826  {
2827  BranchInst::Create(noTelemetryBlock, telemetryBlock);
2828  currentBlock = noTelemetryBlock;
2829  }
2830  else
2831  {
2832  currentBlock = telemetryBlock;
2833  }
2834  }
2835 }
2836 
2841 void VuoCompilerBitcodeGenerator::generateTelemetryFromPublishedOutputNode(Function *function, BasicBlock *&currentBlock, Value *compositionStateValue,
2842  Value *nodeContextValue, VuoCompilerNode *node)
2843 {
2844  IntegerType *boolType = IntegerType::get(module->getContext(), 1);
2845  PointerType *pointerToCharType = PointerType::get(IntegerType::get(module->getContext(), 8), 0);
2846 
2847  for (auto inputPort : node->getBase()->getInputPorts())
2848  {
2849  // If the published output port is for internal use only, do nothing.
2850  if (inputPort == graph->getGatherPortOnPublishedOutputNode())
2851  continue;
2852 
2853  VuoCompilerInputEventPort *inputEventPort = dynamic_cast<VuoCompilerInputEventPort *>(inputPort->getCompiler());
2854 
2855  BasicBlock *telemetryBlock = BasicBlock::Create(module->getContext(), "", function, NULL);
2856  BasicBlock *noTelemetryBlock = BasicBlock::Create(module->getContext(), "", function, NULL);
2857 
2858  // If the published output port isn't transmitting an event, do nothing.
2859  Value *eventValue = inputEventPort->generateLoadEvent(module, currentBlock, nodeContextValue);
2860  ConstantInt *zeroValue = ConstantInt::get(static_cast<IntegerType *>(eventValue->getType()), 0);
2861  ICmpInst *eventValueIsTrue = new ICmpInst(*currentBlock, ICmpInst::ICMP_NE, eventValue, zeroValue, "");
2862  BranchInst::Create(telemetryBlock, noTelemetryBlock, eventValueIsTrue, currentBlock);
2863 
2864  VuoCompilerInputData *data = inputEventPort->getData();
2865  Value *dataValue = data ? inputEventPort->generateLoadData(module, telemetryBlock, nodeContextValue) : NULL;
2866  Constant *trueValue = ConstantInt::get(boolType, 1);
2867  Constant *falseValue = ConstantInt::get(boolType, 0);
2868 
2869  Value *sentDataValue = NULL;
2870  Value *dataSummaryValue = NULL;
2871  if (dataValue)
2872  {
2873  // sentData = true;
2874  sentDataValue = trueValue;
2875 
2876  // dataSummary = <type>_getSummary(portValue);
2877  VuoCompilerType *type = inputEventPort->getDataVuoType()->getCompiler();
2878  dataSummaryValue = type->generateSummaryFromValueFunctionCall(module, telemetryBlock, dataValue);
2879  }
2880  else
2881  {
2882  // sentData = false;
2883  sentDataValue = falseValue;
2884 
2885  // dataSummary = NULL;
2886  dataSummaryValue = ConstantPointerNull::get(pointerToCharType);
2887  }
2888 
2889  Constant *portIdentifierValue = constantsCache->get(inputEventPort->getBase()->getClass()->getName());
2890  VuoCompilerCodeGenUtilities::generateSendPublishedOutputPortsUpdated(module, telemetryBlock, compositionStateValue, portIdentifierValue,
2891  sentDataValue, dataSummaryValue);
2892 
2893  BranchInst::Create(noTelemetryBlock, telemetryBlock);
2894  currentBlock = noTelemetryBlock;
2895  }
2896 }
2897 
2904 void VuoCompilerBitcodeGenerator::generateDataOnlyTransmissionFromNode(Function *function, BasicBlock *&currentBlock, Value *compositionStateValue,
2905  VuoCompilerNode *node, bool shouldWaitForDownstreamNodes,
2906  bool shouldUpdateTriggers, bool shouldSendTelemetry)
2907 {
2908  vector<VuoCompilerNode *> downstreamNodes = graph->getNodesDownstreamViaDataOnlyTransmission(node);
2909  if (downstreamNodes.empty())
2910  return;
2911 
2912  if (shouldWaitForDownstreamNodes)
2913  {
2914  // Claim the nodes downstream via data-only transmission.
2915  generateLockNodes(module, currentBlock, compositionStateValue, downstreamNodes, nullptr);
2916  }
2917 
2918  // For this node and each node downstream via data-only transmission...
2919  vector<VuoCompilerNode *> nodesToVisit = downstreamNodes;
2920  nodesToVisit.insert(nodesToVisit.begin(), node);
2921  for (VuoCompilerNode *visitedNode : nodesToVisit)
2922  {
2923  if (graph->mayTransmitDataOnly(visitedNode))
2924  {
2925  Value *nodeContextValue = visitedNode->generateGetContext(module, currentBlock, compositionStateValue);
2926 
2927  // Simulate an event having just hit all input ports of the node (necessary due to published input node's doors).
2928  vector<VuoPort *> inputPorts = visitedNode->getBase()->getInputPorts();
2929  for (size_t i = VuoNodeClass::unreservedInputPortStartIndex; i < inputPorts.size(); ++i)
2930  {
2931  VuoCompilerInputEventPort *inputEventPort = static_cast<VuoCompilerInputEventPort *>(inputPorts[i]->getCompiler());
2932  inputEventPort->generateStoreEvent(module, currentBlock, nodeContextValue, true);
2933  }
2934 
2935  // Call the node's event function, and send telemetry if needed.
2936  generateNodeExecution(function, currentBlock, compositionStateValue, visitedNode, false);
2937 
2938  // Transmit data through the node's outgoing cables, and send telemetry for port updates if needed.
2939  generateTransmissionFromNode(function, currentBlock, compositionStateValue, nodeContextValue, visitedNode, false, shouldSendTelemetry);
2940 
2941  // Reset the node's event inputs and outputs.
2942  VuoCompilerCodeGenUtilities::generateResetNodeContextEvents(module, currentBlock, nodeContextValue);
2943  }
2944 
2945  if (visitedNode != node)
2946  {
2947  if (shouldUpdateTriggers)
2948  {
2949  // Call the downstream node's trigger update function.
2950  visitedNode->generateCallbackUpdateFunctionCall(module, currentBlock, compositionStateValue);
2951  }
2952 
2953  if (shouldWaitForDownstreamNodes)
2954  {
2955  // Signal the downstream node.
2956  generateUnlockNodes(module, currentBlock, compositionStateValue, vector<VuoCompilerNode *>(1, visitedNode));
2957  }
2958  }
2959  }
2960 }
2961 
2965 void VuoCompilerBitcodeGenerator::generateNodeExecution(Function *function, BasicBlock *&currentBlock,
2966  Value *compositionStateValue, VuoCompilerNode *node,
2967  bool shouldSendTelemetry)
2968 {
2969  Value *nodeIdentifierValue = constantsCache->get(node->getIdentifier());
2970 
2971  if (shouldSendTelemetry)
2972  {
2973  // Send telemetry indicating that the node's execution has started.
2974  VuoCompilerCodeGenUtilities::generateSendNodeExecutionStarted(module, currentBlock, compositionStateValue, nodeIdentifierValue);
2975  }
2976 
2977  // Call the node's event function.
2978  if (debugMode)
2979  VuoCompilerCodeGenUtilities::generatePrint(module, currentBlock, node->getBase()->getTitle() + "\n");
2980  node->generateEventFunctionCall(module, function, currentBlock, compositionStateValue);
2981 
2982  if (shouldSendTelemetry)
2983  {
2984  // Send telemetry indicating that the node's execution has finished.
2985  VuoCompilerCodeGenUtilities::generateSendNodeExecutionFinished(module, currentBlock, compositionStateValue, nodeIdentifierValue);
2986  }
2987 }
2988 
2992 void VuoCompilerBitcodeGenerator::generateAllocation(void)
2993 {
2994 #ifdef VUO_PRO
2995  generateAllocation_Pro();
2996 #endif
2997 
2998  {
2999  Constant *value = constantsCache->get(VuoCompilerComposition::topLevelCompositionIdentifier);
3000  new GlobalVariable(*module, value->getType(), true, GlobalValue::ExternalLinkage, value, "vuoTopLevelCompositionIdentifier");
3001  }
3002 }
3003 
3011 void VuoCompilerBitcodeGenerator::generateSetupFunction(bool isStatefulComposition)
3012 {
3013  Function *function = VuoCompilerCodeGenUtilities::getSetupFunction(module);
3014  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
3015 
3016  Value *topLevelRuntimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, block);
3017  Value *topLevelCompositionIdentifierValue = constantsCache->get(VuoCompilerComposition::topLevelCompositionIdentifier);
3018  Value *topLevelCompositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, topLevelRuntimeStateValue, topLevelCompositionIdentifierValue);
3019 
3020  // Top__compositionAddNodeMetadata(compositionState);
3021 
3022  Function *compositionCreateAndRegisterMetadataFunction = VuoCompilerCodeGenUtilities::getCompositionAddNodeMetadataFunction(module);
3023  CallInst::Create(compositionCreateAndRegisterMetadataFunction, topLevelCompositionStateValue, "", block);
3024 
3025  // vuoInitContextForTopLevelComposition(compositionState, hasInstanceData, publishedOutputPortCount);
3026 
3027  size_t publishedOutputPortCount = composition->getBase()->getPublishedOutputPorts().size();
3028  VuoCompilerCodeGenUtilities::generateInitContextForTopLevelComposition(module, block, topLevelCompositionStateValue,
3029  isStatefulComposition, publishedOutputPortCount);
3030 
3031  // Set each published input port to its initial value.
3032 
3033  Function *compositionSetPublishedInputPortValueFunction = VuoCompilerCodeGenUtilities::getCompositionSetPublishedInputPortValueFunction(module);
3034  Value *falseValue = ConstantInt::get(compositionSetPublishedInputPortValueFunction->getFunctionType()->getParamType(3), 0);
3035 
3036  for (VuoPublishedPort *publishedInputPort : composition->getBase()->getPublishedInputPorts())
3037  {
3038  string name = publishedInputPort->getClass()->getName();
3039  string initialValue = static_cast<VuoCompilerPublishedPort *>(publishedInputPort->getCompiler())->getInitialValue();
3040 
3041  vector<Value *> args;
3042  args.push_back(topLevelCompositionStateValue);
3043  args.push_back( constantsCache->get(name) );
3044  args.push_back( constantsCache->get(initialValue) );
3045  args.push_back(falseValue);
3046  CallInst::Create(compositionSetPublishedInputPortValueFunction, args, "", block);
3047  }
3048 
3049  // Top__compositionPerformDataOnlyTransmissions(compositionState);
3050 
3051  Function *compositionPerformDataOnlyTransmissionsFunction = VuoCompilerCodeGenUtilities::getCompositionPerformDataOnlyTransmissionsFunction(module);
3052  CallInst::Create(compositionPerformDataOnlyTransmissionsFunction, topLevelCompositionStateValue, "", block);
3053 
3054  // Update the function pointers for all trigger functions in the top-level composition.
3055 
3056  for (map<VuoCompilerTriggerPort *, Function *>::iterator i = topLevelTriggerFunctions.begin(); i != topLevelTriggerFunctions.end(); ++i)
3057  {
3058  VuoCompilerTriggerPort *trigger = i->first;
3059  Function *function = i->second;
3060 
3061  VuoCompilerNode *node = graph->getNodeForTriggerPort(trigger);
3062  Value *nodeContextValue = node->generateGetContext(module, block, topLevelCompositionStateValue);
3063  trigger->generateStoreFunction(module, block, nodeContextValue, function);
3064  }
3065 
3066  // Update the function pointers for all trigger functions in subcompositions.
3067 
3068  for (map<string, map<size_t, map<VuoCompilerTriggerDescription *, Function *> > >::iterator i = subcompositionTriggerFunctions.begin(); i != subcompositionTriggerFunctions.end(); ++i)
3069  {
3070  string compositionIdentifier = i->first;
3071 
3072  for (map<size_t, map<VuoCompilerTriggerDescription *, Function *> >::iterator j = i->second.begin(); j != i->second.end(); ++j)
3073  {
3074  size_t nodeIndex = j->first;
3075 
3076  for (map<VuoCompilerTriggerDescription *, Function *>::iterator k = j->second.begin(); k != j->second.end(); ++k)
3077  {
3078  VuoCompilerTriggerDescription *trigger = k->first;
3079  Function *function = k->second;
3080 
3081  Value *compositionIdentifierValue = constantsCache->get(compositionIdentifier);
3082  Value *compositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, topLevelRuntimeStateValue, compositionIdentifierValue);
3083 
3084  int portContextIndex = trigger->getPortContextIndex();
3085  Value *nodeContextValue = VuoCompilerCodeGenUtilities::generateGetNodeContext(module, block, compositionStateValue, nodeIndex);
3086  Value *portContextValue = VuoCompilerCodeGenUtilities::generateGetNodeContextPortContext(module, block, nodeContextValue, portContextIndex);
3087  VuoCompilerCodeGenUtilities::generateSetPortContextTriggerFunction(module, block, portContextValue, function);
3088 
3089  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, compositionStateValue);
3090  }
3091  }
3092  }
3093 
3094  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, topLevelCompositionStateValue);
3095 
3096  ReturnInst::Create(module->getContext(), block);
3097 }
3098 
3105 void VuoCompilerBitcodeGenerator::generateCleanupFunction(void)
3106 {
3107  Function *function = VuoCompilerCodeGenUtilities::getCleanupFunction(module);
3108  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
3109 
3110  Value *topLevelRuntimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, block);
3111  Value *topLevelCompositionIdentifierValue = constantsCache->get(VuoCompilerComposition::topLevelCompositionIdentifier);
3112  Value *topLevelCompositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, topLevelRuntimeStateValue, topLevelCompositionIdentifierValue);
3113 
3114  VuoCompilerCodeGenUtilities::generateFiniContextForTopLevelComposition(module, block, topLevelCompositionStateValue);
3115 
3116  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, topLevelCompositionStateValue);
3117 
3118  ReturnInst::Create(module->getContext(), block);
3119 }
3120 
3126 void VuoCompilerBitcodeGenerator::generateInstanceInitFunction(bool isStatefulComposition)
3127 {
3128  Function *function = VuoCompilerCodeGenUtilities::getInstanceInitFunction(module);
3129  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
3130 
3131  if (isStatefulComposition)
3132  {
3133  map<VuoPort *, size_t> indexOfParameter;
3134  Function *nodeInstanceInitFunction = VuoCompilerCodeGenUtilities::getNodeInstanceInitFunction(module, moduleKey, true,
3136  vector<VuoPort *>(),
3137  indexOfParameter, constantsCache);
3138 
3139  Value *topLevelRuntimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, block);
3140  Value *topLevelCompositionIdentifierValue = constantsCache->get(VuoCompilerComposition::topLevelCompositionIdentifier);
3141  Value *topLevelCompositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, topLevelRuntimeStateValue, topLevelCompositionIdentifierValue);
3142 
3143  CallInst::Create(nodeInstanceInitFunction, topLevelCompositionStateValue, "", block);
3144 
3145  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, topLevelCompositionStateValue);
3146  }
3147 
3148  ReturnInst::Create(module->getContext(), block);
3149 }
3150 
3156 void VuoCompilerBitcodeGenerator::generateInstanceFiniFunction(bool isStatefulComposition)
3157 {
3158  Function *function = VuoCompilerCodeGenUtilities::getInstanceFiniFunction(module);
3159  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
3160 
3161  if (isStatefulComposition)
3162  {
3163  Function *nodeInstanceFiniFunction = VuoCompilerCodeGenUtilities::getNodeInstanceFiniFunction(module, moduleKey,
3165  constantsCache);
3166 
3167  Value *topLevelRuntimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, block);
3168  Value *topLevelCompositionIdentifierValue = constantsCache->get(VuoCompilerComposition::topLevelCompositionIdentifier);
3169  Value *topLevelCompositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, topLevelRuntimeStateValue, topLevelCompositionIdentifierValue);
3170 
3171  PointerType *instanceDataType = static_cast<PointerType *>( nodeInstanceFiniFunction->getFunctionType()->getParamType(1) );
3172  ConstantPointerNull *nullInstanceDataValue = ConstantPointerNull::get(instanceDataType);
3173 
3174  vector<Value *> args;
3175  args.push_back(topLevelCompositionStateValue);
3176  args.push_back(nullInstanceDataValue);
3177  CallInst::Create(nodeInstanceFiniFunction, args, "", block);
3178 
3179  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, topLevelCompositionStateValue);
3180  }
3181 
3182  ReturnInst::Create(module->getContext(), block);
3183 }
3184 
3190 void VuoCompilerBitcodeGenerator::generateInstanceTriggerStartFunction(bool isStatefulComposition)
3191 {
3193  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
3194 
3195  if (isStatefulComposition)
3196  {
3197  map<VuoPort *, size_t> indexOfParameter;
3198  Function *nodeInstanceTriggerStartFunction = VuoCompilerCodeGenUtilities::getNodeInstanceTriggerStartFunction(module, moduleKey,
3200  vector<VuoPort *>(),
3201  indexOfParameter,
3202  constantsCache);
3203 
3204  Value *topLevelRuntimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, block);
3205  Value *topLevelCompositionIdentifierValue = constantsCache->get(VuoCompilerComposition::topLevelCompositionIdentifier);
3206  Value *topLevelCompositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, topLevelRuntimeStateValue, topLevelCompositionIdentifierValue);
3207 
3208  PointerType *instanceDataType = static_cast<PointerType *>( nodeInstanceTriggerStartFunction->getFunctionType()->getParamType(1) );
3209  ConstantPointerNull *nullInstanceDataValue = ConstantPointerNull::get(instanceDataType);
3210 
3211  vector<Value *> args;
3212  args.push_back(topLevelCompositionStateValue);
3213  args.push_back(nullInstanceDataValue);
3214  CallInst::Create(nodeInstanceTriggerStartFunction, args, "", block);
3215 
3216  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, topLevelCompositionStateValue);
3217  }
3218 
3219  ReturnInst::Create(module->getContext(), block);
3220 }
3221 
3227 void VuoCompilerBitcodeGenerator::generateInstanceTriggerStopFunction(bool isStatefulComposition)
3228 {
3230  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function, NULL);
3231 
3232  {
3233  Function *nodeInstanceTriggerStopFunction = VuoCompilerCodeGenUtilities::getNodeInstanceTriggerStopFunction(module, moduleKey,
3235  constantsCache);
3236 
3237  Value *topLevelRuntimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, block);
3238  Value *topLevelCompositionIdentifierValue = constantsCache->get(VuoCompilerComposition::topLevelCompositionIdentifier);
3239  Value *topLevelCompositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, topLevelRuntimeStateValue, topLevelCompositionIdentifierValue);
3240 
3241  PointerType *instanceDataType = static_cast<PointerType *>( nodeInstanceTriggerStopFunction->getFunctionType()->getParamType(1) );
3242  ConstantPointerNull *nullInstanceDataValue = ConstantPointerNull::get(instanceDataType);
3243 
3244  vector<Value *> args;
3245  args.push_back(topLevelCompositionStateValue);
3246  args.push_back(nullInstanceDataValue);
3247  CallInst::Create(nodeInstanceTriggerStopFunction, args, "", block);
3248 
3249  VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, topLevelCompositionStateValue);
3250  }
3251 
3252  ReturnInst::Create(module->getContext(), block);
3253 }
3254 
3260 void VuoCompilerBitcodeGenerator::generateTriggerFunctions(void)
3261 {
3262  auto isSpinOffTrigger = [] (const string &nodeClassName)
3263  {
3264  return (VuoStringUtilities::beginsWith(nodeClassName, "vuo.event.spinOff") ||
3265  VuoStringUtilities::beginsWith(nodeClassName, "vuo.list.build") ||
3266  VuoStringUtilities::beginsWith(nodeClassName, "vuo.list.process"));
3267  };
3268 
3269  map<VuoCompilerTriggerPort *, Function *> workerFunctionForTrigger;
3270  for (VuoCompilerTriggerPort *trigger : graph->getTriggerPorts())
3271  {
3272  Function *workerFunction = generateTriggerWorkerFunction(trigger);
3273  workerFunctionForTrigger[trigger] = workerFunction;
3274  }
3275 
3276  if (isTopLevelComposition)
3277  {
3278  for (map<VuoCompilerTriggerPort *, Function *>::iterator i = workerFunctionForTrigger.begin(); i != workerFunctionForTrigger.end(); ++i)
3279  {
3280  VuoCompilerTriggerPort *trigger = i->first;
3281  Function *workerFunction = i->second;
3282 
3283  VuoType *dataType = trigger->getDataVuoType();
3284 
3285  VuoCompilerNode *node = graph->getNodeForTriggerPort(trigger);
3286  size_t triggerNodeIndex = node->getIndexInOrderedNodes();
3287 
3288  string portIdentifier = trigger->getIdentifier();
3289 
3290  int portContextIndex = trigger->getIndexInPortContexts();
3291 
3292  bool canDropEvents = (trigger->getBase()->getEventThrottling() == VuoPortClass::EventThrottling_Drop);
3293 
3294  bool isPublishedTrigger = (trigger == graph->getPublishedInputTrigger());
3295 
3296  bool isSpinOff = isSpinOffTrigger(node->getBase()->getNodeClass()->getClassName());
3297 
3298  int minThreadsNeeded, maxThreadsNeeded;
3299  graph->getWorkerThreadsNeeded(trigger, minThreadsNeeded, maxThreadsNeeded);
3300 
3301  int chainCount = (int)graph->getChains()[trigger].size();
3302 
3303  Function *function = generateTriggerSchedulerFunction(dataType, VuoCompilerComposition::topLevelCompositionIdentifier, triggerNodeIndex,
3304  portIdentifier, portContextIndex, canDropEvents, isPublishedTrigger, isSpinOff,
3305  minThreadsNeeded, maxThreadsNeeded, chainCount, workerFunction);
3306  topLevelTriggerFunctions[trigger] = function;
3307  }
3308 
3309  for (VuoCompilerNode *node : graph->getNodes())
3310  {
3311  VuoCompilerNodeClass *nodeClass = node->getBase()->getNodeClass()->getCompiler();
3312 
3314  node->getGraphvizIdentifier());
3315 
3316  vector<VuoCompilerTriggerDescription *> triggers = nodeClass->getTriggerDescriptions();
3317  for (vector<VuoCompilerTriggerDescription *>::iterator j = triggers.begin(); j != triggers.end(); ++j)
3318  {
3319  VuoCompilerTriggerDescription *trigger = *j;
3320 
3321  size_t triggerNodeIndex = trigger->getNodeIndex();
3322  string triggerNodeIdentifier = trigger->getNodeIdentifier();
3323  string portIdentifier = VuoStringUtilities::buildPortIdentifier(triggerNodeIdentifier, trigger->getPortName());
3324  int portContextIndex = trigger->getPortContextIndex();
3325  bool canDropEvents = (trigger->getEventThrottling() == VuoPortClass::EventThrottling_Drop);
3326  VuoType *dataType = trigger->getDataType();
3327  string subcompositionNodeClassName = trigger->getSubcompositionNodeClassName();
3328  VuoCompilerNodeClass *subcompositionNodeClass = (subcompositionNodeClassName.empty() ?
3329  nodeClass :
3330  compiler->getNodeClass(subcompositionNodeClassName));
3331  string subcompositionNodeIdentifier = trigger->getSubcompositionNodeIdentifier();
3332  string fullSubcompositionNodeIdentifier = (subcompositionNodeIdentifier.empty() ?
3333  nodeIdentifier :
3334  VuoStringUtilities::buildCompositionIdentifier(nodeIdentifier, subcompositionNodeIdentifier));
3335  bool isPublishedTrigger = (triggerNodeIdentifier == graph->getPublishedInputTriggerNodeIdentifier());
3336 
3337  bool isSpinOff = isSpinOffTrigger(trigger->getNodeClassName());
3338 
3339  int minThreadsNeeded, maxThreadsNeeded;
3340  if (isPublishedTrigger)
3341  minThreadsNeeded = maxThreadsNeeded = -1;
3342  else
3343  trigger->getWorkerThreadsNeeded(minThreadsNeeded, maxThreadsNeeded);
3344 
3345  int chainCount = trigger->getChainCount();
3346 
3347  Function *workerFunctionSrc = subcompositionNodeClass->getTriggerWorkerFunction(portIdentifier);
3348  Function *workerFunction = VuoCompilerModule::declareFunctionInModule(module, workerFunctionSrc);
3349 
3350  Function *function = generateTriggerSchedulerFunction(dataType, fullSubcompositionNodeIdentifier, triggerNodeIndex,
3351  portIdentifier, portContextIndex, canDropEvents, isPublishedTrigger, isSpinOff,
3352  minThreadsNeeded, maxThreadsNeeded, chainCount, workerFunction);
3353 
3354  subcompositionTriggerFunctions[fullSubcompositionNodeIdentifier][triggerNodeIndex][trigger] = function;
3355  }
3356  }
3357  }
3358 }
3359 
3403 Function * VuoCompilerBitcodeGenerator::generateTriggerSchedulerFunction(VuoType *dataType,
3404  string compositionIdentifier, size_t nodeIndex,
3405  string portIdentifier, int portContextIndex,
3406  bool canDropEvents, bool isPublishedInputTrigger, bool isSpinOff,
3407  int minThreadsNeeded, int maxThreadsNeeded, int chainCount,
3408  Function *workerFunction)
3409 {
3410  string functionName = VuoStringUtilities::prefixSymbolName(workerFunction->getName().str(),
3411  VuoStringUtilities::transcodeToIdentifier(compositionIdentifier));
3412  FunctionType *functionType = VuoCompilerCodeGenUtilities::getFunctionType(module, dataType);
3413  Function *function = Function::Create(functionType, GlobalValue::InternalLinkage, functionName, module);
3414 
3415  if (dataType)
3416  {
3417  AttributeSet paramAttributes = dataType->getCompiler()->getFunctionParameterAttributes();
3418  function->setAttributes(paramAttributes);
3419  }
3420 
3421  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, NULL);
3422  BasicBlock *finalBlock = BasicBlock::Create(module->getContext(), "final", function, NULL);
3423  BasicBlock *scheduleBlock = BasicBlock::Create(module->getContext(), "schedule", function, NULL);
3424 
3425  Value *runtimeStateValue = VuoCompilerCodeGenUtilities::generateRuntimeStateValue(module, initialBlock);
3426  Value *compositionIdentifierValue = constantsCache->get(compositionIdentifier);
3427 
3428  Value *compositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, initialBlock, runtimeStateValue, compositionIdentifierValue);
3429  VuoCompilerCodeGenUtilities::generateRegisterCall(module, initialBlock, compositionStateValue, VuoCompilerCodeGenUtilities::getFreeFunction(module));
3430  VuoCompilerCodeGenUtilities::generateRetainCall(module, initialBlock, compositionStateValue);
3431 
3432  Value *nodeContextValue = VuoCompilerCodeGenUtilities::generateGetNodeContext(module, initialBlock, compositionStateValue, nodeIndex);
3433  Value *portContextValue = VuoCompilerCodeGenUtilities::generateGetNodeContextPortContext(module, initialBlock, nodeContextValue, portContextIndex);
3434 
3435  if (canDropEvents)
3436  {
3437  BasicBlock *checkEventDropBlock = BasicBlock::Create(module->getContext(), "checkEventDrop", function, NULL);
3438  BranchInst::Create(checkEventDropBlock, initialBlock);
3439 
3440  // Do a non-blocking wait on the trigger's semaphore to check if it's already claimed. If so...
3441  Value *retValue = VuoCompilerTriggerPort::generateNonBlockingWaitForSemaphore(module, checkEventDropBlock, portContextValue);
3442  Constant *zeroValue = ConstantInt::get(retValue->getType(), 0);
3443  ICmpInst *isTriggerAvailableValue = new ICmpInst(*checkEventDropBlock, ICmpInst::ICMP_EQ, retValue, zeroValue, "");
3444  BasicBlock *dropEventBlock = BasicBlock::Create(module->getContext(), "dropEvent", function, NULL);
3445  BranchInst::Create(scheduleBlock, dropEventBlock, isTriggerAvailableValue, checkEventDropBlock);
3446 
3447  // Release the data value.
3448  if (dataType)
3449  VuoCompilerTriggerPort::generateDataValueDiscardFromScheduler(module, function, dropEventBlock, dataType);
3450 
3451  // Send telemetry that the event has been dropped.
3452  Constant *portIdentifierValue = constantsCache->get(portIdentifier);
3453  VuoCompilerCodeGenUtilities::generateSendEventDropped(module, dropEventBlock, compositionStateValue, portIdentifierValue);
3454 
3455  VuoCompilerCodeGenUtilities::generateReleaseCall(module, dropEventBlock, compositionStateValue);
3456 
3457  BranchInst::Create(finalBlock, dropEventBlock);
3458  }
3459  else
3460  {
3461  BranchInst::Create(scheduleBlock, initialBlock);
3462  }
3463 
3464  // Enter the trigger's dispatch group for tracking workers scheduled.
3465  Value *triggerWorkersScheduledValue = VuoCompilerCodeGenUtilities::getTriggerWorkersScheduledValue(module, scheduleBlock, compositionStateValue);
3466  VuoCompilerCodeGenUtilities::generateEnterDispatchGroup(module, scheduleBlock, triggerWorkersScheduledValue);
3467 
3468  Value *eventIdValue;
3469  if (! isPublishedInputTrigger)
3470  {
3471  // Get a unique ID for this event.
3472  eventIdValue = VuoCompilerCodeGenUtilities::generateGetNextEventId(module, scheduleBlock, compositionStateValue);
3473 
3474  // If this trigger fires in response to an input event, and the original event came from the published input trigger,
3475  // associate the new (spun off) event's ID with the original event.
3476  if (isSpinOff)
3477  {
3478  Value *compositionContextValue = VuoCompilerCodeGenUtilities::generateGetCompositionContext(module, scheduleBlock, compositionStateValue);
3479  VuoCompilerCodeGenUtilities::generateSpunOffExecutingEvent(module, scheduleBlock, compositionContextValue, eventIdValue);
3480  }
3481  }
3482  else
3483  {
3484  // Use the event ID from the parent composition or `firePublishedInputTrigger()`.
3485  Value *compositionContextValue = VuoCompilerCodeGenUtilities::generateGetCompositionContext(module, scheduleBlock, compositionStateValue);
3486  eventIdValue = VuoCompilerCodeGenUtilities::generateGetOneExecutingEvent(module, scheduleBlock, compositionContextValue);
3487  }
3488 
3489  // Schedule the trigger's worker function via `vuoScheduleTriggerWorker()`.
3490  VuoCompilerTriggerPort::generateScheduleWorker(module, function, scheduleBlock,
3491  compositionStateValue, eventIdValue, portContextValue, dataType,
3492  minThreadsNeeded, maxThreadsNeeded, chainCount, workerFunction);
3493  BranchInst::Create(finalBlock, scheduleBlock);
3494 
3495  ReturnInst::Create(module->getContext(), finalBlock);
3496 
3497  return function;
3498 }
3499 
3644 Function * VuoCompilerBitcodeGenerator::generateTriggerWorkerFunction(VuoCompilerTriggerPort *trigger)
3645 {
3647  Function *function = trigger->getWorkerFunction(module, functionName, true);
3648 
3649  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, NULL);
3650  BasicBlock *triggerBlock = BasicBlock::Create(module->getContext(), "trigger", function, NULL);
3651  BasicBlock *finalBlock = BasicBlock::Create(module->getContext(), "final", function, NULL);
3652 
3653  Value *compositionStateValue = trigger->generateCompositionStateValue(module, initialBlock, function);
3654  Value *compositionContextValue = VuoCompilerCodeGenUtilities::generateGetCompositionContext(module, initialBlock, compositionStateValue);
3655  Value *eventIdValue = trigger->generateEventIdValue(module, initialBlock, function);
3656 
3657  VuoCompilerNode *triggerNode = graph->getNodeForTriggerPort(trigger);
3658  Value *triggerNodeContextValue = triggerNode->generateGetContext(module, initialBlock, compositionStateValue);
3659  Value *triggerWorkersScheduledValue = VuoCompilerCodeGenUtilities::getTriggerWorkersScheduledValue(module, initialBlock, compositionStateValue);
3660  bool canDropEvents = (trigger->getBase()->getEventThrottling() == VuoPortClass::EventThrottling_Drop);
3661 
3662  bool isPublishedInputTrigger = (trigger == graph->getPublishedInputTrigger());
3663  bool isNodeEventForSubcomposition = (! isTopLevelComposition && isPublishedInputTrigger);
3664 
3665  if (! isNodeEventForSubcomposition)
3666  {
3667  // Check if `isPaused` is true. If so...
3668  BasicBlock *isPausedBlock = BasicBlock::Create(module->getContext(), "isPaused", function, NULL);
3669  ICmpInst *isPausedValueIsTrue = VuoCompilerCodeGenUtilities::generateIsPausedComparison(module, initialBlock, compositionStateValue);
3670  BranchInst::Create(isPausedBlock, triggerBlock, isPausedValueIsTrue, initialBlock);
3671 
3672  // Release the data value.
3673  trigger->generateDataValueDiscardFromWorker(module, isPausedBlock, function);
3674 
3675  // Wait for the published output node's semaphore, if not already claimed in `firePublishedInputPortEvent()`.
3676  VuoCompilerNode *publishedOutputNode = graph->getPublishedOutputNode();
3677  vector<VuoCompilerNode *> publishedOutputNodeVector(1, publishedOutputNode);
3678  if (publishedOutputNode && ! isPublishedInputTrigger)
3679  generateLockNodes(module, isPausedBlock, compositionStateValue, publishedOutputNodeVector);
3680 
3681  // Call `vuoSendEventFinished()`.
3682  VuoCompilerCodeGenUtilities::generateSendEventFinished(module, isPausedBlock, compositionStateValue, eventIdValue);
3683 
3684  if (isPublishedInputTrigger)
3685  {
3686  // Signal the semaphores claimed in `firePublishedInputPortEvent()`.
3687  vector<VuoCompilerNode *> triggerWaitNodes = getNodesToWaitOnBeforeTransmission(trigger);
3688  generateUnlockNodes(module, isPausedBlock, compositionStateValue, triggerWaitNodes);
3689  }
3690 
3691  // Signal the published output node's semaphore.
3692  if (publishedOutputNode)
3693  generateUnlockNodes(module, isPausedBlock, compositionStateValue, publishedOutputNodeVector);
3694 
3695  if (canDropEvents)
3696  // Signal the trigger's semaphore for event dropping.
3697  trigger->generateSignalForSemaphore(module, isPausedBlock, triggerNodeContextValue);
3698 
3699  // Leave the trigger's dispatch group for tracking workers scheduled.
3700  VuoCompilerCodeGenUtilities::generateLeaveDispatchGroup(module, isPausedBlock, triggerWorkersScheduledValue);
3701 
3702  // Call `vuoReturnThreadsForTriggerWorker()`.
3703  VuoCompilerCodeGenUtilities::generateReturnThreadsForTriggerWorker(module, isPausedBlock, eventIdValue, compositionStateValue);
3704 
3705  BranchInst::Create(finalBlock, isPausedBlock);
3706  // Otherwise...
3707  }
3708  else
3709  {
3710  BranchInst::Create(triggerBlock, initialBlock);
3711  }
3712 
3713  if (isPublishedInputTrigger)
3714  {
3715  if (! isNodeEventForSubcomposition)
3716  {
3717  // Signal the published output node if it was waited on in `firePublishedInputPortEvent()` just to track event start/finished.
3718  vector<VuoCompilerNode *> triggerWaitNodes = getNodesToWaitOnBeforeTransmission(trigger);
3719  VuoCompilerNode *publishedOutputNode = graph->getPublishedOutputNode();
3720  if (find(triggerWaitNodes.begin(), triggerWaitNodes.end(), publishedOutputNode) == triggerWaitNodes.end())
3721  {
3722  vector<VuoCompilerNode *> publishedOutputNodeVector(1, publishedOutputNode);
3723  generateUnlockNodes(module, triggerBlock, compositionStateValue, publishedOutputNodeVector);
3724  }
3725  }
3726  }
3727  else
3728  {
3729  // Claim the semaphores of all necessary downstream nodes.
3730  vector<VuoCompilerNode *> triggerWaitNodes = getNodesToWaitOnBeforeTransmission(trigger);
3731  generateLockNodes(module, triggerBlock, compositionStateValue, triggerWaitNodes, eventIdValue);
3732 
3733  // Update the trigger's data value.
3734  Value *triggerDataValue = trigger->generateDataValueUpdate(module, triggerBlock, function, triggerNodeContextValue);
3735 
3736  // Transmit events and data (if any) out of the trigger port, and send telemetry for port updates.
3737  generateTransmissionFromOutputPort(function, triggerBlock, compositionStateValue, triggerNode, trigger, NULL, triggerDataValue);
3738  }
3739 
3740  // If the trigger node isn't downstream of the trigger, signal the trigger node's semaphore.
3741  vector<VuoCompilerNode *> downstreamNodes = graph->getNodesDownstream(trigger);
3742  if (find(downstreamNodes.begin(), downstreamNodes.end(), triggerNode) == downstreamNodes.end())
3743  generateUnlockNodes(module, triggerBlock, compositionStateValue, vector<VuoCompilerNode *>(1, triggerNode));
3744 
3745  if (canDropEvents)
3746  // Signal the trigger's semaphore for event dropping.
3747  trigger->generateSignalForSemaphore(module, triggerBlock, triggerNodeContextValue);
3748 
3749  // Leave the trigger's dispatch group for tracking workers scheduled.
3750  VuoCompilerCodeGenUtilities::generateLeaveDispatchGroup(module, triggerBlock, triggerWorkersScheduledValue);
3751 
3752 
3753  // Schedule the chain worker function for each chain immediately downstream of the trigger.
3754 
3755  map<VuoCompilerChain *, vector<VuoCompilerChain *> > chainsImmediatelyDownstream;
3756  map<VuoCompilerChain *, vector<VuoCompilerChain *> > chainsImmediatelyUpstream;
3757  set<VuoCompilerChain *> chainsScheduled;
3758 
3759  vector<VuoCompilerChain *> allChains = chainsForTrigger[trigger];
3760 
3761  if (! allChains.empty())
3762  {
3763  // Organize the chains so it's easy to look up what's downstream/upstream of what.
3764  for (vector<VuoCompilerChain *>::iterator i = allChains.begin(); i != allChains.end(); ++i)
3765  {
3766  VuoCompilerChain *chain = *i;
3767  VuoCompilerNode *firstNodeInThisChain = chain->getNodes().front();
3768 
3769  for (vector<VuoCompilerChain *>::iterator j = allChains.begin(); j != allChains.end(); ++j)
3770  {
3771  VuoCompilerChain *otherChain = *j;
3772 
3773  if (chain == otherChain)
3774  break; // Any chains after this are downstream.
3775 
3776  VuoCompilerNode *lastNodeInOtherChain = otherChain->getNodes().back();
3777 
3778  if (graph->mayTransmit(lastNodeInOtherChain, firstNodeInThisChain, trigger))
3779  {
3780  chainsImmediatelyUpstream[chain].push_back(otherChain);
3781  chainsImmediatelyDownstream[otherChain].push_back(chain);
3782  }
3783  }
3784  }
3785 
3786  // Create the context to pass to the chain workers.
3787  Value *contextValue = VuoCompilerChain::generateMakeContext(module, triggerBlock, compositionStateValue, eventIdValue);
3788 
3789  // Find all chains immediately downstream of the trigger (i.e., chains that have no other chains upstream).
3790  vector<VuoCompilerChain *> firstChains;
3791  for (vector<VuoCompilerChain *>::iterator i = allChains.begin(); i != allChains.end(); ++i)
3792  {
3793  VuoCompilerChain *chain = *i;
3794  map<VuoCompilerChain *, vector<VuoCompilerChain *> >::iterator upstreamIter = chainsImmediatelyUpstream.find(chain);
3795  if (upstreamIter == chainsImmediatelyUpstream.end())
3796  firstChains.push_back(chain);
3797  }
3798 
3799  // Choose one chain to execute in the trigger worker, to reduce overhead creating/destroying threads.
3800  VuoCompilerChain *chainToExecute = firstChains.back();
3801  firstChains.pop_back();
3802  chainsScheduled.insert(chainToExecute);
3803  size_t chainIndex = find(allChains.begin(), allChains.end(), chainToExecute) - allChains.begin();
3804  VuoCompilerCodeGenUtilities::generateRetainCall(module, triggerBlock, contextValue);
3805 
3806  // Call `vuoGrantThreadsToChain()` for the chosen chain.
3807  int minThreadsNeeded, maxThreadsNeeded;
3808  graph->getWorkerThreadsNeeded(chainToExecute, minThreadsNeeded, maxThreadsNeeded);
3809  VuoCompilerCodeGenUtilities::generateGrantThreadsToChain(module, triggerBlock, minThreadsNeeded, maxThreadsNeeded,
3810  eventIdValue, compositionStateValue, chainIndex);
3811 
3812  // Schedule the rest of the chains immediately downstream of the trigger.
3813  generateAndScheduleChainWorkerFunctions(triggerBlock, compositionStateValue, contextValue, firstChains, trigger,
3814  allChains, chainsImmediatelyDownstream, chainsImmediatelyUpstream, chainsScheduled);
3815 
3816  // Execute the chosen chain.
3817  generateChainExecution(function, triggerBlock, compositionStateValue, contextValue, eventIdValue, chainToExecute, trigger,
3818  allChains, chainsImmediatelyDownstream, chainsImmediatelyUpstream, chainsScheduled);
3819  VuoCompilerCodeGenUtilities::generateReleaseCall(module, triggerBlock, contextValue);
3820  }
3821  else
3822  {
3823  // Call `vuoReturnThreadsForTriggerWorker()`.
3824  VuoCompilerCodeGenUtilities::generateReturnThreadsForTriggerWorker(module, triggerBlock, eventIdValue, compositionStateValue);
3825 
3826  if (isNodeEventForSubcomposition)
3827  {
3828  // Leave the dispatch group waited on by `nodeEvent()`/`nodeInstanceEvent()`.
3829  Value *subcompositionOutputGroupValue = VuoCompilerCodeGenUtilities::generateGetNodeContextExecutingGroup(module, triggerBlock, compositionContextValue);
3830  VuoCompilerCodeGenUtilities::generateLeaveDispatchGroup(module, triggerBlock, subcompositionOutputGroupValue);
3831  }
3832  }
3833 
3834  BranchInst::Create(finalBlock, triggerBlock);
3835 
3836  // Free the trigger worker's context.
3837  trigger->generateFreeContext(module, finalBlock, function);
3838  VuoCompilerCodeGenUtilities::generateReleaseCall(module, finalBlock, compositionStateValue);
3839 
3840  ReturnInst::Create(module->getContext(), finalBlock);
3841 
3842  return function;
3843 }
3844 
3848 void VuoCompilerBitcodeGenerator::generateAndScheduleChainWorkerFunctions(BasicBlock *schedulerBlock,
3849  Value *compositionStateValueInScheduler, Value *contextValueInScheduler,
3850  const vector<VuoCompilerChain *> &chainsToSchedule, VuoCompilerTriggerPort *trigger,
3851  const vector<VuoCompilerChain *> &allChains,
3852  const map<VuoCompilerChain *, vector<VuoCompilerChain *> > &chainsImmediatelyDownstream,
3853  const map<VuoCompilerChain *, vector<VuoCompilerChain *> > &chainsImmediatelyUpstream,
3854  set<VuoCompilerChain *> &chainsScheduled)
3855 {
3856  // Find the chains in chainsToSchedule that haven't already been scheduled.
3857  vector<VuoCompilerChain *> uniqueChainsToSchedule;
3858  for (vector<VuoCompilerChain *>::const_iterator i = chainsToSchedule.begin(); i != chainsToSchedule.end(); ++i)
3859  {
3860  VuoCompilerChain *chain = *i;
3861  if (chainsScheduled.find(chain) == chainsScheduled.end())
3862  {
3863  uniqueChainsToSchedule.push_back(chain);
3864  chainsScheduled.insert(chain);
3865  }
3866  }
3867 
3868  // Retain the context once for each chain to be scheduled.
3869  for (vector<VuoCompilerChain *>::const_iterator i = uniqueChainsToSchedule.begin(); i != uniqueChainsToSchedule.end(); ++i)
3870  VuoCompilerCodeGenUtilities::generateRetainCall(module, schedulerBlock, contextValueInScheduler);
3871 
3872  // Schedule each chain.
3873  for (vector<VuoCompilerChain *>::const_iterator i = uniqueChainsToSchedule.begin(); i != uniqueChainsToSchedule.end(); ++i)
3874  {
3875  VuoCompilerChain *chain = *i;
3876  generateAndScheduleChainWorkerFunction(schedulerBlock, compositionStateValueInScheduler, contextValueInScheduler,
3877  chain, trigger, allChains, chainsImmediatelyDownstream, chainsImmediatelyUpstream,
3878  chainsScheduled);
3879  }
3880 }
3881 
3885 void VuoCompilerBitcodeGenerator::generateAndScheduleChainWorkerFunction(BasicBlock *schedulerBlock,
3886  Value *compositionStateValueInScheduler, Value *contextValueInScheduler,
3887  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  int minThreadsNeeded, maxThreadsNeeded;
3894  graph->getWorkerThreadsNeeded(chain, minThreadsNeeded, maxThreadsNeeded);
3895 
3896  size_t chainIndex = find(allChains.begin(), allChains.end(), chain) - allChains.begin();
3897 
3898  vector<VuoCompilerChain *> upstreamChains;
3899  map<VuoCompilerChain *, vector<VuoCompilerChain *> >::const_iterator upstreamChainsIter = chainsImmediatelyUpstream.find(chain);
3900  if (upstreamChainsIter != chainsImmediatelyUpstream.end())
3901  upstreamChains = upstreamChainsIter->second;
3902 
3903  vector<size_t> upstreamChainIndices;
3904  for (vector<VuoCompilerChain *>::iterator i = upstreamChains.begin(); i != upstreamChains.end(); ++i)
3905  upstreamChainIndices.push_back( find(allChains.begin(), allChains.end(), *i) - allChains.begin() );
3906 
3907  // Call `vuoScheduleChainWorker` for the worker function implemented below.
3908  Function *chainWorker = chain->generateScheduleWorker(module, schedulerBlock, compositionStateValueInScheduler, contextValueInScheduler,
3909  trigger->getIdentifier(), minThreadsNeeded, maxThreadsNeeded, chainIndex,
3910  upstreamChainIndices);
3911 
3912  BasicBlock *chainBlock = BasicBlock::Create(module->getContext(), "", chainWorker, 0);
3913  Value *contextValueInChainWorker = chainWorker->arg_begin();
3914  Value *compositionStateValueInChainWorker = chain->generateCompositionStateValue(module, chainBlock, contextValueInChainWorker);
3915  Value *eventIdValue = chain->generateEventIdValue(module, chainBlock, contextValueInChainWorker);
3916 
3917  // Execute the chain.
3918  generateChainExecution(chainWorker, chainBlock, compositionStateValueInChainWorker, contextValueInChainWorker, eventIdValue, chain, trigger,
3919  allChains, chainsImmediatelyDownstream, chainsImmediatelyUpstream, chainsScheduled);
3920 
3921  // Release the chain worker's context.
3922  VuoCompilerCodeGenUtilities::generateReleaseCall(module, chainBlock, contextValueInChainWorker);
3923 
3924  ReturnInst::Create(module->getContext(), chainBlock);
3925 }
3926 
3930 void VuoCompilerBitcodeGenerator::generateChainExecution(Function *function, BasicBlock *&block,
3931  Value *compositionStateValue, Value *contextValue,
3932  Value *eventIdValue, VuoCompilerChain *chain, VuoCompilerTriggerPort *trigger,
3933  const vector<VuoCompilerChain *> &allChains,
3934  const map<VuoCompilerChain *, vector<VuoCompilerChain *> > &chainsImmediatelyDownstream,
3935  const map<VuoCompilerChain *, vector<VuoCompilerChain *> > &chainsImmediatelyUpstream,
3936  set<VuoCompilerChain *> &chainsScheduled)
3937 {
3938  size_t chainIndex = find(allChains.begin(), allChains.end(), chain) - allChains.begin();
3939  Value *chainIndexValue = ConstantInt::get(eventIdValue->getType(), chainIndex);
3940 
3941  // For each node in the chain...
3942  vector<VuoCompilerNode *> chainNodes = chain->getNodes();
3943  for (vector<VuoCompilerNode *>::iterator i = chainNodes.begin(); i != chainNodes.end(); ++i)
3944  {
3945  VuoCompilerNode *node = *i;
3946 
3947  Function *nodeExecutionFunction = executionFunctionForNode[node];
3948  if (! nodeExecutionFunction)
3949  {
3950  nodeExecutionFunction = generateNodeExecutionFunction(module, node);
3951  executionFunctionForNode[node] = nodeExecutionFunction;
3952  }
3953 
3954  Function *nodeTransmissionFunction = transmissionFunctionForNode[node];
3955  if (! nodeTransmissionFunction)
3956  {
3957  nodeTransmissionFunction = generateNodeTransmissionFunction(module, node);
3958  transmissionFunctionForNode[node] = nodeTransmissionFunction;
3959  }
3960 
3961  // If the event hit the node, call its event function and send telemetry.
3962  vector<Value *> nodeExecutionArgs;
3963  nodeExecutionArgs.push_back(compositionStateValue);
3964  nodeExecutionArgs.push_back(eventIdValue);
3965  nodeExecutionArgs.push_back(chainIndexValue);
3966  CallInst *isHitValue = CallInst::Create(nodeExecutionFunction, nodeExecutionArgs, "", block);
3967 
3968  // Whether or not the event hit the node, wait on any necessary downstream nodes.
3969  if (! (graph->isRepeatedInFeedbackLoop(node, trigger) && chain->isLastNodeInLoop()))
3970  {
3971  vector<VuoCompilerNode *> outputNodes = getNodesToWaitOnBeforeTransmission(trigger, node);
3972  generateLockNodes(module, block, compositionStateValue, outputNodes, eventIdValue);
3973  }
3974 
3975  // If the event hit the node, transmit events and data through its output cables and send telemetry.
3976  vector<Value *> nodeTransmissionArgs;
3977  nodeTransmissionArgs.push_back(compositionStateValue);
3978  nodeTransmissionArgs.push_back(isHitValue);
3979  CallInst::Create(nodeTransmissionFunction, nodeTransmissionArgs, "", block);
3980 
3981  // Whether or not the event hit the node, if this was the last time this event could reach the node,
3982  // signal the node's semaphore.
3983  if (! (graph->isRepeatedInFeedbackLoop(node, trigger) && ! chain->isLastNodeInLoop()))
3984  {
3985  // Special case: If this is the published output node in a subcomposition,
3986  // the node's semaphore is signaled in the node's execution function or the subcomposition's nodeEvent()/nodeInstanceEvent().
3987  if (! (! isTopLevelComposition && node == graph->getPublishedOutputNode()))
3988  generateUnlockNodes(module, block, compositionStateValue, vector<VuoCompilerNode *>(1, node));
3989  }
3990  }
3991 
3992  // Schedule any chains immediately downstream, if this chain is the one responsible for doing so.
3993  vector<VuoCompilerChain *> downstreamChains;
3994  map<VuoCompilerChain *, vector<VuoCompilerChain *> >::const_iterator downstreamChainsIter = chainsImmediatelyDownstream.find(chain);
3995  if (downstreamChainsIter != chainsImmediatelyDownstream.end())
3996  downstreamChains = downstreamChainsIter->second;
3997  if (! downstreamChains.empty())
3998  {
3999  vector<size_t> downstreamChainIndices;
4000  for (vector<VuoCompilerChain *>::iterator i = downstreamChains.begin(); i != downstreamChains.end(); ++i)
4001  downstreamChainIndices.push_back( find(allChains.begin(), allChains.end(), *i) - allChains.begin() );
4002 
4003  vector<VuoCompilerChain *> nextChains;
4004  for (vector<VuoCompilerChain *>::iterator i = downstreamChains.begin(); i != downstreamChains.end(); ++i)
4005  {
4006  VuoCompilerChain *downstreamChain = *i;
4007  nextChains.push_back(downstreamChain);
4008  }
4009 
4010  generateAndScheduleChainWorkerFunctions(block, compositionStateValue, contextValue, nextChains, trigger, allChains,
4011  chainsImmediatelyDownstream, chainsImmediatelyUpstream, chainsScheduled);
4012  }
4013 
4014  // Return the threads used by this chain to the thread pool.
4015  VuoCompilerCodeGenUtilities::generateReturnThreadsForChainWorker(module, block, eventIdValue, compositionStateValue, chainIndexValue);
4016 }
4017 
4063 Function * VuoCompilerBitcodeGenerator::generateNodeExecutionFunction(Module *module, VuoCompilerNode *node)
4064 {
4065  string functionName = node->getIdentifier() + "__execute";
4066  PointerType *pointerToCompositionStateType = PointerType::get(VuoCompilerCodeGenUtilities::getCompositionStateType(module), 0);
4067  Type *boolType = IntegerType::get(module->getContext(), 1);
4068  Type *eventIdType = VuoCompilerCodeGenUtilities::generateNoEventIdConstant(module)->getType();
4069  vector<Type *> params;
4070  params.push_back(pointerToCompositionStateType);
4071  params.push_back(eventIdType);
4072  params.push_back(eventIdType);
4073  FunctionType *functionType = FunctionType::get(boolType, params, false);
4074  Function *function = Function::Create(functionType, GlobalValue::InternalLinkage, functionName, module);
4075 
4076  Function::arg_iterator args = function->arg_begin();
4077  Value *compositionStateValue = args++;
4078  compositionStateValue->setName("compositionState");
4079  Value *eventIdValue = args++;
4080  eventIdValue->setName("eventId");
4081  Value *chainIndexValue = args++;
4082  chainIndexValue->setName("chainIndex");
4083 
4084  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, NULL);
4085  BasicBlock *finalBlock = BasicBlock::Create(module->getContext(), "final", function, NULL);
4086 
4087  Value *nodeContextValue = node->generateGetContext(module, initialBlock, compositionStateValue);
4088  Value *isHitValue = node->generateReceivedEventCondition(module, initialBlock, nodeContextValue);
4089 
4090  if (node == graph->getPublishedOutputNode())
4091  {
4092  if (isTopLevelComposition)
4093  {
4094  VuoCompilerCodeGenUtilities::generateSendEventFinished(module, initialBlock, compositionStateValue, eventIdValue);
4095 
4096  BranchInst::Create(finalBlock, initialBlock);
4097  }
4098  else
4099  {
4100  // Call the trigger functions for any published trigger ports that the event has hit.
4101 
4102  BasicBlock *currBlock = initialBlock;
4103 
4104  Value *compositionContextValue = VuoCompilerCodeGenUtilities::generateGetCompositionContext(module, currBlock, compositionStateValue);
4105 
4106  vector<VuoPublishedPort *> publishedInputPorts = composition->getBase()->getPublishedInputPorts();
4107  vector<VuoPublishedPort *> publishedOutputPorts = composition->getBase()->getPublishedOutputPorts();
4108 
4109  set<string> publishedOutputTriggerNames = graph->getPublishedOutputTriggers();
4110 
4111  for (size_t publishedPortIndex = 0; publishedPortIndex < publishedOutputPorts.size(); ++publishedPortIndex)
4112  {
4113  VuoPort *port = graph->getInputPortOnPublishedOutputNode(publishedPortIndex);
4114 
4115  Value *isPortHitValue = node->generateReceivedEventCondition(module, currBlock, nodeContextValue, vector<VuoPort *>(1, port));
4116 
4117  if (publishedOutputTriggerNames.find( port->getClass()->getName() ) != publishedOutputTriggerNames.end())
4118  {
4119  BasicBlock *triggerBlock = BasicBlock::Create(module->getContext(), "trigger", function, NULL);
4120  BasicBlock *nextBlock = BasicBlock::Create(module->getContext(), "next", function, NULL);
4121  BranchInst::Create(triggerBlock, nextBlock, isPortHitValue, currBlock);
4122 
4123  VuoCompilerInputEventPort *eventPort = static_cast<VuoCompilerInputEventPort *>( port->getCompiler() );
4124  VuoCompilerInputEventPortClass *eventPortClass = static_cast<VuoCompilerInputEventPortClass *>( port->getClass()->getCompiler() );
4125  VuoType *dataType = eventPort->getDataVuoType();
4126 
4127  FunctionType *triggerFunctionType = VuoCompilerCodeGenUtilities::getFunctionType(module, dataType);
4128 
4129  vector<Value *> args;
4130  if (dataType)
4131  {
4132  Value *dataValue = eventPort->generateLoadData(module, triggerBlock, nodeContextValue);
4133  bool isPassedByValue = dataType->getCompiler()->getFunctionParameterAttributes().hasAttrSomewhere(Attribute::ByVal);
4134  bool isLoweredToTwoParameters = eventPortClass->getDataClass()->isLoweredToTwoParameters();
4135  Value *secondArg = NULL;
4136  Value **secondArgIfNeeded = (isLoweredToTwoParameters ? &secondArg : NULL);
4137  Value *arg = VuoCompilerCodeGenUtilities::convertArgumentToParameterType(dataValue, triggerFunctionType, 0, isPassedByValue,
4138  secondArgIfNeeded, module, triggerBlock);
4139  args.push_back(arg);
4140  if (secondArg)
4141  args.push_back(secondArg);
4142  }
4143 
4144  int indexInSubcompositionPorts = VuoNodeClass::unreservedInputPortStartIndex + publishedInputPorts.size() +
4145  VuoNodeClass::unreservedOutputPortStartIndex + publishedPortIndex;
4146 
4147  Value *portContextValue = VuoCompilerCodeGenUtilities::generateGetNodeContextPortContext(module, triggerBlock, compositionContextValue, indexInSubcompositionPorts);
4148  Value *triggerFunction = VuoCompilerCodeGenUtilities::generateGetPortContextTriggerFunction(module, triggerBlock, portContextValue, triggerFunctionType);
4149 
4150  CallInst::Create(triggerFunction, args, "", triggerBlock);
4151  BranchInst::Create(nextBlock, triggerBlock);
4152 
4153  currBlock = nextBlock;
4154  }
4155  else
4156  {
4157  VuoCompilerCodeGenUtilities::generateSetNodeContextOutputEvent(module, currBlock, compositionContextValue, publishedPortIndex, isPortHitValue);
4158  }
4159  }
4160 
4161  // If this event (which may or may not have actually hit the published output node) is from
4162  // nodeEvent()/nodeInstanceEvent() or an event spun off of it, and is the final one to complete, then...
4163 
4164  Value *subcompositionFinishedValue = VuoCompilerCodeGenUtilities::generateFinishedExecutingEvent(module, currBlock, compositionContextValue, eventIdValue);
4165  ConstantInt *falseValue = ConstantInt::get(static_cast<IntegerType *>(subcompositionFinishedValue->getType()), 0);
4166  ICmpInst *subcompositionFinishedIsTrue = new ICmpInst(*currBlock, ICmpInst::ICMP_NE, subcompositionFinishedValue, falseValue, "");
4167  BasicBlock *leaveBlock = BasicBlock::Create(module->getContext(), "leave", function, NULL);
4168  BasicBlock *signalBlock = BasicBlock::Create(module->getContext(), "signal", function, NULL);
4169  BranchInst::Create(leaveBlock, signalBlock, subcompositionFinishedIsTrue, currBlock);
4170 
4171  // Leave the dispatch group waited on by nodeEvent()/nodeInstanceEvent().
4172 
4173  Value *subcompositionOutputGroupValue = VuoCompilerCodeGenUtilities::generateGetNodeContextExecutingGroup(module, leaveBlock, compositionContextValue);
4174  VuoCompilerCodeGenUtilities::generateLeaveDispatchGroup(module, leaveBlock, subcompositionOutputGroupValue);
4175  BranchInst::Create(finalBlock, leaveBlock);
4176 
4177  // Otherwise, signal the published output node's semaphore so that the remaining events can claim it.
4178  // (For the final event, the published output node's semaphore is signaled in nodeEvent()/nodeInstanceEvent().)
4179 
4180  generateUnlockNodes(module, signalBlock, compositionStateValue, vector<VuoCompilerNode *>(1, node));
4181  BranchInst::Create(finalBlock, signalBlock);
4182  }
4183  }
4184  else
4185  {
4186  // If the node received an event, then...
4187  BasicBlock *executeBlock = BasicBlock::Create(module->getContext(), "execute", function, NULL);
4188  BranchInst::Create(executeBlock, finalBlock, isHitValue, initialBlock);
4189 
4190  if (node->getBase()->getNodeClass()->getCompiler()->isSubcomposition())
4191  {
4192  // Pass the event ID to the subcomposition.
4193  VuoCompilerCodeGenUtilities::generateStartedExecutingEvent(module, executeBlock, nodeContextValue, eventIdValue);
4194 
4195  // Pass the chain's reserved threads to the subcomposition.
4196  Value *compositionIdentifierValue = VuoCompilerCodeGenUtilities::generateGetCompositionStateCompositionIdentifier(module, executeBlock, compositionStateValue);
4197  Value *subcompositionIdentifierValue = node->generateSubcompositionIdentifierValue(module, executeBlock, compositionIdentifierValue);
4199  eventIdValue, compositionStateValue, chainIndexValue,
4200  subcompositionIdentifierValue);
4201  VuoCompilerCodeGenUtilities::generateFreeCall(module, executeBlock, subcompositionIdentifierValue);
4202  }
4203 
4204  // Call the node's event function, and send telemetry that the node's execution has started and finished.
4205  bool shouldSendTelemetry = (node != graph->getPublishedInputNode());
4206  generateNodeExecution(function, executeBlock, compositionStateValue, node, shouldSendTelemetry);
4207  BranchInst::Create(finalBlock, executeBlock);
4208  }
4209 
4210  ReturnInst::Create(module->getContext(), isHitValue, finalBlock);
4211 
4212  return function;
4213 }
4214 
4239 Function * VuoCompilerBitcodeGenerator::generateNodeTransmissionFunction(Module *module, VuoCompilerNode *node)
4240 {
4241  string functionName = node->getIdentifier() + "__transmit";
4242  PointerType *pointerToCompositionStateType = PointerType::get(VuoCompilerCodeGenUtilities::getCompositionStateType(module), 0);
4243  Type *boolType = IntegerType::get(module->getContext(), 1);
4244  vector<Type *> params;
4245  params.push_back(pointerToCompositionStateType);
4246  params.push_back(boolType);
4247  FunctionType *functionType = FunctionType::get(Type::getVoidTy(module->getContext()), params, false);
4248  Function *function = Function::Create(functionType, GlobalValue::InternalLinkage, functionName, module);
4249 
4250  Function::arg_iterator args = function->arg_begin();
4251  Value *compositionStateValue = args++;
4252  compositionStateValue->setName("compositionState");
4253  Value *isHitValue = args++;
4254  isHitValue->setName("isHit");
4255 
4256  BasicBlock *initialBlock = BasicBlock::Create(module->getContext(), "initial", function, NULL);
4257  BasicBlock *transmitBlock = BasicBlock::Create(module->getContext(), "transmit", function, NULL);
4258  BasicBlock *finalBlock = BasicBlock::Create(module->getContext(), "final", function, NULL);
4259 
4260  // If the node received an event, then...
4261  BranchInst::Create(transmitBlock, finalBlock, isHitValue, initialBlock);
4262 
4263  Value *nodeContextValue = node->generateGetContext(module, transmitBlock, compositionStateValue);
4264 
4265  if (node == graph->getPublishedOutputNode())
4266  {
4267  if (isTopLevelComposition)
4268  generateTelemetryFromPublishedOutputNode(function, transmitBlock, compositionStateValue, nodeContextValue, node);
4269  }
4270  else
4271  {
4272  // Transmit events and data through the node's outgoing cables, and send telemetry for port updates.
4273  generateTransmissionFromNode(function, transmitBlock, compositionStateValue, nodeContextValue, node);
4274  }
4275 
4276  // Reset the node's event inputs and outputs.
4277  VuoCompilerCodeGenUtilities::generateResetNodeContextEvents(module, transmitBlock, nodeContextValue);
4278 
4279  BranchInst::Create(finalBlock, transmitBlock);
4280  ReturnInst::Create(module->getContext(), finalBlock);
4281 
4282  return function;
4283 }
4284 
4289 {
4290  this->debugMode = debugMode;
4291 }