Vuo  2.4.1
VuoCompilerNode.cc
Go to the documentation of this file.
1
10#include <sstream>
11
18#include "VuoCompilerIssue.hh"
19#include "VuoCompilerNode.hh"
23#include "VuoCompilerType.hh"
24#include "VuoNode.hh"
25#include "VuoNodeClass.hh"
26#include "VuoPort.hh"
27#include "VuoStringUtilities.hh"
28#include "VuoType.hh"
29
30
35 : VuoBaseDetail<VuoNode>("VuoNode", baseNode)
36{
37 getBase()->setCompiler(this);
38
39 instanceData = NULL;
41 if (instanceDataClass)
42 instanceData = new VuoCompilerInstanceData(instanceDataClass);
43
44 graphvizIdentifier = getGraphvizIdentifierPrefix();
45
46 constantsCache = NULL;
47 indexInOrderedNodes = ULONG_MAX - 1;
48}
49
53void VuoCompilerNode::setIndexInOrderedNodes(size_t indexInOrderedNodes)
54{
55 this->indexInOrderedNodes = indexInOrderedNodes;
56}
57
62{
63 return indexInOrderedNodes;
64}
65
70{
71 this->constantsCache = constantsCache;
72
73 vector<VuoPort *> inputPorts = getBase()->getInputPorts();
74 vector<VuoPort *> outputPorts = getBase()->getOutputPorts();
75 vector<VuoPort *> ports;
76 ports.insert(ports.end(), inputPorts.begin(), inputPorts.end());
77 ports.insert(ports.end(), outputPorts.begin(), outputPorts.end());
78 for (vector<VuoPort *>::iterator i = ports.begin(); i != ports.end(); ++i)
79 {
80 VuoCompilerPort *port = static_cast<VuoCompilerPort *>( (*i)->getCompiler() );
81 port->setConstantsCache(constantsCache);
82 }
83}
84
89{
90 return constantsCache->get(getIdentifier());
91}
92
99Value * VuoCompilerNode::generateSubcompositionIdentifierValue(Module *module, BasicBlock *block, Value *compositionIdentifierValue)
100{
101 vector<Value *> identifierParts;
102 identifierParts.push_back(compositionIdentifierValue);
103 identifierParts.push_back(constantsCache->get("/" + getIdentifier()));
104 return VuoCompilerCodeGenUtilities::generateStringConcatenation(module, block, identifierParts, constantsCache);
105}
106
110Value * VuoCompilerNode::generateGetContext(Module *module, BasicBlock *block, Value *compositionStateValue)
111{
112 return VuoCompilerCodeGenUtilities::generateGetNodeContext(module, block, compositionStateValue, indexInOrderedNodes);
113}
114
119void VuoCompilerNode::generateAddMetadata(Module *module, BasicBlock *block, Value *compositionStateValue,
120 const vector<VuoCompilerType *> &orderedTypes,
121 Function *compositionCreateContextForNode,
122 Function *compositionSetPortValueFunction, Function *compositionGetPortValueFunction,
123 Function *compositionFireTriggerPortEventFunction, Function *compositionReleasePortDataFunction)
124{
125 Function *subcompositionFunctionSrc = getBase()->getNodeClass()->getCompiler()->getCompositionAddNodeMetadataFunction();
126
127 Value *nodeIdentifierValue = generateIdentifierValue(module);
128 VuoCompilerCodeGenUtilities::generateAddNodeMetadata(module, block, compositionStateValue, nodeIdentifierValue,
129 compositionCreateContextForNode, compositionSetPortValueFunction,
130 compositionGetPortValueFunction, compositionFireTriggerPortEventFunction,
131 compositionReleasePortDataFunction);
132
133 vector<VuoPort *> inputPorts = getBase()->getInputPorts();
134 vector<VuoPort *> outputPorts = getBase()->getOutputPorts();
135 vector<VuoPort *> ports;
136 ports.insert(ports.end(), inputPorts.begin(), inputPorts.end());
137 ports.insert(ports.end(), outputPorts.begin(), outputPorts.end());
138 for (vector<VuoPort *>::iterator i = ports.begin(); i != ports.end(); ++i)
139 {
140 VuoCompilerPort *port = static_cast<VuoCompilerPort *>( (*i)->getCompiler() );
141
142 Value *portIdentifierValue = constantsCache->get(port->getIdentifier());
143 Value *portNameValue = constantsCache->get(port->getBase()->getClass()->getName());
144
145 size_t typeIndex;
146 string initialValue;
147
148 VuoType *dataType = port->getDataVuoType();
149 if (dataType)
150 {
151 vector<VuoCompilerType *>::const_iterator typeIter = find(orderedTypes.begin(), orderedTypes.end(), dataType->getCompiler());
152 typeIndex = typeIter - orderedTypes.begin();
153
154 VuoCompilerInputEventPort *inputEventPort = dynamic_cast<VuoCompilerInputEventPort *>(port);
155 initialValue = (inputEventPort ? inputEventPort->getData()->getInitialValue() : "");
156 }
157 else
158 {
159 typeIndex = orderedTypes.size();
160 }
161
162 Value *initialValueValue = constantsCache->get(initialValue);
163
164 VuoCompilerCodeGenUtilities::generateAddPortMetadata(module, block, compositionStateValue, portIdentifierValue,
165 portNameValue, typeIndex, initialValueValue);
166 }
167
168 if (subcompositionFunctionSrc)
169 {
170 Value *runtimeStateValue = VuoCompilerCodeGenUtilities::generateGetCompositionStateRuntimeState(module, block, compositionStateValue);
171 Value *compositionIdentifierValue = VuoCompilerCodeGenUtilities::generateGetCompositionStateCompositionIdentifier(module, block, compositionStateValue);
172 Value *subcompositionIdentifierValue = generateSubcompositionIdentifierValue(module, block, compositionIdentifierValue);
173 Value *subcompositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, runtimeStateValue, subcompositionIdentifierValue);
174
175 Function *subcompositionFunctionDst = VuoCompilerModule::declareFunctionInModule(module, subcompositionFunctionSrc);
176 Value *arg = new BitCastInst(subcompositionStateValue, subcompositionFunctionDst->getFunctionType()->getParamType(0), "", block);
177 CallInst::Create(subcompositionFunctionDst, arg, "", block);
178
179 VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, subcompositionStateValue);
180 VuoCompilerCodeGenUtilities::generateFreeCall(module, block, subcompositionIdentifierValue);
181 }
182}
183
187Value * VuoCompilerNode::generateCreateContext(Module *module, BasicBlock *block)
188{
189 // Create the node context.
190
191 bool isSubcomposition = getBase()->getNodeClass()->getCompiler()->isSubcomposition();
192 unsigned long publishedOutputPortCount = (isSubcomposition ?
194
195 Value * nodeContextValue = VuoCompilerCodeGenUtilities::generateCreateNodeContext(module, block, instanceData, isSubcomposition, publishedOutputPortCount);
196
197 // Create each port's context.
198
199 vector<VuoPort *> inputPorts = getBase()->getInputPorts();
200 vector<VuoPort *> outputPorts = getBase()->getOutputPorts();
201 vector<VuoPort *> ports;
202 ports.insert(ports.end(), inputPorts.begin(), inputPorts.end());
203 ports.insert(ports.end(), outputPorts.begin(), outputPorts.end());
204 vector<Value *> portContextValues;
205 for (vector<VuoPort *>::iterator i = ports.begin(); i != ports.end(); ++i)
206 {
207 VuoCompilerPort *port = static_cast<VuoCompilerPort *>( (*i)->getCompiler() );
208
209 Value *portContextValue = port->generateCreatePortContext(module, block);
210 portContextValues.push_back(portContextValue);
211 }
212
213 VuoCompilerCodeGenUtilities::generateSetNodeContextPortContexts(module, block, nodeContextValue, portContextValues);
214
215 return nodeContextValue;
216}
217
230void VuoCompilerNode::generateEventFunctionCall(Module *module, Function *function, BasicBlock *&currentBlock,
231 Value *compositionStateValue)
232{
233 Function *functionSrc = getBase()->getNodeClass()->getCompiler()->getEventFunction();
234
235 Value *nodeContextValue = generateGetContext(module, currentBlock, compositionStateValue);
236
237 map<VuoCompilerEventPort *, Value *> portContextForEventPort;
238 vector<VuoPort *> inputPorts = getBase()->getInputPorts();
239 vector<VuoPort *> outputPorts = getBase()->getOutputPorts();
240 vector<VuoPort *> ports;
241 ports.insert(ports.end(), inputPorts.begin(), inputPorts.end());
242 ports.insert(ports.end(), outputPorts.begin(), outputPorts.end());
243 for (vector<VuoPort *>::iterator i = ports.begin(); i != ports.end(); ++i)
244 {
245 VuoCompilerEventPort *eventPort = dynamic_cast<VuoCompilerEventPort *>((*i)->getCompiler());
246 if (eventPort)
247 portContextForEventPort[eventPort] = eventPort->generateGetPortContext(module, currentBlock, nodeContextValue);
248 }
249
250 generateFunctionCall(functionSrc, module, currentBlock, compositionStateValue, nodeContextValue, portContextForEventPort);
251
252 // The output port should transmit an event if any non-blocking input port received the event.
253 // The output port should not transmit an event if no non-blocking or door input ports received the event.
254 // Otherwise, the output port's event transmission is handled by the node class implementation.
255
256 vector<VuoPort *> nonBlockingInputPorts;
257 vector<VuoPort *> doorInputPorts;
258 for (vector<VuoPort *>::iterator i = inputPorts.begin(); i != inputPorts.end(); ++i)
259 {
260 VuoPortClass::EventBlocking eventBlocking = (*i)->getClass()->getEventBlocking();
261 if (eventBlocking == VuoPortClass::EventBlocking_None)
262 nonBlockingInputPorts.push_back(*i);
263 else if (eventBlocking == VuoPortClass::EventBlocking_Door)
264 doorInputPorts.push_back(*i);
265 }
266
267 Value *eventHitNonBlockingInputPort = generateReceivedEventCondition(module, currentBlock, nodeContextValue, nonBlockingInputPorts,
268 portContextForEventPort);
269 Value *transmitForAllOutputPorts = eventHitNonBlockingInputPort;
270
271 BasicBlock *handleTransmissionBlock = NULL;
272 BasicBlock *nextBlock = NULL;
273 if (! doorInputPorts.empty())
274 {
275 handleTransmissionBlock = BasicBlock::Create(module->getContext(), "handleTransmission", function, 0);
276 nextBlock = BasicBlock::Create(module->getContext(), "next", function, 0);
277
278 Value *eventHitDoorInputPort = generateReceivedEventCondition(module, currentBlock, nodeContextValue, doorInputPorts,
279 portContextForEventPort);
280
281 Value *blockForAllOutputPorts = BinaryOperator::Create(Instruction::And,
282 BinaryOperator::CreateNot(eventHitNonBlockingInputPort, "", currentBlock),
283 BinaryOperator::CreateNot(eventHitDoorInputPort, "", currentBlock),
284 "", currentBlock);
285 Value *handleTransmission = BinaryOperator::Create(Instruction::Or, transmitForAllOutputPorts, blockForAllOutputPorts, "", currentBlock);
286
287 Constant *zeroValue = ConstantInt::get(transmitForAllOutputPorts->getType(), 0);
288 ICmpInst *handleTransmissionComparison = new ICmpInst(*currentBlock, ICmpInst::ICMP_NE, handleTransmission, zeroValue, "");
289 BranchInst::Create(handleTransmissionBlock, nextBlock, handleTransmissionComparison, currentBlock);
290 }
291 else
292 {
293 handleTransmissionBlock = currentBlock;
294 }
295
296 for (vector<VuoPort *>::iterator i = outputPorts.begin(); i != outputPorts.end(); ++i)
297 {
298 VuoCompilerOutputEventPort *eventPort = dynamic_cast<VuoCompilerOutputEventPort *>((*i)->getCompiler());
299 if (eventPort)
300 {
301 Value *portContextValue = portContextForEventPort[eventPort];
302 eventPort->generateStoreEvent(module, handleTransmissionBlock, nodeContextValue, transmitForAllOutputPorts, portContextValue);
303 }
304 }
305
306 if (! doorInputPorts.empty())
307 {
308 BranchInst::Create(nextBlock, handleTransmissionBlock);
309 currentBlock = nextBlock;
310 }
311}
312
324void VuoCompilerNode::generateInitFunctionCall(Module *module, BasicBlock *block, Value *compositionStateValue)
325{
326 Function *functionSrc = getBase()->getNodeClass()->getCompiler()->getInitFunction();
327
328 Value *nodeContextValue = generateGetContext(module, block, compositionStateValue);
329 CallInst *call = generateFunctionCall(functionSrc, module, block, compositionStateValue, nodeContextValue);
330
331 Type *instanceDataType = instanceData->getType();
332 Value *callCasted = VuoCompilerCodeGenUtilities::generateTypeCast(module, block, call, instanceDataType);
333 instanceData->generateStore(module, block, nodeContextValue, callCasted);
334
335 // Retain the instance data.
336 Value *instanceDataValue = instanceData->generateLoad(module, block, nodeContextValue);
337 VuoCompilerCodeGenUtilities::generateRetainCall(module, block, instanceDataValue);
338}
339
350void VuoCompilerNode::generateFiniFunctionCall(Module *module, BasicBlock *block, Value *compositionStateValue)
351{
352 Function *functionSrc = getBase()->getNodeClass()->getCompiler()->getFiniFunction();
353
354 Value *nodeContextValue = generateGetContext(module, block, compositionStateValue);
355 if (functionSrc)
356 generateFunctionCall(functionSrc, module, block, compositionStateValue, nodeContextValue);
357
358 // Release the instance data.
359 Value *instanceDataValue = instanceData->generateLoad(module, block, nodeContextValue);
360 VuoCompilerCodeGenUtilities::generateReleaseCall(module, block, instanceDataValue);
361}
362
371void VuoCompilerNode::generateCallbackStartFunctionCall(Module *module, BasicBlock *block, Value *compositionStateValue)
372{
373 Function *functionSrc = getBase()->getNodeClass()->getCompiler()->getCallbackStartFunction();
374 if (! functionSrc)
375 return;
376
377 Value *nodeContextValue = generateGetContext(module, block, compositionStateValue);
378 generateFunctionCall(functionSrc, module, block, compositionStateValue, nodeContextValue);
379}
380
389void VuoCompilerNode::generateCallbackUpdateFunctionCall(Module *module, BasicBlock *block, Value *compositionStateValue)
390{
391 Function *functionSrc = getBase()->getNodeClass()->getCompiler()->getCallbackUpdateFunction();
392 if (! functionSrc)
393 return;
394
395 Value *nodeContextValue = generateGetContext(module, block, compositionStateValue);
396 generateFunctionCall(functionSrc, module, block, compositionStateValue, nodeContextValue);
397}
398
407void VuoCompilerNode::generateCallbackStopFunctionCall(Module *module, BasicBlock *block, Value *compositionStateValue)
408{
409 Function *functionSrc = getBase()->getNodeClass()->getCompiler()->getCallbackStopFunction();
410 if (! functionSrc)
411 return;
412
413 Value *nodeContextValue = generateGetContext(module, block, compositionStateValue);
414 generateFunctionCall(functionSrc, module, block, compositionStateValue, nodeContextValue);
415}
416
428CallInst * VuoCompilerNode::generateFunctionCall(Function *functionSrc, Module *module, BasicBlock *block,
429 Value *compositionStateValue, Value *nodeContextValue,
430 const map<VuoCompilerEventPort *, Value *> &portContextForEventPort)
431{
432 Function *functionDst = VuoCompilerModule::declareFunctionInModule(module, functionSrc);
433
434 vector<Value *> args(functionDst->getFunctionType()->getNumParams());
435
436 // Set up the argument for the composition state (if a subcomposition).
437 Value *subcompositionIdentifierValue = NULL;
438 Value *subcompositionStateValue = NULL;
439 if (getBase()->getNodeClass()->getCompiler()->isSubcomposition())
440 {
441 Value *runtimeStateValue = VuoCompilerCodeGenUtilities::generateGetCompositionStateRuntimeState(module, block, compositionStateValue);
442 Value *compositionIdentifierValue = VuoCompilerCodeGenUtilities::generateGetCompositionStateCompositionIdentifier(module, block, compositionStateValue);
443 subcompositionIdentifierValue = generateSubcompositionIdentifierValue(module, block, compositionIdentifierValue);
444 subcompositionStateValue = VuoCompilerCodeGenUtilities::generateCreateCompositionState(module, block, runtimeStateValue, subcompositionIdentifierValue);
445 args[0] = new BitCastInst(subcompositionStateValue, functionDst->getFunctionType()->getParamType(0), "", block);
446 }
447
448 // Set up the arguments for input ports.
449 vector<VuoPort *> inputPorts = getBase()->getInputPorts();
450 for (vector<VuoPort *>::iterator i = inputPorts.begin(); i != inputPorts.end(); ++i)
451 {
452 VuoCompilerInputEventPort *eventPort = dynamic_cast<VuoCompilerInputEventPort *>((*i)->getCompiler());
453
454 VuoCompilerInputData *data = eventPort->getData();
455 bool isEventArgumentInFunction = isArgumentInFunction(eventPort, functionSrc);
456 bool isDataArgumentInFunction = data && isArgumentInFunction(data, functionSrc);
457
458 if (isEventArgumentInFunction || isDataArgumentInFunction)
459 {
460 map<VuoCompilerEventPort *, Value *>::const_iterator iter = portContextForEventPort.find(eventPort);
461 Value *portContextValue = (iter != portContextForEventPort.end() ?
462 iter->second :
463 eventPort->generateGetPortContext(module, block, nodeContextValue));
464
465 if (isEventArgumentInFunction)
466 {
467 size_t index = getArgumentIndexInFunction(eventPort, functionSrc);
468 args[index] = eventPort->generateLoadEvent(module, block, nodeContextValue, portContextValue);
469 }
470
471 if (isDataArgumentInFunction)
472 {
473 size_t index = getArgumentIndexInFunction(data, functionSrc);
474 Value *pointerToDataAsVoidPointer = VuoCompilerCodeGenUtilities::generateGetPortContextDataVariableAsVoidPointer(module, block, portContextValue);
475 vector<Value *> loweredArgs = eventPort->getDataType()->convertPortDataToArgs(module, block, pointerToDataAsVoidPointer,
476 functionDst->getFunctionType(), index,
477 isUnloweredStructPointerParameter(data, functionSrc));
478 for (auto a : loweredArgs)
479 args[index++] = a;
480 }
481 }
482 }
483
484 // Set up the arguments for output ports.
485 vector<VuoPort *> outputPorts = getBase()->getOutputPorts();
486 map<VuoCompilerOutputEventPort *, Value *> outputPortDataVariables;
487 map<VuoCompilerOutputEventPort *, AllocaInst *> outputPortEventVariables;
488 for (vector<VuoPort *>::iterator i = outputPorts.begin(); i != outputPorts.end(); ++i)
489 {
490 VuoCompilerOutputEventPort *eventPort = dynamic_cast<VuoCompilerOutputEventPort *>((*i)->getCompiler());
491 if (eventPort)
492 {
493 VuoCompilerOutputData *data = eventPort->getData();
494 bool isEventArgumentInFunction = isArgumentInFunction(eventPort, functionSrc);
495 bool isDataArgumentInFunction = data && isArgumentInFunction(data, functionSrc);
496
497 if (isEventArgumentInFunction)
498 {
499 size_t index = getArgumentIndexInFunction(eventPort, functionSrc);
500 PointerType *eventPointerType = static_cast<PointerType *>( functionDst->getFunctionType()->getParamType(index) );
501 AllocaInst *arg = new AllocaInst(eventPointerType->getElementType(), 0, "", block);
502 new StoreInst(ConstantInt::get(eventPointerType->getElementType(), 0), arg, block);
503 outputPortEventVariables[eventPort] = arg;
504 args[index] = arg;
505 }
506
507 if (isDataArgumentInFunction)
508 {
509 map<VuoCompilerEventPort *, Value *>::const_iterator iter = portContextForEventPort.find(eventPort);
510 Value *portContextValue = (iter != portContextForEventPort.end() ?
511 iter->second :
512 eventPort->generateGetPortContext(module, block, nodeContextValue));
513
514 size_t index = getArgumentIndexInFunction(data, functionSrc);
515 VuoCompilerType *type = eventPort->getDataVuoType()->getCompiler();
516 Value *dataPointer = VuoCompilerCodeGenUtilities::generateGetPortContextDataVariable(module, block, portContextValue, type);
517 outputPortDataVariables[eventPort] = dataPointer;
518
519 Value *arg = new BitCastInst(dataPointer, functionDst->getFunctionType()->getParamType(index), "dataArgumentCasted", block);
520 args[index] = arg;
521 }
522 }
523 else
524 {
525 VuoCompilerTriggerPort *triggerPort = (VuoCompilerTriggerPort *)((*i)->getCompiler());
526 if (isArgumentInFunction(triggerPort, functionSrc))
527 {
528 size_t index = getArgumentIndexInFunction(triggerPort, functionSrc);
529 Value *triggerFunction = triggerPort->generateLoadFunction(module, block, nodeContextValue);
530 args[index] = new BitCastInst(triggerFunction, functionDst->getFunctionType()->getParamType(index), "triggerArgumentCasted", block);
531 }
532 }
533 }
534
535 // Set up the argument for the instance data (if it exists).
536 Value *instanceDataVariable = NULL;
537 if (instanceData && isArgumentInFunction(instanceData, functionSrc))
538 {
539 Type *type = instanceData->getType();
540 instanceDataVariable = VuoCompilerCodeGenUtilities::generateGetNodeContextInstanceDataVariable(module, block, nodeContextValue, type);
541
542 size_t index = getArgumentIndexInFunction(instanceData, functionSrc);
543 Value *arg = instanceDataVariable;
544 args[index] = new BitCastInst(arg, functionDst->getFunctionType()->getParamType(index), "", block);
545 if (!args[index])
546 {
547 VUserLog("Warning: Couldn't convert argument for instance data of function %s; not generating call.", functionDst->getName().str().c_str());
548 return nullptr;
549 }
550 }
551
552 // Save the old output port values so they can be released later.
553 map<VuoCompilerOutputEventPort *, Value *> oldOutputDataPointers;
554 for (map<VuoCompilerOutputEventPort *, Value *>::iterator i = outputPortDataVariables.begin(); i != outputPortDataVariables.end(); ++i)
555 {
556 VuoCompilerOutputEventPort *eventPort = i->first;
557 Value *dataVariable = i->second; // For VuoText, this is `char **`
558 Value *dataPointer = new AllocaInst(static_cast<PointerType *>(dataVariable->getType())->getElementType(), 0, "", block); // For VuoText, this is `char **`
559 Value *dataValue = new LoadInst(dataVariable, "", false, block); // For VuoText, this is `char *`
560 new StoreInst(dataValue, dataPointer, block);
561 oldOutputDataPointers[eventPort] = dataPointer;
562 }
563
564 // Save the old instance data value so it can be released later.
565 Value *oldInstanceDataValue = NULL;
566 if (instanceDataVariable)
567 {
568 oldInstanceDataValue = new LoadInst(instanceDataVariable, "", false, block);
569 }
570
572
573 {
574 int i = 0;
575 for (auto arg : args)
576 {
577 if (!arg)
578 {
579 string s;
580 raw_string_ostream type(s);
581 functionDst->getFunctionType()->getParamType(i)->print(type);
582 ostringstream argIndex;
583 argIndex << i;
584 string details = "When trying to generate a call to function " + functionDst->getName().str() +
585 ", argument " + argIndex.str() + " (" + type.str() + ") was missing.";
586 VuoCompilerIssue issue(VuoCompilerIssue::Error, "compiling composition", "", "", details);
587 throw VuoCompilerException(issue);
588 }
589 ++i;
590 }
591 }
592
593 // Call the node class's function.
594 CallInst *call = CallInst::Create(functionDst, args, "", block);
595
597
598 // Save the output events from temporary variables to the ports.
599 // (The temporary variables are needed to avoid mismatched types between the parameters and the arguments, e.g. i8* vs. i64*.)
600 for (map<VuoCompilerOutputEventPort *, AllocaInst *>::iterator i = outputPortEventVariables.begin(); i != outputPortEventVariables.end(); ++i)
601 {
602 VuoCompilerOutputEventPort *eventPort = i->first;
603 AllocaInst *eventVariable = i->second;
604 Value *eventValue = new LoadInst(eventVariable, "", false, block);
605 eventPort->generateStoreEvent(module, block, nodeContextValue, eventValue);
606 }
607
608 // Retain the new output port values.
609 for (map<VuoCompilerOutputEventPort *, Value *>::iterator i = outputPortDataVariables.begin(); i != outputPortDataVariables.end(); ++i)
610 {
611 VuoCompilerOutputEventPort *eventPort = i->first;
612 Value *dataVariable = i->second;
613
614 VuoCompilerType *type = eventPort->getDataVuoType()->getCompiler();
615 type->generateRetainCall(module, block, dataVariable);
616 }
617
618 // Release the old output port values.
619 for (map<VuoCompilerOutputEventPort *, Value *>::iterator i = oldOutputDataPointers.begin(); i != oldOutputDataPointers.end(); ++i)
620 {
621 VuoCompilerOutputEventPort *eventPort = i->first;
622 Value *oldOutputDataPointer = i->second; // For VuoText, this is `char **`
623
624 VuoCompilerType *type = eventPort->getDataVuoType()->getCompiler();
625 type->generateReleaseCall(module, block, oldOutputDataPointer);
626 }
627
628 if (instanceDataVariable)
629 {
630 // Retain the new instance data value.
631 Value *instanceDataValue = new LoadInst(instanceDataVariable, "", false, block);
632 VuoCompilerCodeGenUtilities::generateRetainCall(module, block, instanceDataValue);
633
634 // Release the old instance data value.
635 VuoCompilerCodeGenUtilities::generateReleaseCall(module, block, oldInstanceDataValue);
636 }
637
638 if (getBase()->getNodeClass()->getCompiler()->isSubcomposition())
639 {
640 VuoCompilerCodeGenUtilities::generateFreeCompositionState(module, block, subcompositionStateValue);
641 VuoCompilerCodeGenUtilities::generateFreeCall(module, block, subcompositionIdentifierValue);
642 }
643
644 return call;
645}
646
653bool VuoCompilerNode::isArgumentInFunction(VuoCompilerNodeArgument *argument, Function *function)
654{
655 VuoCompilerNodeArgumentClass *argumentClass = argument->getBase()->getClass()->getCompiler();
656 if (function == getBase()->getNodeClass()->getCompiler()->getEventFunction())
657 return argumentClass->isInEventFunction();
658 else if (function == getBase()->getNodeClass()->getCompiler()->getInitFunction())
659 return argumentClass->isInInitFunction();
660 else if (function == getBase()->getNodeClass()->getCompiler()->getCallbackStartFunction())
661 return argumentClass->isInCallbackStartFunction();
662 else if (function == getBase()->getNodeClass()->getCompiler()->getCallbackUpdateFunction())
663 return argumentClass->isInCallbackUpdateFunction();
664 else if (function == getBase()->getNodeClass()->getCompiler()->getCallbackStopFunction())
665 return argumentClass->isInCallbackStopFunction();
666 else if (instanceData == argument &&
667 (function == getBase()->getNodeClass()->getCompiler()->getFiniFunction()))
668 return true;
669 return false;
670}
671
678size_t VuoCompilerNode::getArgumentIndexInFunction(VuoCompilerNodeArgument *argument, Function *function)
679{
680 VuoCompilerNodeArgumentClass *argumentClass = argument->getBase()->getClass()->getCompiler();
681 if (function == getBase()->getNodeClass()->getCompiler()->getEventFunction())
682 return argumentClass->getIndexInEventFunction();
683 else if (function == getBase()->getNodeClass()->getCompiler()->getInitFunction())
684 return argumentClass->getIndexInInitFunction();
685 else if (function == getBase()->getNodeClass()->getCompiler()->getFiniFunction())
686 return (getBase()->getNodeClass()->getCompiler()->isSubcomposition() ? 1 : 0);
687 else if (function == getBase()->getNodeClass()->getCompiler()->getCallbackStartFunction())
688 return argumentClass->getIndexInCallbackStartFunction();
689 else if (function == getBase()->getNodeClass()->getCompiler()->getCallbackUpdateFunction())
690 return argumentClass->getIndexInCallbackUpdateFunction();
691 else if (function == getBase()->getNodeClass()->getCompiler()->getCallbackStopFunction())
692 return argumentClass->getIndexInCallbackStopFunction();
693 return 0;
694}
695
703bool VuoCompilerNode::isUnloweredStructPointerParameter(VuoCompilerInputData *inputData, Function *function)
704{
705 VuoCompilerInputDataClass *inputDataClass = static_cast<VuoCompilerInputDataClass *>(inputData->getBase()->getClass()->getCompiler());
706 if (function == getBase()->getNodeClass()->getCompiler()->getEventFunction())
707 return inputDataClass->isUnloweredStructPointerInEventFunction();
708 else if (function == getBase()->getNodeClass()->getCompiler()->getInitFunction())
709 return inputDataClass->isUnloweredStructPointerInInitFunction();
710 else if (function == getBase()->getNodeClass()->getCompiler()->getCallbackStartFunction())
712 else if (function == getBase()->getNodeClass()->getCompiler()->getCallbackUpdateFunction())
714 else if (function == getBase()->getNodeClass()->getCompiler()->getCallbackStopFunction())
715 return inputDataClass->isUnloweredStructPointerInCallbackStopFunction();
716 return false;
717}
718
722Value * VuoCompilerNode::generateReceivedEventCondition(Module *module, BasicBlock *block, Value *nodeContextValue)
723{
724 return generateReceivedEventCondition(module, block, nodeContextValue, getBase()->getInputPorts());
725}
726
730Value * VuoCompilerNode::generateReceivedEventCondition(Module *module, BasicBlock *block, Value *nodeContextValue,
731 vector<VuoPort *> selectedInputPorts,
732 const map<VuoCompilerEventPort *, Value *> &portContextForEventPort)
733{
734 Value *conditionValue = ConstantInt::getFalse(block->getContext());
735 for (vector<VuoPort *>::iterator i = selectedInputPorts.begin(); i != selectedInputPorts.end(); ++i)
736 {
737 VuoCompilerInputEventPort *eventPort = dynamic_cast<VuoCompilerInputEventPort *>((*i)->getCompiler());
738 if (eventPort)
739 {
740 map<VuoCompilerEventPort *, Value *>::const_iterator iter = portContextForEventPort.find(eventPort);
741 Value *portContextValue = (iter != portContextForEventPort.end() ?
742 iter->second :
743 eventPort->generateGetPortContext(module, block, nodeContextValue));
744
745 Value *pushValue = eventPort->generateLoadEvent(module, block, nodeContextValue, portContextValue);
746 conditionValue = BinaryOperator::Create(Instruction::Or, conditionValue, pushValue, "", block);
747 }
748 }
749 return conditionValue;
750}
751
756{
757 return instanceData;
758}
759
767{
768 return getGraphvizIdentifier();
769}
770
780{
781 string titleWithoutSpaces = VuoStringUtilities::convertToCamelCase(getBase()->getTitle(), true, false, false);
782
783 if (titleWithoutSpaces.empty())
784 return "Node";
785 else
786 return titleWithoutSpaces;
787}
788
792void VuoCompilerNode::setGraphvizIdentifier(string graphvizIdentifier)
793{
794 this->graphvizIdentifier = graphvizIdentifier;
795}
796
801{
802 return graphvizIdentifier;
803}
804
809string VuoCompilerNode::getGraphvizDeclaration(bool shouldPrintPosition, double xPositionOffset, double yPositionOffset,
810 VuoPort *manuallyFirableInputPort)
811{
812 ostringstream declaration;
813
814 vector<VuoPort *> inputPorts = getBase()->getInputPorts();
815 vector<VuoPort *> outputPorts = getBase()->getOutputPorts();
816
817 // name
818 declaration << getGraphvizIdentifier();
819
820 // type
821 declaration << " [type=\"" << getBase()->getNodeClass()->getClassName() << "\"";
822
823 // version
824 declaration << " version=\"" << getBase()->getNodeClass()->getVersion() << "\"";
825
826 // label
827 declaration << " label=\"" << VuoStringUtilities::transcodeToGraphvizIdentifier(getBase()->getTitle());
828 for (vector<VuoPort *>::iterator i = inputPorts.begin(); i != inputPorts.end(); ++i)
829 {
830 string portName = VuoStringUtilities::transcodeToGraphvizIdentifier((*i)->getClass()->getName());
831 declaration << "|<" << portName << ">" << portName << "\\l";
832 }
833 for (vector<VuoPort *>::iterator i = outputPorts.begin(); i != outputPorts.end(); ++i)
834 {
835 string portName = VuoStringUtilities::transcodeToGraphvizIdentifier((*i)->getClass()->getName());
836 declaration << "|<" << portName << ">" << portName << "\\r";
837 }
838 declaration << "\"";
839
840 // position
841 if (shouldPrintPosition)
842 declaration << " pos=\"" << getBase()->getX()+xPositionOffset << "," << getBase()->getY()+yPositionOffset << "\"";
843
844 // collapsed
845 if (getBase()->isCollapsed())
846 declaration << " collapsed";
847
848 // tint color
849 if (getBase()->getTintColor() != VuoNode::TintNone)
850 declaration << " fillcolor=\"" << getBase()->getTintColorGraphvizName() << "\"";
851
852 // constant values
853 for (vector<VuoPort *>::iterator i = inputPorts.begin(); i != inputPorts.end(); ++i)
854 {
855 VuoPort *port = *i;
856 VuoCompilerInputEventPort *eventPort = static_cast<VuoCompilerInputEventPort *>(port->getCompiler());
857 VuoCompilerInputData *data = eventPort->getData();
858 if (data && (! eventPort->hasConnectedDataCable() && ! data->getInitialValue().empty()))
859 {
860 string portConstant = data->getInitialValue();
861 string escapedPortConstant = VuoStringUtilities::transcodeToGraphvizIdentifier(portConstant);
862 declaration << " _" << port->getClass()->getName() << "=\"" << escapedPortConstant << "\"";
863 }
864 }
865
866 // event throttling
867 for (vector<VuoPort *>::iterator i = outputPorts.begin(); i != outputPorts.end(); ++i)
868 {
869 VuoPort *port = *i;
871 {
872 string eventThrottling = (port->getEventThrottling() == VuoPortClass::EventThrottling_Enqueue ? "enqueue" : "drop");
873 declaration << " _" << port->getClass()->getName() << "_eventThrottling=\"" << eventThrottling << "\"";
874 }
875 }
876
877 // manually firable input port
878 if (manuallyFirableInputPort)
879 declaration << " _" << manuallyFirableInputPort->getClass()->getName() << "_manuallyFirable=\"yes\"";
880
881 declaration << "];";
882
883 return declaration.str();
884}