Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mutable arguments that are not meant to be returned #124

Open
eponier opened this issue May 2, 2022 · 5 comments
Open

Mutable arguments that are not meant to be returned #124

eponier opened this issue May 2, 2022 · 5 comments
Labels

Comments

@eponier
Copy link
Contributor

eponier commented May 2, 2022

Apparently before PR #82, some people were relying on a pattern involving inline functions and reg ptr arguments used as a scratchpad. Here is a small example.

inline fn f (reg ptr u64[1] a, reg ptr u64[1] scratchpad) -> reg ptr u64[1] {
  reg u64 tmp;
  scratchpad[0] = 2;
  tmp = scratchpad[0];
  a[0] = tmp;
  return a;
}

export fn main () -> reg u64 {
  stack u64[1] a scratchpad;
  reg u64 res;
  a[0] = 1;
  scratchpad[0] = 1;
  a = f (a, scratchpad);
  res = a[0];
  return res;
}

Function f takes as an argument variable scratchpad that is used to write temporary data and is useless after the function call, that's why it's not returned. This example used to work because:

  • scratchpad is not returned so is marked as const
  • the function is inline, otherwise it would fail at line scratchpad[0] = 2; during stack alloc
  • we don't read scratchpad after the call

With PR #82, typing fails on scratchpad[0] = 2; since writing in a const array is now forbidden. Do we want this feature back? I don't think we want it back as is, because it was hacky. But one thing we could do is allowing reg mut ptr not to be returned, meaning such a variable would be unusable after the function call. Maybe this would allow to reduce the lifetime of the variable because we wouldn't have to insert an assignment after the function call. And it could be supported also for non-inline functions.

@eponier eponier changed the title "reg const ptr" in inline functions Mutable arguments that are not meant to be returned May 2, 2022
@eponier
Copy link
Contributor Author

eponier commented May 2, 2022

cc @AntoineSere who mentioned that problem to me. Did I describe the issue faithfully?

@AntoineSere
Copy link
Collaborator

Yes, the issue seems to me to be accurately described.

@vbgl
Copy link
Member

vbgl commented May 16, 2022

Are there any good reasons to use this kind of pattern? It seems that the inline function could declare its own local stack variable instead of receiving it from the caller.

@AntoineSere
Copy link
Collaborator

If the same scratchpad can be used by different inlined functions, then this construct makes sense, as it allow you to only allocate one scratchpad instead of many if you were to declare a local stack variable in each inlined function.

Here is a small modification of @eponier 's example illustrating this usecase:

inline fn f (reg ptr u64[1] a, reg ptr u64[1] scratchpad) -> reg ptr u64[1] {
  reg u64 tmp;
  scratchpad[0] = 1;
  tmp = scratchpad[0];
  a[0] = tmp;
  return a;
}

inline fn g (reg ptr u64[1] a, reg ptr u64[1] scratchpad) -> reg ptr u64[1] {
  reg u64 tmp;
  scratchpad[0] = 2;
  tmp = scratchpad[0];
  a[0] = tmp;
  return a;
}

export fn main () -> reg u64 {
  stack u64[1] a scratchpad;
  reg u64 res;
  a[0] = 1;
  scratchpad[0] = 1;
  a = f (a, scratchpad);
  a = g (a, scratchpad);
  res = a[0];
  return res;
}

In this example, only one scratchpad is needed.

@vbgl
Copy link
Member

vbgl commented May 16, 2022

The compiler does that for you.

/* --------------------------------------------------- */
inline fn f (reg ptr u64[1] a, reg ptr u64[1] scratchpad) -> reg ptr u64[1], reg ptr u64[1] {
  reg u64 tmp;
  scratchpad[0] = 1;
  tmp = scratchpad[0];
  a[0] = tmp;
  return a, scratchpad;
}

inline fn g (reg ptr u64[1] a, reg ptr u64[1] scratchpad) -> reg ptr u64[1], reg ptr u64[1] {
  reg u64 tmp;
  scratchpad[0] = 2;
  tmp = scratchpad[0];
  a[0] = tmp;
  return a, scratchpad;
}

#[stacksize=16]
export fn main () -> reg u64 {
  stack u64[1] a scratchpad;
  reg u64 res;
  a[0] = 1;
  // scratchpad[0] = 1;
  a, scratchpad = f (a, scratchpad);
  a, _ = g (a, scratchpad);
  res = a[0];
  return res;
}

/* --------------------------------------------------- */
inline fn h (reg ptr u64[1] a) -> reg ptr u64[1] {
  reg u64 tmp;
  stack u64[1] scratchpad;
  scratchpad[0] = 1;
  tmp = scratchpad[0];
  a[0] = tmp;
  return a;
}

inline fn i (reg ptr u64[1] a) -> reg ptr u64[1] {
  reg u64 tmp;
  stack u64[1] scratchpad;
  scratchpad[0] = 2;
  tmp = scratchpad[0];
  a[0] = tmp;
  return a;
}

#[stacksize=16]
export fn good () -> reg u64 {
  stack u64[1] a;
  reg u64 res;
  a[0] = 1;
  a = h (a);
  a = i (a);
  res = a[0];
  return res;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants