How to use EE->runFunction for a function with StructRet set?

Hi,

I'm using LLVM 2.4 (but llvm-gcc 2.2) on Ubuntu 8.10 (Intrepid Ibex) for
a small part-time project combining Witty (http://www.webtoolkit.eu) and
the ExecutionEngine in LLVM. (This is my second week with any of these
so I still lack a lot of basic knowledge.)

Sometimes I want to call a function returing a struct (in this case
std::string), thus hasStructRetAttr() is true for the Function and
getNumParams() for the FunctionType is one more than the actual number
of parameters including "this".

I've made an implementation that seems to work fine, but I would
apreciate if the people on this list could take a look to see if there's
anything amiss in my code.

Below is my test source code with compilation instructions.

Best regards,

David Eriksson

== StructRetExample.cc ==

= Source =

#include <string>

std::string get_hello()
{
  return "hello";
}

= Compile to LLVM bitcode =

llvm-g++ --emit-llvm -O3 -c -o StructRetExample.bc StructRetExample.cc

== TestStructRet.cc ==

= Source =

#include <iostream>
#include <string>

#include <llvm/Bitcode/ReaderWriter.h>
#include <llvm/DerivedTypes.h>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/ExecutionEngine/GenericValue.h>
#include <llvm/Module.h>
#include <llvm/ModuleProvider.h>
#include <llvm/Support/MemoryBuffer.h>
#include <llvm/Target/TargetData.h>
#include <llvm/Type.h>

using namespace std;
using namespace llvm;

int main(int argc, char** argv)
{
  string ErrorMessage;
  auto_ptr<MemoryBuffer>
Buffer(MemoryBuffer::getFileOrSTDIN("StructRetExample.bc",
&ErrorMessage));
  Module *M = ParseBitcodeFile(Buffer.get(), &ErrorMessage);

  ExecutionEngine *EE = ExecutionEngine::create(new
ExistingModuleProvider(M), false, &ErrorMessage);

  // Function returning std::string
  Function *F = M->getFunction("_Z9get_hellov");

  // XXX Is all of this the right way?

  const Type* paramType = F->getFunctionType()->getParamType(0); //
pointer to struct
  const Type* structRetType = dynamic_cast<const
PointerType*>(paramType)->getTypeAtIndex((unsigned)0);
  const std::string structRetName(M->getTypeName(structRetType));

  if (structRetName != "struct.std::string")
    return 1;

  // Get object size
  uint64_t size = EE->getTargetData()->getABITypeSize(structRetType);
  // Make room on stack
  void* p = alloca(size);

  // Create parameter list
  std::vector<GenericValue> parameters;
  GenericValue structRetParameter;
  structRetParameter = PTOGV(p);
  parameters.push_back(structRetParameter);

  EE->runFunction(F, parameters);

  // Copy and print result
  std::string result = *(std::string*)p;
  std::cout << "Result: " << result << std::endl;

  // TODO: call std::string destructor

  return 0;
}

= Compile =

g++ -o TestStructRet TestStructRet.cc `llvm-config --cxxflags --ldflags
--libs jit interpreter nativecodegen bitreader `

== End ==

I'd strongly recommend using EE->getPointerToFunction() and casting it to the right function pointer type. "runFunction" is really only useful if you're using the LLVM IR interpreter, and it is pretty broken right now.

-Chris