Skip to content

representation for initializing expressions and putting function return values in registers #3133

Open
@zygoloid

Description

@zygoloid

We currently unconditionally permit returned vars in functions, and the implication seems to be that the assert in this testcase holds for any type T:

fn F[T:! type](v: T, p: T**) -> T {
  returned var ret: T = v;
  *p = &ret;
  return var;
}

fn G[T:! type](x: T) {
  var p: T*;
  var v: T = F(x, &p);
  Assert(&v == p);
}

But that's problematic: it means that a function like F that uses a returned var (or, transitively, initializes its return object from a function that uses a returned var) cannot return in registers, which means that our calling convention, at least for functions whose bodies we can't see, can't return in registers, even for types like i32 or ().

I think:

  1. A type author should be able to choose whether their type is guaranteed to be returned in-place or not (and in the latter case might be returned in registers).
  2. A function author should be able to choose whether they guarantee to return in-place or not.

As a starting point, how about this:

  • Any type T whose value representation is const T* defaults to being returned in-place; any type whose value representation is const T defaults to being returned by copy.
    • Possibly this default can be overridden in some way, separately from customizing the value representation, or possibly not.
    • For the in-place case, we could choose to both pass in a return slot and return a pointer to where the result actually is, putting the burden of performing an optional copy on the caller, or we could choose to require that the function actually initializes into the provided address.
    • For a custom value representation, we could provide some mechanism to let the class author choose, or we could always use in-place initialization, or we could pass in a return slot and return a value representation and a bool indicating whether the return slot got initialized.
  • A function that uses a -> T return uses the default for the type; a function that uses a -> var T return guarantees to return in-place.
    • returned var notation is only permitted in a function that is guaranteed to return in-place, either because the function uses -> var or (optionally) because the type requires an in-place return.

Metadata

Metadata

Assignees

No one assigned

    Labels

    leads questionA question for the leads teamlong term issueIssues expected to take over 90 days to resolve. Does not apply to PRs.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions