Vuo 2.4.4
Loading...
Searching...
No Matches
VuoCompilerType.cc
Go to the documentation of this file.
1
10#include <sstream>
15#include "VuoCompilerIssue.hh"
16#include "VuoCompilerType.hh"
17#include "VuoType.hh"
18
22VuoCompilerType::VuoCompilerType(string typeName, Module *module)
23 : VuoBaseDetail<VuoType>("VuoCompilerType", new VuoType(typeName)),
24 VuoCompilerModule(getBase(), module)
25{
26 getBase()->setCompiler(this);
27
28 makeFromJsonFunction = NULL;
29 getJsonFunction = NULL;
30 getInterprocessJsonFunction = NULL;
31 getStringFunction = NULL;
32 getInterprocessStringFunction = NULL;
33 getSummaryFunction = NULL;
34 areEqualFunction = NULL;
35 isLessThanFunction = NULL;
36 retainFunction = NULL;
37 releaseFunction = NULL;
38 llvmArgumentType = nullptr;
39 llvmSecondArgumentType = nullptr;
40 llvmReturnType = nullptr;
41 isReturnPassedAsArgument = false;
42
43 parse();
44}
45
50VuoCompilerType * VuoCompilerType::newType(string typeName, Module *module)
51{
52 VuoCompilerType *type = nullptr;
53
54 if (isType(typeName, module))
55 {
56 VuoCompilerCompoundType *compoundType = VuoCompilerCompoundType::newType(typeName, module);
57 if (compoundType)
58 type = compoundType;
59 else
60 type = new VuoCompilerType(typeName, module);
61 }
62
63 return type;
64}
65
70bool VuoCompilerType::isType(string typeName, Module *module)
71{
72 return (module->getNamedValue(typeName + "_makeFromJson") != NULL);
73}
74
78void VuoCompilerType::parse(void)
79{
81
82 string typeName = getBase()->getModuleKey();
83 makeFromJsonFunction = parser->getFunction(typeName + "_makeFromJson");
84 getJsonFunction = parser->getFunction(typeName + "_getJson");
85 getInterprocessJsonFunction = parser->getFunction(typeName + "_getInterprocessJson");
86 getSummaryFunction = parser->getFunction(typeName + "_getSummary");
87 areEqualFunction = parser->getFunction(typeName + "_areEqual");
88 isLessThanFunction = parser->getFunction(typeName + "_isLessThan");
89
90 if (! makeFromJsonFunction)
91 VUserLog("Error: Couldn't find %s_makeFromJson() function.", typeName.c_str());
92 if (! getJsonFunction)
93 VUserLog("Error: Couldn't find %s_getJson() function.", typeName.c_str());
94 if (! getSummaryFunction)
95 VUserLog("Error: Couldn't find %s_getSummary() function.", typeName.c_str());
96
97 llvmArgumentType = getJsonFunction->getFunctionType()->getParamType(0);
98 if (getJsonFunction->getFunctionType()->getNumParams() == 2)
99 llvmSecondArgumentType = getJsonFunction->getFunctionType()->getParamType(1);
100 else if (getJsonFunction->getFunctionType()->getNumParams() != 1)
101 {
102 string s;
103 raw_string_ostream oss(s);
104 oss << "Expected a function with 1 or 2 parameters, got " << getJsonFunction->getFunctionType()->getNumParams() << " for function `";
105 getJsonFunction->getFunctionType()->print(oss);
106 oss << "`.";
107 VuoCompilerIssue issue(VuoCompilerIssue::Error, "compiling composition", "", "Unsupported port data type", oss.str());
108 throw VuoCompilerException(issue);
109 }
110
111 llvmReturnType = makeFromJsonFunction->getReturnType();
112 if (llvmReturnType->isVoidTy())
113 {
114 isReturnPassedAsArgument = true;
115 llvmReturnType = makeFromJsonFunction->arg_begin()->getType();
116 }
117
118 parseOrGenerateStringFromValueFunction(false);
119 if (getInterprocessJsonFunction)
120 parseOrGenerateStringFromValueFunction(true);
121
122 parseOrGenerateRetainOrReleaseFunction(true);
123 parseOrGenerateRetainOrReleaseFunction(false);
124}
125
129set<string> VuoCompilerType::globalsToRename(void)
130{
131 set<string> globals = VuoCompilerModule::globalsToRename();
132 return globals;
133}
134
153void VuoCompilerType::parseOrGenerateStringFromValueFunction(bool isInterprocess)
154{
155 string functionName = (getBase()->getModuleKey() + (isInterprocess ? "_getInterprocessString" : "_getString")).c_str();
156 Function *function = parser->getFunction(functionName);
157
158 Function *chosenJsonFromValueFunction = (isInterprocess ? getInterprocessJsonFunction : getJsonFunction);
159
160 if (! function)
161 {
162 PointerType *pointerToCharType = PointerType::get(IntegerType::get(module->getContext(), 8), 0);
163 FunctionType *getJsonFunctionType = chosenJsonFromValueFunction->getFunctionType();
164
165 Type *returnType = pointerToCharType;
166
167 vector<Type *> functionParams;
168 for (int i = 0; i < getJsonFunctionType->getNumParams(); ++i)
169 functionParams.push_back(getJsonFunctionType->getParamType(i));
170
171 FunctionType *functionType = FunctionType::get(returnType, functionParams, false);
172 function = Function::Create(functionType, GlobalValue::ExternalLinkage, functionName, module);
173
175 }
176
177 if (function->isDeclaration())
178 {
179 BasicBlock *block = BasicBlock::Create(module->getContext(), "", function);
180
181 int argIndex = 0;
182 for (Function::arg_iterator args = function->arg_begin(); args != function->arg_end(); ++args, ++argIndex)
183 {
184 Value *value = args;
185 ostringstream argName;
186 argName << "value" << argIndex;
187 value->setName(argName.str().c_str());
188 }
189
190 Function *jsonObjectToJsonStringExtFunction = VuoCompilerCodeGenUtilities::getJsonObjectToJsonStringExtFunction(module);
191 Function *strdupFunction = VuoCompilerCodeGenUtilities::getStrdupFunction(module);
192 Function *jsonObjectPutFunction = VuoCompilerCodeGenUtilities::getJsonObjectPutFunction(module);
193
194 vector<Value *> getJsonArgs;
195 for (Function::arg_iterator args = function->arg_begin(); args != function->arg_end(); ++args)
196 {
197 Value *value = args;
198 getJsonArgs.push_back(value);
199 }
200 CallInst *getJsonReturn = CallInst::Create(chosenJsonFromValueFunction, getJsonArgs, "", block);
201
202 BitCastInst *getJsonReturnCasted = new BitCastInst(getJsonReturn, jsonObjectToJsonStringExtFunction->getFunctionType()->getParamType(0), "", block);
203
204 vector<Value *> jsonObjectToJsonStringExtArgs;
205 jsonObjectToJsonStringExtArgs.push_back(getJsonReturnCasted);
206 jsonObjectToJsonStringExtArgs.push_back(ConstantInt::get(module->getContext(), APInt(32, JSON_C_TO_STRING_PLAIN)));
207 CallInst *jsonObjectToJsonStringExtReturn = CallInst::Create(jsonObjectToJsonStringExtFunction, jsonObjectToJsonStringExtArgs, "", block);
208
209 CallInst *strdupReturn = CallInst::Create(strdupFunction, jsonObjectToJsonStringExtReturn, "", block);
210
211 CallInst::Create(jsonObjectPutFunction, getJsonReturnCasted, "", block);
212
213 ReturnInst::Create(module->getContext(), strdupReturn, block);
214 }
215
216 if (isInterprocess)
217 getInterprocessStringFunction = function;
218 else
219 getStringFunction = function;
220}
221
238void VuoCompilerType::parseOrGenerateRetainOrReleaseFunction(bool isRetain)
239{
240 string functionName{getBase()->getModuleKey() + (isRetain ? "_retain" : "_release")};
241 Function *function = parser->getFunction(functionName);
242
243 if (! function)
244 {
245 vector<Type *> functionParams;
246 functionParams.push_back(llvmArgumentType);
247 if (llvmSecondArgumentType)
248 functionParams.push_back(llvmSecondArgumentType);
249
250 FunctionType *functionType = FunctionType::get(Type::getVoidTy(module->getContext()), functionParams, false);
251 function = Function::Create(functionType, GlobalValue::ExternalLinkage, functionName, module);
252
254 }
255
256 if (function->isDeclaration())
257 {
258 BasicBlock *block = BasicBlock::Create(module->getContext(), "", function);
259
260 Function::arg_iterator args = function->arg_begin();
261 Value *arg = args++;
262
263 if (!llvmSecondArgumentType)
264 {
265 if (isReturnPassedAsArgument && VuoCompilerCodeGenUtilities::isPointerToStruct(arg->getType()))
266 {
267 // The data type is a struct that is passed by reference (LLVM's `byval` attribute on x86_64).
268 arg = new LoadInst(arg, "unloweredStruct", false, block);
269 }
270
272 }
273 else
274 {
275 if (llvmArgumentType->isPointerTy())
276 {
277 // The data type is a struct with pointer field(s), lowered to 2 arguments, the 1st of which is a pointer.
279 }
280
281 if (llvmSecondArgumentType->isPointerTy())
282 {
283 // The data type is a struct with pointer field(s), lowered to 2 arguments, the 2nd of which is a pointer.
284 Value *secondArg = args++;
285 VuoCompilerCodeGenUtilities::generateRetainOrReleaseCall(module, block, secondArg, isRetain);
286 }
287 }
288
289 ReturnInst::Create(module->getContext(), block);
290 }
291
292 if (isRetain)
293 retainFunction = function;
294 else
295 releaseFunction = function;
296}
297
313Value * VuoCompilerType::generateRetainedValueFromString(Module *module, BasicBlock *block, Value *stringValue)
314{
315 Function *makeFromJsonFunctionInModule = declareFunctionInModule(module, makeFromJsonFunction);
316
317 Function *jsonTokenerParseFunction = VuoCompilerCodeGenUtilities::getJsonTokenerParseFunction(module);
318 Value *jsonValue = CallInst::Create(jsonTokenerParseFunction, stringValue, "valueAsJson", block);
319
320 vector<Value *> makeFromJsonArgs;
321 int jsonParamIndex = makeFromJsonFunctionInModule->getFunctionType()->getNumParams() - 1;
322 Type *jsonParamType = static_cast<PointerType *>(makeFromJsonFunctionInModule->getFunctionType()->getParamType(jsonParamIndex));
323 Value *jsonArg = new BitCastInst(jsonValue, jsonParamType, "", block);
324 makeFromJsonArgs.push_back(jsonArg);
325
326 Value *dataPointer = nullptr;
328 {
329 Value *makeFromJsonReturn = VuoCompilerCodeGenUtilities::callFunctionWithStructReturn(makeFromJsonFunctionInModule, makeFromJsonArgs, block);
330 dataPointer = new BitCastInst(makeFromJsonReturn, llvmReturnType, "valueFromString", block);
331 }
332 else
333 {
334 Value *makeFromJsonReturn = CallInst::Create(makeFromJsonFunctionInModule, makeFromJsonArgs, "valueFromString", block);
335 dataPointer = VuoCompilerCodeGenUtilities::generatePointerToValue(block, makeFromJsonReturn);
336 }
337
338 generateRetainCall(module, block, dataPointer);
339
340 Function *jsonObjectPutFunction = VuoCompilerCodeGenUtilities::getJsonObjectPutFunction(module);
341 CallInst::Create(jsonObjectPutFunction, jsonValue, "", block);
342
343 return dataPointer;
344}
345
354Value * VuoCompilerType::generateStringFromValueFunctionCall(Module *module, BasicBlock *block, Value *arg)
355{
356 return generateFunctionCallWithTypeParameter(module, block, arg, getStringFunction);
357}
358
367Value * VuoCompilerType::generateInterprocessStringFromValueFunctionCall(Module *module, BasicBlock *block, Value *arg)
368{
369 if (getInterprocessStringFunction)
370 return generateFunctionCallWithTypeParameter(module, block, arg, getInterprocessStringFunction);
371 else
372 return generateStringFromValueFunctionCall(module, block, arg);
373}
374
383Value * VuoCompilerType::generateSummaryFromValueFunctionCall(Module *module, BasicBlock *block, Value *arg)
384{
385 return generateFunctionCallWithTypeParameter(module, block, arg, getSummaryFunction);
386}
387
391void VuoCompilerType::generateRetainCall(Module *module, BasicBlock *block, Value *arg)
392{
393 generateFunctionCallWithTypeParameter(module, block, arg, retainFunction);
394}
395
399void VuoCompilerType::generateReleaseCall(Module *module, BasicBlock *block, Value *arg)
400{
401 generateFunctionCallWithTypeParameter(module, block, arg, releaseFunction);
402}
403
409vector<Value *> VuoCompilerType::convertPortDataToArgs(Module *module, BasicBlock *block, Value *arg, FunctionType *functionType, int parameterIndex,
410 bool isUnloweredStructPointerParameter)
411{
412 vector<Value *> args;
413 if (!llvmSecondArgumentType)
414 {
415 Type *parameterType = functionType->getParamType(parameterIndex);
416
417 if (!isReturnPassedAsArgument)
418 {
419 bool isLoweredAsUsual = true;
420 if (parameterType->isPointerTy() && !llvmArgumentType->isPointerTy())
421 isLoweredAsUsual = false;
422
423 if (isLoweredAsUsual)
424 {
425 // The data type is either not lowered or lowered to 1 parameter.
426 arg = new BitCastInst(arg, PointerType::getUnqual(parameterType), "dataPointerCasted", block);
427 arg = new LoadInst(arg, "data", false, block);
428 }
429 else
430 {
431 // The data type is normally lowered to 1 parameter, but here is passed by reference ('byval').
432 arg = new BitCastInst(arg, parameterType, "dataCasted", block);
433 }
434 }
435 else
436 {
437 // The data type is a struct that is passed by reference (LLVM's `byval` attribute on x86_64).
438 arg = new BitCastInst(arg, parameterType, "dataCasted", block);
439 }
440
441 args.push_back(arg);
442 }
443 else
444 {
445 if (! isUnloweredStructPointerParameter)
446 {
447 // The data type is lowered to 2 parameters.
448 arg = new BitCastInst(arg, PointerType::getUnqual(llvmReturnType), "dataStructCasted", block);
449 for (int i = 0; i < 2; ++i)
450 {
451 Value *currArg = VuoCompilerCodeGenUtilities::generateGetStructPointerElement(module, block, arg, i);
452 if (currArg->getType()->isPointerTy())
453 {
454 Type *parameterType = functionType->getParamType(parameterIndex + i);
455 currArg = new BitCastInst(currArg, parameterType, "dataCasted", block);
456 }
457 args.push_back(currArg);
458 }
459 }
460 else
461 {
462 // The data type is normally lowered to 2 parameters, but here is a struct passed by reference (`byval`).
463 Type *parameterType = functionType->getParamType(parameterIndex);
464 arg = new BitCastInst(arg, parameterType, "dataCasted", block);
465 args.push_back(arg);
466 }
467 }
468
469 return args;
470}
471
476Value * VuoCompilerType::convertArgsToPortData(Module *module, BasicBlock *block, Function *function, int parameterIndex)
477{
478 vector<Value *> args;
479 args.push_back( VuoCompilerCodeGenUtilities::getArgumentAtIndex(function, parameterIndex) );
480 if (llvmSecondArgumentType)
481 args.push_back( VuoCompilerCodeGenUtilities::getArgumentAtIndex(function, parameterIndex+1) );
482
483 if (!llvmSecondArgumentType)
484 {
485 if (!isReturnPassedAsArgument)
486 {
487 Value *argPointer = VuoCompilerCodeGenUtilities::generatePointerToValue(block, args[0]);
488 return new BitCastInst(argPointer, PointerType::getUnqual(llvmReturnType), "dataPointerCasted", block);
489 }
490 else
491 return args[0];
492 }
493 else
494 {
495 size_t totalArgByteCount = 0;
496 for (auto arg : args)
497 totalArgByteCount += module->getDataLayout().getTypeStoreSize(arg->getType());
498
499 Value *dataPointer = new AllocaInst(llvmReturnType, 0, "dataPointer", block);
500 Value *dataPointerAsBytePointer = new BitCastInst(dataPointer, PointerType::getUnqual(IntegerType::get(module->getContext(), 8)), "dataBytePointer", block);
501
502 size_t argByteOffset = 0;
503 for (auto arg : args)
504 {
505 Value *argPointer = VuoCompilerCodeGenUtilities::generatePointerToValue(block, arg);
506 Value *offsetValue = ConstantInt::get(module->getContext(), APInt(64, argByteOffset));
507 Value *offsetDataPointer = GetElementPtrInst::Create(nullptr, dataPointerAsBytePointer, offsetValue, "", block);
508 size_t storeByteCount = module->getDataLayout().getTypeStoreSize(arg->getType());
509 size_t allocByteCount = module->getDataLayout().getTypeAllocSize(arg->getType());
510 VuoCompilerCodeGenUtilities::generateMemoryCopy(module, block, argPointer, offsetDataPointer, storeByteCount);
511 argByteOffset += allocByteCount;
512 }
513
514 return dataPointer;
515 }
516}
517
525Value * VuoCompilerType::generateFunctionCallWithTypeParameter(Module *module, BasicBlock *block, Value *arg, Function *sourceFunction)
526{
527 Function *function = declareFunctionInModule(module, sourceFunction);
528 vector<Value *> args = convertPortDataToArgs(module, block, arg, function->getFunctionType(), 0, false);
529 return CallInst::Create(function, args, "", block);
530}
531
536{
537 Type *type = llvmReturnType;
538 if (isReturnPassedAsArgument)
539 type = static_cast<PointerType *>(llvmReturnType)->getElementType();
540
541 return module->getDataLayout().getTypeAllocSize(type);
542}
543
548{
549 Type *type = llvmReturnType;
550 if (isReturnPassedAsArgument)
551 type = static_cast<PointerType *>(llvmReturnType)->getElementType();
552
553 return module->getDataLayout().getTypeStoreSize(type);
554}
555
559Value * VuoCompilerType::convertToPortData(BasicBlock *block, Value *voidPointer)
560{
561 Type *type = PointerType::getUnqual(llvmReturnType);
562 if (isReturnPassedAsArgument)
563 type = llvmReturnType;
564
565 return new BitCastInst(voidPointer, type, "", block);
566}
567
572{
573 vector<Type *> types;
574 types.push_back(llvmArgumentType);
575 if (llvmSecondArgumentType)
576 types.push_back(llvmSecondArgumentType);
577 return types;
578}
579
584{
585 return PointerType::getUnqual(llvmReturnType);
586}
587
594{
595 return getJsonFunction->getAttributes();
596}
597
602{
603 VuoCompilerCodeGenUtilities::copyParameterAttributes(getJsonFunction, dstFunction);
604}
605
609void VuoCompilerType::copyFunctionParameterAttributes(Module *module, CallInst *dstCall)
610{
611 VuoCompilerCodeGenUtilities::copyParameterAttributes(module, getJsonFunction, dstCall);
612}
613
618{
619 if (! type)
620 return false;
621
623}
624
629{
630 return getInterprocessStringFunction != NULL;
631}
632
637{
638 return areEqualFunction != NULL && isLessThanFunction != NULL;
639}