## ~sircmpwn/hare unlisted

137684c900b614378e8f032518a3b9b9ff9810d4 — Drew DeVault a month ago
```docs: add storage.txt
```
```1 files changed, 205 insertions(+), 0 deletions(-)

A docs/storage.txt
```
`A docs/storage.txt => docs/storage.txt +205 -0`
```@@ 0,0 1,205 @@
+			      Allocation & storage
+
+A variable stored in a temporary:
+	/* In function scope: */
+	let x: int = 1234;
+		-> %x =w copy 1234
+
+	In this situation, x is of type int, and %x is of type =w, and the value
+	of %x stores the value of x.
+
+A variable stored on the stack:
+	/* In function scope: */
+	let x: int = 1234;
+		-> %x =l alloc4 4
+		-> storew 1234, %x
+	&x; /* Force stack allocation */
+
+	In this situation, x is of type int, and %x is of type =l, and the valu
+	of %x is a pointer to a =w where the value of x is stored.
+
+A variable stored on the heap:
+	/* In function scope: */
+	let x: &int = alloc(&int, 1234);
+		-> %x =l call calloc(l 4, l 1)
+		-> storew 1234, %x
+
+	x is of type int, and %x is of type =l, and the value of %x is a pointer
+	to a =w where the value of x is stored.
+
+A statically allocated variable:
+	/* In function scope: */
+	static let x: int = 1234;
+		-> /* In global scope (lowered to symbol): */
+		-> data \$.x.static.1 = { w 1234 }
+
+	x is of type int, and \$.x.static.1 is a generated name of type symbol,
+	and is a pointer to a =w where the value of x is stored.
+
+A global stored in the address space:
+	/* In global scope: */
+	let x: int = 1234;
+		-> data \$x = { w 1234 }
+
+	In this situation, x is of type int, and \$x is of type symbol, and is a
+	pointer to a =w where the value of x is stored.
+
+Aggregate types are always stored indirectly:
+	/* In function scope: */
+	let x: int = [4, 3, 2, 1];
+		-> %x =l alloc4 16 /* 4 × 4 = 16 */
+		-> %.offset.1 =l mul 0, 4
+		-> %.index.1 =l add %x, %.offset.1
+		-> storew 4, %index.1
+		-> /* ... */
+
+	The type of x is int, but because it's an aggregate type, the gen
+	step will infer that %x is a pointer and it's always accessed
+	indirectly.
+
+	let x = struct { x: int = 4, y: int = 2 };
+		-> %x =l alloc4 8
+		-> %.field.1 =l add %x, 0
+		-> storew 4, %.field.1
+		-> %.field.2 =l add %x, 0
+		-> storew 4, %.field.2
+
+	/* In global scope: */
+	let x: int = [1, 2, 3, 4];
+		-> data \$x = { w 4, w 3, w 2, w 1 }
+
+Nested aggregate types are embedded in their parents:
+	/* In function scope: */
+	let x: int = [[4, 3], [2, 1]];
+		-> %x =l alloc4 16 /* 4 × 4 = 16 */
+		-> %.offset.1 =l mul 0, 4
+		-> %.index.1 =l add %x, %.offset.1
+		-> storew 4, %index.1
+		-> /* ... */
+
+	let x = struct { a: struct { x: int = 4 }, b: struct { y: int = 2 } };
+		-> %x =l alloc4 8
+		-> %.field.1 =l add %x, 0
+		-> storew 4, %.field.1
+		-> %.field.2 =l add %x, 0
+		-> storew 4, %.field.2
+
+	/* In global scope: */
+	let x: int = [1, 2, 3, 4];
+		-> data \$x = { w 4, w 3, w 2, w 1 }
+
+	Note that this is exactly the same as the previous example.
+
+A string literal is lowered to a symbol:
+	/* In function scope: */
+	let x: str = "Hello, world!";
+		-> data \$x = { l 13, b "Hello, world!", b 0 }
+		-> %x =l copy \$str
+
+	x is of type str, and is immutable. The string contents are UTF-8.
+
+	let x: *str = "Hello, world!";
+		-> data \$x = { l 13, b "Hello, world!", b 0 }
+		-> %x =l copy \$str
+
+	x is of type *str, the pointer is mutable, and the string is not. Note
+	that the generated code is identical.
+
+	Note that aggregate types may be implicitly cast to a borrowed pointer
+	of that type. The same is true of the following:
+
+	let x: *int = [1, 2, 3, 4];
+
+	Back to strings, an owned pointer has to be made via the stdlib:
+
+	let x: &str = strings::dup("Hello, world!");
+		-> data \$.string.0 = { l 13, b "Hello, world!", b 0 }
+		-> %x =l call strings.dup(l \$.string.0)
+
+	x is of type &str. The pointer is mutable, but owned, and must be
+	transferred before mutating. The string itself is immutable.
+
+	/* Misc. string usage examples */
+	let x: &str = strings::dup("Hello, ");
+	x = strings::append(^x, "!\n");
+
+	/* or: */
+	let x: &str = strings::dup("Hello");
+	x = fmt::sprintf("%s, %s!\n", ^x, username);
+
+	/* or (obvious answer): */
+	let x: &str = fmt::sprintf("Hello, %s!", username);
+
+				     Access
+
+There are several kinds of accesses:
+
+- Identifier access (accessing locals & globals by name)
+- Array member access
+- Slice subset access
+- Struct field access
+
+			       Identifier access
+
+In order to access an identifier, we need to decide on an access strategy:
+direct access (via the temporary) or indirect access (dereferencing a pointer).
+
+When accessing a local:
+	Is it static?		-> Indirect access via symbol
+	Is it stack-allocated?	-> Indirect access via temporary
+	Is it an aggregate?	-> Direct access to the temporary *
+
+When accessing a global:
+	Is it an aggregate?	-> Direct access to the temporary *
+	Otherwise?		-> Indirect access via symbol
+
+* Note: aggregate types are only accessed directly (rather than accessing their
+  constituent values) as the parameters to functions or builtins.
+
+When accessing a parameter:
+	Is it an aggregate?	-> TODO: qbe aggregate types
+
+			      Array member access
+			      Slice member access
+			      Struct field access
+
+1. Because <aggregate> and *<aggregate> are both stored indirectly, one level of
+   pointer indirection may be removed from the type without additional
+   computation.
+2. Reduce all aggregate member accesses to determine the address of the member.
+3. Generate an indirect access via this computed address.
+
+			      Slice subset access
+
+The caller allocates storage for the resulting slice. Compute the appropriate
+values for the start address and length, and store these values in this slice.
+The result type of this operation is a const slice of the source array or source
+slice member type.
+
+	let x = [1, 2, 3, 4];
+	let y: const []int = x[..2];
+	assert(y == 1 && y == 2);
+
+			    Assignment (= operator)
+
+TODO
+
+
+TODO
+
+			   Dereferencing (* operator)
+
+TODO
+
+			     Implicit dereferencing
+
+Array member and struct field accesses are automatically dereferenced, e.g.
+
+	let coords: *struct { x: int, y: int } = /* ... */;
+	coords.x; /* coords is dereferenced */
+
+TODO: More details

```