Q:

How does compiler inline a function with branches and multiple return statements? 

If an inline function ends with a single return at the end, it is trivial to simply replace the caller code with the function body, conceptually. 
inline int foo(int i) {
    return i - 1;
}

// prior to inline
int result = foo(k);
// => after inline
int result = k - 1;

What if there are branches and multiple returns?  How does a compiler generate correct code?  A simple replacement is clearly not enough. 
inline int foo(int i) {
    if (i > 0)
        return i - 1;

    return i + 1;
}

// prior to inline
int result = foo(k);
// => after inline
int result;
if (k > 0)
    result = k - 1;

result = k + 1;

A:

The compiler is allowed to make all kinds of transformations of the code during compilation.  For your example, the compiler can transform the function foo to 
int foo(int i)
{
  int rv;
  if (i > 0)
  {
    rv = i - 1;
    goto end;
  }

  rv = i + 1;
end:
  return rv;
}

This code can then be inserted in the caller.  During insertion the compiler introduces variables to handle the parameters and return value of the inlined function.  The result looks something like the code below. 
int foo_rv;
int foo_param_i = k;
{
  int i = foo_param_i;
  if (i > 0)
  {
    rv = i - 1;
    goto end:
  }

  rv = i + 1;
end:
  foo_rv = rv
}

int result = foo_rv;

This code can then be optimized further by the compiler, resulting in the code below
{
  if (k > 0)
  {
    result = k - 1;
    goto end:
  }

  result = k + 1;
end:
}

