Vuo 2.4.2
Loading...
Searching...
No Matches
VuoCompilerType.cc
Go to the documentation of this file.
1
10#include <sstream>
14#include "VuoCompilerIssue.hh"
15#include "VuoCompilerType.hh"
16#include "VuoType.hh"
17
21VuoCompilerType::VuoCompilerType(string typeName, Module *module)
22 : VuoBaseDetail<VuoType>("VuoCompilerType", new VuoType(typeName)),
23 VuoCompilerModule(getBase(), module)
24{
25 getBase()->setCompiler(this);
26
27 makeFromJsonFunction = NULL;
28 getJsonFunction = NULL;
29 getInterprocessJsonFunction = NULL;
30 getStringFunction = NULL;
31 getInterprocessStringFunction = NULL;
32 getSummaryFunction = NULL;
33 areEqualFunction = NULL;
34 isLessThanFunction = NULL;
35 retainFunction = NULL;
36 releaseFunction = NULL;
37 llvmArgumentType = nullptr;
38 llvmSecondArgumentType = nullptr;
39 llvmReturnType = nullptr;
40 isReturnPassedAsArgument = false;
41
42 parse();
43}
44
49VuoCompilerType * VuoCompilerType::newType(string typeName, Module *module)
50{
51 if (! isType(typeName, module))
52 return NULL;
53
54 return new VuoCompilerType(typeName, module);
55}
56
61bool VuoCompilerType::isType(string typeName, Module *module)
62{
63 return (module->getNamedValue(typeName + "_makeFromJson") != NULL);
64}
65
69void VuoCompilerType::parse(void)
70{
72
73 string typeName = getBase()->getModuleKey();
74 makeFromJsonFunction = parser->getFunction(typeName + "_makeFromJson");
75 getJsonFunction = parser->getFunction(typeName + "_getJson");
76 getInterprocessJsonFunction = parser->getFunction(typeName + "_getInterprocessJson");
77 getSummaryFunction = parser->getFunction(typeName + "_getSummary");
78 areEqualFunction = parser->getFunction(typeName + "_areEqual");
79 isLessThanFunction = parser->getFunction(typeName + "_isLessThan");
80
81 if (! makeFromJsonFunction)
82 VUserLog("Error: Couldn't find %s_makeFromJson() function.", typeName.c_str());
83 if (! getJsonFunction)
84 VUserLog("Error: Couldn't find %s_getJson() function.", typeName.c_str());
85 if (! getSummaryFunction)
86 VUserLog("Error: Couldn't find %s_getSummary() function.", typeName.c_str());
87
88 llvmArgumentType = getJsonFunction->getFunctionType()->getParamType(0);
89 if (getJsonFunction->getFunctionType()->getNumParams() == 2)
90 llvmSecondArgumentType = getJsonFunction->getFunctionType()->getParamType(1);
91 else if (getJsonFunction->getFunctionType()->getNumParams() != 1)
92 {
93 string s;
94 raw_string_ostream oss(s);
95 oss << "Expected a function with 1 or 2 parameters, got " << getJsonFunction->getFunctionType()->getNumParams() << " for function `";
96 getJsonFunction->getFunctionType()->print(oss);
97 oss << "`.";
98 VuoCompilerIssue issue(VuoCompilerIssue::Error, "compiling composition", "", "Unsupported port data type", oss.str());
99 throw VuoCompilerException(issue);
100 }
101
102 llvmReturnType = makeFromJsonFunction->getReturnType();
103 if (llvmReturnType->isVoidTy())
104 {
105 isReturnPassedAsArgument = true;
106 llvmReturnType = makeFromJsonFunction->arg_begin()->getType();
107 }
108
109 parseOrGenerateStringFromValueFunction(false);
110 if (getInterprocessJsonFunction)
111 parseOrGenerateStringFromValueFunction(true);
112
113 parseOrGenerateRetainOrReleaseFunction(true);
114 parseOrGenerateRetainOrReleaseFunction(false);
115}
116
120set<string> VuoCompilerType::globalsToRename(void)
121{
122 set<string> globals = VuoCompilerModule::globalsToRename();
123 return globals;
124}
125
144void VuoCompilerType::parseOrGenerateStringFromValueFunction(bool isInterprocess)
145{
146 string functionName = (getBase()->getModuleKey() + (isInterprocess ? "_getInterprocessString" : "_getString")).c_str();
147 Function *function = parser->getFunction(functionName);
148
149 Function *chosenJsonFromValueFunction = (isInterprocess ? getInterprocessJsonFunction : getJsonFunction);
150
151 if (! function)
152 {
153 PointerType *pointerToCharType = PointerType::get(IntegerType::get(module->getContext(), 8), 0);
154 FunctionType *getJsonFunctionType = chosenJsonFromValueFunction->getFunctionType();
155
156 Type *returnType = pointerToCharType;
157
158 vector<Type *> functionParams;
159 for (int i = 0; i < getJsonFunctionType->getNumParams(); ++i)
160 functionParams.push_back(getJsonFunctionType->getParamType(i));
161
162 FunctionType *functionType = FunctionType::get(returnType, functionParams, false);
163 function = Function::Create(functionType, GlobalValue::ExternalLinkage, functionName, module);
164
166 }
167
168 if (function->isDeclaration())
169 {
170 BasicBlock *block = BasicBlock::Create(module->getContext(), "", function);
171
172 int argIndex = 0;
173 for (Function::arg_iterator args = function->arg_begin(); args != function->arg_end(); ++args, ++argIndex)
174 {
175 Value *value = args;
176 ostringstream argName;
177 argName << "value" << argIndex;
178 value->setName(argName.str().c_str());
179 }
180
181 Function *jsonObjectToJsonStringExtFunction = VuoCompilerCodeGenUtilities::getJsonObjectToJsonStringExtFunction(module);
182 Function *strdupFunction = VuoCompilerCodeGenUtilities::getStrdupFunction(module);
183 Function *jsonObjectPutFunction = VuoCompilerCodeGenUtilities::getJsonObjectPutFunction(module);
184
185 vector<Value *> getJsonArgs;
186 for (Function::arg_iterator args = function->arg_begin(); args != function->arg_end(); ++args)
187 {
188 Value *value = args;
189 getJsonArgs.push_back(value);
190 }
191 CallInst *getJsonReturn = CallInst::Create(chosenJsonFromValueFunction, getJsonArgs, "", block);
192
193 vector<Value *> jsonObjectToJsonStringExtArgs;
194 jsonObjectToJsonStringExtArgs.push_back(getJsonReturn);
195 jsonObjectToJsonStringExtArgs.push_back(ConstantInt::get(module->getContext(), APInt(32, JSON_C_TO_STRING_PLAIN)));
196 CallInst *jsonObjectToJsonStringExtReturn = CallInst::Create(jsonObjectToJsonStringExtFunction, jsonObjectToJsonStringExtArgs, "", block);
197
198 CallInst *strdupReturn = CallInst::Create(strdupFunction, jsonObjectToJsonStringExtReturn, "", block);
199
200 CallInst::Create(jsonObjectPutFunction, getJsonReturn, "", block);
201
202 ReturnInst::Create(module->getContext(), strdupReturn, block);
203 }
204
205 if (isInterprocess)
206 getInterprocessStringFunction = function;
207 else
208 getStringFunction = function;
209}
210
227void VuoCompilerType::parseOrGenerateRetainOrReleaseFunction(bool isRetain)
228{
229 string functionName{getBase()->getModuleKey() + (isRetain ? "_retain" : "_release")};
230 Function *function = parser->getFunction(functionName);
231
232 if (! function)
233 {
234 vector<Type *> functionParams;
235 functionParams.push_back(llvmArgumentType);
236 if (llvmSecondArgumentType)
237 functionParams.push_back(llvmSecondArgumentType);
238
239 FunctionType *functionType = FunctionType::get(Type::getVoidTy(module->getContext()), functionParams, false);
240 function = Function::Create(functionType, GlobalValue::ExternalLinkage, functionName, module);
241
243 }
244
245 if (function->isDeclaration())
246 {
247 BasicBlock *block = BasicBlock::Create(module->getContext(), "", function);
248
249 Function::arg_iterator args = function->arg_begin();
250 Value *arg = args++;
251
252 if (!llvmSecondArgumentType)
253 {
254 if (isReturnPassedAsArgument && VuoCompilerCodeGenUtilities::isPointerToStruct(arg->getType()))
255 {
256 // The data type is a struct that is passed by reference (LLVM's `byval` attribute on x86_64).
257 arg = new LoadInst(arg, "unloweredStruct", false, block);
258 }
259
261 }
262 else
263 {
264 if (llvmArgumentType->isPointerTy())
265 {
266 // The data type is a struct with pointer field(s), lowered to 2 arguments, the 1st of which is a pointer.
268 }
269
270 if (llvmSecondArgumentType->isPointerTy())
271 {
272 // The data type is a struct with pointer field(s), lowered to 2 arguments, the 2nd of which is a pointer.
273 Value *secondArg = args++;
275 }
276 }
277
278 ReturnInst::Create(module->getContext(), block);
279 }
280
281 if (isRetain)
282 retainFunction = function;
283 else
284 releaseFunction = function;
285}
286
302Value * VuoCompilerType::generateRetainedValueFromString(Module *module, BasicBlock *block, Value *stringValue)
303{
304 Function *makeFromJsonFunctionInModule = declareFunctionInModule(module, makeFromJsonFunction);
305
306 Function *jsonTokenerParseFunction = VuoCompilerCodeGenUtilities::getJsonTokenerParseFunction(module);
307 Value *jsonValue = CallInst::Create(jsonTokenerParseFunction, stringValue, "valueAsJson", block);
308
309 vector<Value *> makeFromJsonArgs;
310 int jsonParamIndex = makeFromJsonFunctionInModule->getFunctionType()->getNumParams() - 1;
311 Type *jsonParamType = static_cast<PointerType *>(makeFromJsonFunctionInModule->getFunctionType()->getParamType(jsonParamIndex));
312 Value *jsonArg = new BitCastInst(jsonValue, jsonParamType, "", block);
313 makeFromJsonArgs.push_back(jsonArg);
314
315 Value *dataPointer = nullptr;
317 {
318 Value *makeFromJsonReturn = VuoCompilerCodeGenUtilities::callFunctionWithStructReturn(makeFromJsonFunctionInModule, makeFromJsonArgs, block);
319 dataPointer = new BitCastInst(makeFromJsonReturn, llvmReturnType, "valueFromString", block);
320 }
321 else
322 {
323 Value *makeFromJsonReturn = CallInst::Create(makeFromJsonFunctionInModule, makeFromJsonArgs, "valueFromString", block);
324 dataPointer = VuoCompilerCodeGenUtilities::generatePointerToValue(block, makeFromJsonReturn);
325 }
326
327 generateRetainCall(module, block, dataPointer);
328
329 Function *jsonObjectPutFunction = VuoCompilerCodeGenUtilities::getJsonObjectPutFunction(module);
330 CallInst::Create(jsonObjectPutFunction, jsonValue, "", block);
331
332 return dataPointer;
333}
334
343Value * VuoCompilerType::generateStringFromValueFunctionCall(Module *module, BasicBlock *block, Value *arg)
344{
345 return generateFunctionCallWithTypeParameter(module, block, arg, getStringFunction);
346}
347
356Value * VuoCompilerType::generateInterprocessStringFromValueFunctionCall(Module *module, BasicBlock *block, Value *arg)
357{
358 if (getInterprocessStringFunction)
359 return generateFunctionCallWithTypeParameter(module, block, arg, getInterprocessStringFunction);
360 else
362}
363
372Value * VuoCompilerType::generateSummaryFromValueFunctionCall(Module *module, BasicBlock *block, Value *arg)
373{
374 return generateFunctionCallWithTypeParameter(module, block, arg, getSummaryFunction);
375}
376
380void VuoCompilerType::generateRetainCall(Module *module, BasicBlock *block, Value *arg)
381{
382 generateFunctionCallWithTypeParameter(module, block, arg, retainFunction);
383}
384
388void VuoCompilerType::generateReleaseCall(Module *module, BasicBlock *block, Value *arg)
389{
390 generateFunctionCallWithTypeParameter(module, block, arg, releaseFunction);
391}
392
398vector<Value *> VuoCompilerType::convertPortDataToArgs(Module *module, BasicBlock *block, Value *arg, FunctionType *functionType, int parameterIndex,
399 bool isUnloweredStructPointerParameter)
400{
401 vector<Value *> args;
402 if (!llvmSecondArgumentType)
403 {
404 Type *parameterType = functionType->getParamType(parameterIndex);
405
406 if (!isReturnPassedAsArgument)
407 {
408 bool isLoweredAsUsual = true;
409 if (parameterType->isPointerTy() && !llvmArgumentType->isPointerTy())
410 isLoweredAsUsual = false;
411
412 if (isLoweredAsUsual)
413 {
414 // The data type is either not lowered or lowered to 1 parameter.
415 arg = new BitCastInst(arg, PointerType::getUnqual(parameterType), "dataPointerCasted", block);
416 arg = new LoadInst(arg, "data", false, block);
417 }
418 else
419 {
420 // The data type is normally lowered to 1 parameter, but here is passed by reference ('byval').
421 arg = new BitCastInst(arg, parameterType, "dataCasted", block);
422 }
423 }
424 else
425 {
426 // The data type is a struct that is passed by reference (LLVM's `byval` attribute on x86_64).
427 arg = new BitCastInst(arg, parameterType, "dataCasted", block);
428 }
429
430 args.push_back(arg);
431 }
432 else
433 {
434 if (! isUnloweredStructPointerParameter)
435 {
436 // The data type is lowered to 2 parameters.
437 arg = new BitCastInst(arg, PointerType::getUnqual(llvmReturnType), "dataStructCasted", block);
438 for (int i = 0; i < 2; ++i)
439 {
441 if (currArg->getType()->isPointerTy())
442 {
443 Type *parameterType = functionType->getParamType(parameterIndex + i);
444 currArg = new BitCastInst(currArg, parameterType, "dataCasted", block);
445 }
446 args.push_back(currArg);
447 }
448 }
449 else
450 {
451 // The data type is normally lowered to 2 parameters, but here is a struct passed by reference (`byval`).
452 Type *parameterType = functionType->getParamType(parameterIndex);
453 arg = new BitCastInst(arg, parameterType, "dataCasted", block);
454 args.push_back(arg);
455 }
456 }
457
458 return args;
459}
460
465Value * VuoCompilerType::convertArgsToPortData(Module *module, BasicBlock *block, Function *function, int parameterIndex)
466{
467 vector<Value *> args;
468 args.push_back( VuoCompilerCodeGenUtilities::getArgumentAtIndex(function, parameterIndex) );
469 if (llvmSecondArgumentType)
470 args.push_back( VuoCompilerCodeGenUtilities::getArgumentAtIndex(function, parameterIndex+1) );
471
472 if (!llvmSecondArgumentType)
473 {
474 if (!isReturnPassedAsArgument)
475 {
476 Value *argPointer = VuoCompilerCodeGenUtilities::generatePointerToValue(block, args[0]);
477 return new BitCastInst(argPointer, PointerType::getUnqual(llvmReturnType), "dataPointerCasted", block);
478 }
479 else
480 return args[0];
481 }
482 else
483 {
484 size_t totalArgByteCount = 0;
485 for (auto arg : args)
486 totalArgByteCount += module->getDataLayout().getTypeStoreSize(arg->getType());
487
488 Value *dataPointer = new AllocaInst(llvmReturnType, 0, "dataPointer", block);
489 Value *dataPointerAsBytePointer = new BitCastInst(dataPointer, PointerType::getUnqual(IntegerType::get(module->getContext(), 8)), "dataBytePointer", block);
490
491 size_t argByteOffset = 0;
492 for (auto arg : args)
493 {
494 Value *argPointer = VuoCompilerCodeGenUtilities::generatePointerToValue(block, arg);
495 Value *offsetValue = ConstantInt::get(module->getContext(), APInt(64, argByteOffset));
496 Value *offsetDataPointer = GetElementPtrInst::Create(nullptr, dataPointerAsBytePointer, offsetValue, "", block);
497 size_t storeByteCount = module->getDataLayout().getTypeStoreSize(arg->getType());
498 size_t allocByteCount = module->getDataLayout().getTypeAllocSize(arg->getType());
499 VuoCompilerCodeGenUtilities::generateMemoryCopy(module, block, argPointer, offsetDataPointer, storeByteCount);
500 argByteOffset += allocByteCount;
501 }
502
503 return dataPointer;
504 }
505}
506
514Value * VuoCompilerType::generateFunctionCallWithTypeParameter(Module *module, BasicBlock *block, Value *arg, Function *sourceFunction)
515{
516 Function *function = declareFunctionInModule(module, sourceFunction);
517 vector<Value *> args = convertPortDataToArgs(module, block, arg, function->getFunctionType(), 0, false);
518 return CallInst::Create(function, args, "", block);
519}
520
525{
526 Type *type = llvmReturnType;
527 if (isReturnPassedAsArgument)
528 type = static_cast<PointerType *>(llvmReturnType)->getElementType();
529
530 return module->getDataLayout().getTypeAllocSize(type);
531}
532
537{
538 Type *type = llvmReturnType;
539 if (isReturnPassedAsArgument)
540 type = static_cast<PointerType *>(llvmReturnType)->getElementType();
541
542 return module->getDataLayout().getTypeStoreSize(type);
543}
544
548Value * VuoCompilerType::convertToPortData(BasicBlock *block, Value *voidPointer)
549{
550 Type *type = PointerType::getUnqual(llvmReturnType);
551 if (isReturnPassedAsArgument)
552 type = llvmReturnType;
553
554 return new BitCastInst(voidPointer, type, "", block);
555}
556
561{
562 vector<Type *> types;
563 types.push_back(llvmArgumentType);
564 if (llvmSecondArgumentType)
565 types.push_back(llvmSecondArgumentType);
566 return types;
567}
568
573{
574 return PointerType::getUnqual(llvmReturnType);
575}
576
583{
584 return getJsonFunction->getAttributes();
585}
586
591{
592 VuoCompilerCodeGenUtilities::copyParameterAttributes(getJsonFunction, dstFunction);
593}
594
598void VuoCompilerType::copyFunctionParameterAttributes(Module *module, CallInst *dstCall)
599{
601}
602
607{
608 if (! type)
609 return false;
610
612}
613
618{
619 return getInterprocessStringFunction != NULL;
620}
621
626{
627 return areEqualFunction != NULL && isLessThanFunction != NULL;
628}