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