lurscher
lurscher

Reputation: 26983

llvm: generating cleanup destructors before function return

in LLVM, usually you will exit a generated function with CreateRet, however, i want to add cleanup destructors for local objects instantiated in the function.

My question is: i assume i have to insert the cleanup function calls before inserting the CreateRet, however, i'm wondering if the return value is one of the locals (suppose we are returning by value) then we cannot destruct this value before the return, but the local will not be destructed after the return either, so i would say i'm a bit confused about the lifetime of the locals and where to properly insert the cleanup

Upvotes: 4

Views: 1282

Answers (2)

Johannes Schaub - litb
Johannes Schaub - litb

Reputation: 507205

You can codegen your source-language return statement / expressions as copies into the return storage followed by a branch to a designated return basic block, which will destroy locals. If your generated LLVM function returns the value itself, instead of following its own protocol (by returning the value through the first parameter, or some such), you can save the return value to an alloca first, and then load that alloca and return that with ret. Example for when you return through the first parameter, with %valuetype denoting the struct storing values in your language runtime

define void @myfn(%valuetype *%ret) {
  ; use and create whatever locals you need

  ; source-language: return somelocal
  store %valuetype %local1, %valuetype *%ret
  br label %retlabel

retlabel:
  ; emit code to destruct locals ..., then return
  ret void
}

Upvotes: 2

Xeo
Xeo

Reputation: 131839

Look at some C++ disassembly! :)
Generally, you save the return value on the stack, call the destructors of all local objects and then move the return value from the stack into the eax register (cdecl calling convention). The eax saving is necessary because the destructors are allowed to change that register.
Take this very hypothetical pseudo assembly for example:

// inside imaginary function
mov [ebp-0Ch],eax; // save eax register
lea ecx, [ebp-4]; // [ebp-4] == your object address
call Foo::~Foo(); // call the destructor
mov eax,[ebp-0Ch]; // retrieve the saved return value
ret; // now return

If the returned value is a local object, then you of course first need to copy the object into the prepared space.

// pseudo function call
int i = func();

Here, the space for the return value of func will be provided on the stack, and that's where you copy your return value. After that, proceed as shown above.

Upvotes: 2

Related Questions