Vuo  2.3.2
VuoCompilerType.cc
Go to the documentation of this file.
1 
10 #include <sstream>
13 #include "VuoCompilerException.hh"
14 #include "VuoCompilerIssue.hh"
15 #include "VuoCompilerType.hh"
16 #include "VuoType.hh"
17 
21 VuoCompilerType::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  makeFromStringFunction = 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 
50 VuoCompilerType * VuoCompilerType::newType(string typeName, Module *module)
51 {
52  if (! isType(typeName, module))
53  return NULL;
54 
55  return new VuoCompilerType(typeName, module);
56 }
57 
62 bool VuoCompilerType::isType(string typeName, Module *module)
63 {
64  return (module->getNamedValue(typeName + "_makeFromJson") != NULL);
65 }
66 
70 void VuoCompilerType::parse(void)
71 {
73 
74  string typeName = getBase()->getModuleKey();
75  makeFromJsonFunction = parser->getFunction(typeName + "_makeFromJson");
76  getJsonFunction = parser->getFunction(typeName + "_getJson");
77  getInterprocessJsonFunction = parser->getFunction(typeName + "_getInterprocessJson");
78  getSummaryFunction = parser->getFunction(typeName + "_getSummary");
79  areEqualFunction = parser->getFunction(typeName + "_areEqual");
80  isLessThanFunction = parser->getFunction(typeName + "_isLessThan");
81 
82  if (! makeFromJsonFunction)
83  VUserLog("Error: Couldn't find %s_makeFromJson() function.", typeName.c_str());
84  if (! getJsonFunction)
85  VUserLog("Error: Couldn't find %s_getJson() function.", typeName.c_str());
86  if (! getSummaryFunction)
87  VUserLog("Error: Couldn't find %s_getSummary() function.", typeName.c_str());
88 
89  llvmArgumentType = getJsonFunction->getFunctionType()->getParamType(0);
90  if (getJsonFunction->getFunctionType()->getNumParams() == 2)
91  llvmSecondArgumentType = getJsonFunction->getFunctionType()->getParamType(1);
92  else if (getJsonFunction->getFunctionType()->getNumParams() != 1)
93  {
94  string s;
95  raw_string_ostream oss(s);
96  oss << "Expected a function with 1 or 2 parameters, got " << getJsonFunction->getFunctionType()->getNumParams() << " for function `";
97  getJsonFunction->getFunctionType()->print(oss);
98  oss << "`.";
99  VuoCompilerIssue issue(VuoCompilerIssue::Error, "compiling composition", "", "Unsupported port data type", oss.str());
100  throw VuoCompilerException(issue);
101  }
102 
103  llvmReturnType = makeFromJsonFunction->getReturnType();
104  if (llvmReturnType->isVoidTy())
105  {
106  isReturnPassedAsArgument = true;
107  llvmReturnType = makeFromJsonFunction->arg_begin()->getType();
108  }
109 
110  parseOrGenerateValueFromStringFunction();
111  parseOrGenerateStringFromValueFunction(false);
112  if (getInterprocessJsonFunction)
113  parseOrGenerateStringFromValueFunction(true);
114 
115  parseOrGenerateRetainOrReleaseFunction(true);
116  parseOrGenerateRetainOrReleaseFunction(false);
117 }
118 
122 set<string> VuoCompilerType::globalsToRename(void)
123 {
124  set<string> globals = VuoCompilerModule::globalsToRename();
125  return globals;
126 }
127 
145 void VuoCompilerType::parseOrGenerateValueFromStringFunction(void)
146 {
147  string functionName = (getBase()->getModuleKey() + "_makeFromString").c_str();
148  Function *function = parser->getFunction(functionName);
149 
150  bool isReturnInParam = VuoCompilerCodeGenUtilities::isFunctionReturningStructViaParameter(makeFromJsonFunction);
151 
152  if (! function)
153  {
154  PointerType *pointerToCharType = PointerType::get(IntegerType::get(module->getContext(), 8), 0);
155  FunctionType *makeFromJsonFunctionType = makeFromJsonFunction->getFunctionType();
156 
157  Type *returnType = makeFromJsonFunctionType->getReturnType();
158 
159  vector<Type *> functionParams;
160  if (isReturnInParam)
161  functionParams.push_back(makeFromJsonFunctionType->getParamType(0));
162  functionParams.push_back(pointerToCharType);
163 
164  FunctionType *functionType = FunctionType::get(returnType, functionParams, false);
165  function = Function::Create(functionType, GlobalValue::ExternalLinkage, functionName, module);
166 
167  if (isReturnInParam)
168  VuoCompilerCodeGenUtilities::copyParameterAttributes(makeFromJsonFunction, function);
169  }
170 
171  if (function->isDeclaration())
172  {
173  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function);
174 
175  Function::arg_iterator args = function->arg_begin();
176  Value *result = NULL;
177  if (isReturnInParam)
178  {
179  result = args++;
180  result->setName("result");
181  }
182  Value *str = args++;
183  str->setName("str");
184 
185  Function *jsonTokenerParseFunction = VuoCompilerCodeGenUtilities::getJsonTokenerParseFunction(module);
186  Function *jsonObjectPutFunction = VuoCompilerCodeGenUtilities::getJsonObjectPutFunction(module);
187 
188  CallInst *jsonTokenerParseReturn = CallInst::Create(jsonTokenerParseFunction, str, "", block);
189 
190  vector<Value *> makeFromJsonArgs;
191  if (isReturnInParam)
192  makeFromJsonArgs.push_back(result);
193  makeFromJsonArgs.push_back(jsonTokenerParseReturn);
194  Value *makeFromJsonReturn = CallInst::Create(makeFromJsonFunction, makeFromJsonArgs, "", block);
195 
196  CallInst::Create(jsonObjectPutFunction, jsonTokenerParseReturn, "", block);
197 
198  Value *returnValue = (isReturnInParam ? NULL : makeFromJsonReturn);
199  ReturnInst::Create(module->getContext(), returnValue, block);
200  }
201 
202  makeFromStringFunction = function;
203 }
204 
223 void VuoCompilerType::parseOrGenerateStringFromValueFunction(bool isInterprocess)
224 {
225  string functionName = (getBase()->getModuleKey() + (isInterprocess ? "_getInterprocessString" : "_getString")).c_str();
226  Function *function = parser->getFunction(functionName);
227 
228  Function *chosenJsonFromValueFunction = (isInterprocess ? getInterprocessJsonFunction : getJsonFunction);
229 
230  if (! function)
231  {
232  PointerType *pointerToCharType = PointerType::get(IntegerType::get(module->getContext(), 8), 0);
233  FunctionType *getJsonFunctionType = chosenJsonFromValueFunction->getFunctionType();
234 
235  Type *returnType = pointerToCharType;
236 
237  vector<Type *> functionParams;
238  for (int i = 0; i < getJsonFunctionType->getNumParams(); ++i)
239  functionParams.push_back(getJsonFunctionType->getParamType(i));
240 
241  FunctionType *functionType = FunctionType::get(returnType, functionParams, false);
242  function = Function::Create(functionType, GlobalValue::ExternalLinkage, functionName, module);
243 
245  }
246 
247  if (function->isDeclaration())
248  {
249  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function);
250 
251  int argIndex = 0;
252  for (Function::arg_iterator args = function->arg_begin(); args != function->arg_end(); ++args, ++argIndex)
253  {
254  Value *value = args;
255  ostringstream argName;
256  argName << "value" << argIndex;
257  value->setName(argName.str().c_str());
258  }
259 
260  Function *jsonObjectToJsonStringExtFunction = VuoCompilerCodeGenUtilities::getJsonObjectToJsonStringExtFunction(module);
261  Function *strdupFunction = VuoCompilerCodeGenUtilities::getStrdupFunction(module);
262  Function *jsonObjectPutFunction = VuoCompilerCodeGenUtilities::getJsonObjectPutFunction(module);
263 
264  vector<Value *> getJsonArgs;
265  for (Function::arg_iterator args = function->arg_begin(); args != function->arg_end(); ++args)
266  {
267  Value *value = args;
268  getJsonArgs.push_back(value);
269  }
270  CallInst *getJsonReturn = CallInst::Create(chosenJsonFromValueFunction, getJsonArgs, "", block);
271 
272  vector<Value *> jsonObjectToJsonStringExtArgs;
273  jsonObjectToJsonStringExtArgs.push_back(getJsonReturn);
274  jsonObjectToJsonStringExtArgs.push_back(ConstantInt::get(module->getContext(), APInt(32, JSON_C_TO_STRING_PLAIN)));
275  CallInst *jsonObjectToJsonStringExtReturn = CallInst::Create(jsonObjectToJsonStringExtFunction, jsonObjectToJsonStringExtArgs, "", block);
276 
277  CallInst *strdupReturn = CallInst::Create(strdupFunction, jsonObjectToJsonStringExtReturn, "", block);
278 
279  CallInst::Create(jsonObjectPutFunction, getJsonReturn, "", block);
280 
281  ReturnInst::Create(module->getContext(), strdupReturn, block);
282  }
283 
284  if (isInterprocess)
285  getInterprocessStringFunction = function;
286  else
287  getStringFunction = function;
288 }
289 
306 void VuoCompilerType::parseOrGenerateRetainOrReleaseFunction(bool isRetain)
307 {
308  string functionName = (getBase()->getModuleKey() + (isRetain ? "_retain" : "_release")).c_str();
309  Function *function = parser->getFunction(functionName);
310 
311  if (! function)
312  {
313  vector<Type *> functionParams;
314  functionParams.push_back(llvmArgumentType);
315  if (llvmSecondArgumentType)
316  functionParams.push_back(llvmSecondArgumentType);
317 
318  FunctionType *functionType = FunctionType::get(Type::getVoidTy(module->getContext()), functionParams, false);
319  function = Function::Create(functionType, GlobalValue::ExternalLinkage, functionName, module);
320 
322  }
323 
324  if (function->isDeclaration())
325  {
326  BasicBlock *block = BasicBlock::Create(module->getContext(), "", function);
327 
328  Function::arg_iterator args = function->arg_begin();
329  Value *arg = args++;
330 
331  if (!llvmSecondArgumentType)
332  {
333  if (isReturnPassedAsArgument && VuoCompilerCodeGenUtilities::isPointerToStruct(arg->getType()))
334  {
335  // The data type is a struct that is passed by reference (LLVM's `byval` attribute on x86_64).
336  arg = new LoadInst(arg, "unloweredStruct", false, block);
337  }
338 
340  }
341  else
342  {
343  if (llvmArgumentType->isPointerTy())
344  {
345  // The data type is a struct with pointer field(s), lowered to 2 arguments, the 1st of which is a pointer.
347  }
348 
349  if (llvmSecondArgumentType->isPointerTy())
350  {
351  // The data type is a struct with pointer field(s), lowered to 2 arguments, the 2nd of which is a pointer.
352  Value *secondArg = args++;
354  }
355  }
356 
357  ReturnInst::Create(module->getContext(), block);
358  }
359 
360  if (isRetain)
361  retainFunction = function;
362  else
363  releaseFunction = function;
364 }
365 
374 Value * VuoCompilerType::generateValueFromStringFunctionCall(Module *module, BasicBlock *block, Value *arg)
375 {
376  Function *function = declareFunctionInModule(module, makeFromStringFunction);
377 
378  if (isReturnPassedAsArgument)
379  {
380  vector<Value *> functionArgs;
381  functionArgs.push_back(arg);
382  Value *returnVariable = VuoCompilerCodeGenUtilities::callFunctionWithStructReturn(function, functionArgs, block);
383  return new BitCastInst(returnVariable, llvmReturnType, "valueFromString", block);
384  }
385  else
386  {
387  Value *returnValue = CallInst::Create(function, arg, "valueFromString", block);
388  return VuoCompilerCodeGenUtilities::generatePointerToValue(block, returnValue);
389  }
390 }
391 
400 Value * VuoCompilerType::generateStringFromValueFunctionCall(Module *module, BasicBlock *block, Value *arg)
401 {
402  return generateFunctionCallWithTypeParameter(module, block, arg, getStringFunction);
403 }
404 
413 Value * VuoCompilerType::generateInterprocessStringFromValueFunctionCall(Module *module, BasicBlock *block, Value *arg)
414 {
415  if (getInterprocessStringFunction)
416  return generateFunctionCallWithTypeParameter(module, block, arg, getInterprocessStringFunction);
417  else
418  return generateStringFromValueFunctionCall(module, block, arg);
419 }
420 
429 Value * VuoCompilerType::generateSummaryFromValueFunctionCall(Module *module, BasicBlock *block, Value *arg)
430 {
431  return generateFunctionCallWithTypeParameter(module, block, arg, getSummaryFunction);
432 }
433 
437 void VuoCompilerType::generateRetainCall(Module *module, BasicBlock *block, Value *arg)
438 {
440  generateFunctionCallWithTypeParameter(module, block, arg, retainFunction);
441 }
442 
446 void VuoCompilerType::generateReleaseCall(Module *module, BasicBlock *block, Value *arg)
447 {
449  generateFunctionCallWithTypeParameter(module, block, arg, releaseFunction);
450 }
451 
457 vector<Value *> VuoCompilerType::convertPortDataToArgs(Module *module, BasicBlock *block, Value *arg, FunctionType *functionType, int parameterIndex,
458  bool isUnloweredStructPointerParameter)
459 {
460  vector<Value *> args;
461  if (!llvmSecondArgumentType)
462  {
463  Type *parameterType = functionType->getParamType(parameterIndex);
464 
465  if (!isReturnPassedAsArgument)
466  {
467  bool isLoweredAsUsual = true;
468  if (parameterType->isPointerTy() && !llvmArgumentType->isPointerTy())
469  isLoweredAsUsual = false;
470 
471  if (isLoweredAsUsual)
472  {
473  // The data type is either not lowered or lowered to 1 parameter.
474  arg = new BitCastInst(arg, PointerType::getUnqual(parameterType), "dataPointerCasted", block);
475  arg = new LoadInst(arg, "data", false, block);
476  }
477  else
478  {
479  // The data type is normally lowered to 1 parameter, but here is passed by reference ('byval').
480  arg = new BitCastInst(arg, parameterType, "dataCasted", block);
481  }
482  }
483  else
484  {
485  // The data type is a struct that is passed by reference (LLVM's `byval` attribute on x86_64).
486  arg = new BitCastInst(arg, parameterType, "dataCasted", block);
487  }
488 
489  args.push_back(arg);
490  }
491  else
492  {
493  if (! isUnloweredStructPointerParameter)
494  {
495  // The data type is lowered to 2 parameters.
496  arg = new BitCastInst(arg, PointerType::getUnqual(llvmReturnType), "dataStructCasted", block);
497  for (int i = 0; i < 2; ++i)
498  {
500  if (currArg->getType()->isPointerTy())
501  {
502  Type *parameterType = functionType->getParamType(parameterIndex + i);
503  currArg = new BitCastInst(currArg, parameterType, "dataCasted", block);
504  }
505  args.push_back(currArg);
506  }
507  }
508  else
509  {
510  // The data type is normally lowered to 2 parameters, but here is a struct passed by reference (`byval`).
511  Type *parameterType = functionType->getParamType(parameterIndex);
512  arg = new BitCastInst(arg, parameterType, "dataCasted", block);
513  args.push_back(arg);
514  }
515  }
516 
517  return args;
518 }
519 
524 Value * VuoCompilerType::convertArgsToPortData(Module *module, BasicBlock *block, Function *function, int parameterIndex)
525 {
526  vector<Value *> args;
527  args.push_back( VuoCompilerCodeGenUtilities::getArgumentAtIndex(function, parameterIndex) );
528  if (llvmSecondArgumentType)
529  args.push_back( VuoCompilerCodeGenUtilities::getArgumentAtIndex(function, parameterIndex+1) );
530 
531  if (!llvmSecondArgumentType)
532  {
533  if (!isReturnPassedAsArgument)
534  {
535  Value *argPointer = VuoCompilerCodeGenUtilities::generatePointerToValue(block, args[0]);
536  return new BitCastInst(argPointer, PointerType::getUnqual(llvmReturnType), "dataPointerCasted", block);
537  }
538  else
539  return args[0];
540  }
541  else
542  {
543  size_t totalArgByteCount = 0;
544  for (auto arg : args)
545  totalArgByteCount += module->getDataLayout().getTypeStoreSize(arg->getType());
546 
547  size_t dataByteCount = getSize(module);
548 
549  Value *dataPointer = new AllocaInst(llvmReturnType, 0, "dataPointer", block);
550  Value *dataPointerAsBytePointer = new BitCastInst(dataPointer, PointerType::getUnqual(IntegerType::get(module->getContext(), 8)), "dataBytePointer", block);
551 
552  size_t argByteOffset = 0;
553  for (auto arg : args)
554  {
555  Value *argPointer = VuoCompilerCodeGenUtilities::generatePointerToValue(block, arg);
556  Value *offsetValue = ConstantInt::get(module->getContext(), APInt(64, argByteOffset));
557  Value *offsetDataPointer = GetElementPtrInst::Create(nullptr, dataPointerAsBytePointer, offsetValue, "", block);
558  size_t argByteCount = module->getDataLayout().getTypeStoreSize(arg->getType());
559  size_t copyByteCount = max(argByteCount, argByteCount - (dataByteCount - (argByteOffset + argByteCount)));
560  VuoCompilerCodeGenUtilities::generateMemoryCopy(module, block, argPointer, offsetDataPointer, copyByteCount);
561  argByteOffset += argByteCount;
562  }
563 
564  return dataPointer;
565  }
566 }
567 
575 Value * VuoCompilerType::generateFunctionCallWithTypeParameter(Module *module, BasicBlock *block, Value *arg, Function *sourceFunction)
576 {
577  Function *function = declareFunctionInModule(module, sourceFunction);
578  vector<Value *> args = convertPortDataToArgs(module, block, arg, function->getFunctionType(), 0, false);
579  return CallInst::Create(function, args, "", block);
580 }
581 
585 size_t VuoCompilerType::getSize(Module *module)
586 {
587  Type *type = llvmReturnType;
588  if (isReturnPassedAsArgument)
589  type = static_cast<PointerType *>(llvmReturnType)->getElementType();
590 
591  size_t size = module->getDataLayout().getTypeStoreSize(type);
592  return size;
593 }
594 
598 Value * VuoCompilerType::convertToPortData(BasicBlock *block, Value *voidPointer)
599 {
600  Type *type = PointerType::getUnqual(llvmReturnType);
601  if (isReturnPassedAsArgument)
602  type = llvmReturnType;
603 
604  return new BitCastInst(voidPointer, type, "", block);
605 }
606 
612 {
613  return llvmReturnType->isPointerTy() || llvmReturnType->isStructTy();
614 }
615 
620 {
621  vector<Type *> types;
622  types.push_back(llvmArgumentType);
623  if (llvmSecondArgumentType)
624  types.push_back(llvmSecondArgumentType);
625  return types;
626 }
627 
632 {
633  return PointerType::getUnqual(llvmReturnType);
634 }
635 
642 {
643  return getJsonFunction->getAttributes();
644 }
645 
650 {
651  VuoCompilerCodeGenUtilities::copyParameterAttributes(getJsonFunction, dstFunction);
652 }
653 
657 void VuoCompilerType::copyFunctionParameterAttributes(Module *module, CallInst *dstCall)
658 {
660 }
661 
666 {
667  if (! type)
668  return false;
669 
670  return VuoType::isListTypeName(type->getBase()->getModuleKey());
671 }
672 
677 {
678  return getInterprocessStringFunction != NULL;
679 }
680 
685 {
686  return areEqualFunction != NULL && isLessThanFunction != NULL;
687 }