diff options
| author | Tim Foley <tfoleyNV@users.noreply.github.com> | 2021-02-04 11:15:46 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-02-04 11:15:46 -0800 |
| commit | ef283b80b886c7a0fb34c20e07a43ccca3237ed8 (patch) | |
| tree | 1132d7b360ec1f4389383db559b5d075817aed2c /examples | |
| parent | 4c66c17b2e5572c95da260ea4761f5804eb52853 (diff) | |
Change how function-scope static variables lower to IR (#1686)
This change pertains to `static` variables in function scope (including things like methods, initializers, property accessors, etc.). Note that it does *not* have anything to do with global-scope `static` variables or with `static const` variables (whether inside a function or not).
The old code generation strategy had a lot of "clever" code to deal with the problem of a `static` variable inside a generic function (or inside a function inside a generic type, etc.). Basically, if you had input code like:
int myFunc<T>(int newVal) {
static int state = 0;
int result = state;
state = newVal;
return result;
}
The language semantics are that `myFunc<float3>` should have a different `state` variable than `myFunc<int2>`. The way that the existing codegen handled that was to generate the `state` variable into its own dedicated `IRGeneric`. Something like:
generic myFunc_state<T0> { global_var g_ptr : int*; return g_ptr; }
generic myFunc<T1> {
func f(int newVal) {
let result : int = load(state<T>);
store(state<T1>, newVal);
return result;
}
}
The catch there is that you end up needing to generate an entire second `IRGeneric`, and then references to `state` need to explicitly use `specialize` to instantiate that generic using the same parameters as `myFunc` was passed (note how `T0` and `T1` are distinct IR generic parameters, despite both representing `T` here).
Things get even more complicated when you consider function-`static` variables with initialization logic, since we need to be sure we only perform that initialization once, but the initialization could refer to arguments of the outer function, and thus needs to be done inside the function body. To handle that case we emit an additional `bool` global if a function-`static` variable has an initializer, and that `bool` gets wrapped up in yet another generic.
That whole approach seems silly in retrospect, and a much simpler solution is possible: just emit the function-`static` variable immediately before the IR function it pertains to, which means it will be nested under the *same* IR generic if there is one (and at module scope if there isn't). The result is something like:
generic myFunc<T1> {
global_var state_ptr : int*;
func f(int newVal) {
let result : int = load(state_ptr);
store(state_ptr, newVal);
return result;
}
}
This change implements that simplification, and all the same tests pass (including whatever tests we had for function-`static` variables).
Diffstat (limited to 'examples')
0 files changed, 0 insertions, 0 deletions
