3 Here are two valid statements in Mu:
10 Understanding when to use one vs the other is the critical idea in Mu. In
11 short, the former increments a value in memory, while the latter increments a
14 Most languages start from some syntax and do what it takes to implement it.
15 Mu, however, is designed as a safe way to program in [a regular subset of
16 32-bit x86 machine code](subx.md), _satisficing_ rather than optimizing for a
17 clean syntax. To keep the mapping to machine code lightweight, Mu exclusively
18 uses statements. Most statements map to a single instruction of machine code.
20 Since the x86 instruction set restricts how many memory locations an instruction
21 can use, Mu makes registers explicit as well. Variables must be explicitly
22 mapped to specific registers; otherwise they live in memory. While you have to
23 do your own register allocation, Mu will helpfully point out when you get it
26 Statements consist of 3 parts: the operation, optional _inouts_ and optional
27 _outputs_. Outputs come before the operation name and `<-`.
29 Outputs are always registers; memory locations that need to be modified are
30 passed in by reference in inouts.
32 So Mu programmers need to make two new categories of decisions: whether to
33 define variables in registers or memory, and whether to put variables to the
34 left or right. There's always exactly one way to write any given operation. In
35 return for this overhead you get a lightweight and future-proof stack. And Mu
36 will provide good error messages to support you.
38 Further down, this page enumerates all available primitives in Mu, and [a
39 separate page](http://akkartik.github.io/mu/html/mu_instructions.html)
40 describes how each primitive is translated to machine code. There is also a
41 useful list of pre-defined functions (implemented in unsafe machine code) in [400.mu](http://akkartik.github.io/mu/html/400.mu.html)
42 and [vocabulary.md](vocabulary.md).
44 ## Functions and calls
46 Zooming out from single statements, here's a complete sample program in Mu
49 <img alt='ex2.mu' src='html/ex2.mu.png' width='400px'>
51 Mu programs are lists of functions. Each function has the following form:
54 fn _name_ _inout_ ... -> _output_ ... {
61 Each function has a header line, and some number of statements, each on a
62 separate line. Headers describe inouts and outputs. Inouts can't be registers,
63 and outputs _must_ be registers (specified using metadata after a `/`).
64 Outputs can't take names.
66 The above program also demonstrates a function call (to the function `do-add`).
67 Function calls look the same as primitive statements: they can return (multiple)
68 outputs in registers, and modify inouts passed in by reference. In addition,
69 there's one more constraint: output registers must match the function header.
78 a/ebx <- f # wrong; `a` must be in register `eax`
82 You can exit a function at any time with the `return` instruction. Give it the
83 right number of arguments, and it'll assign them respectively to the function's
84 outputs before jumping back to the caller.
86 Mu encloses multi-word types in parentheses, and types can get quite expressive.
87 For example, you read `main`'s inout type as "an address to an array of
88 addresses to arrays of bytes." Since addresses to arrays of bytes are almost
89 always strings in Mu, you'll quickly learn to mentally shorten this type to
90 "an address to an array of strings".
92 Mu currently has no way to name magic constants. Instead, document integer
93 literals using metadata after a `/`. For example:
96 var x/eax: int <- copy 3/margin-left
99 Here we use metadata in two ways: to specify a register for the variable `x`
100 (checked), and to give a name to the constant `3` (unchecked; purely for
103 Variables can't currently accept unchecked metadata for documentation.
104 (Perhaps this should change.)
106 The function `main` is special. It's where Mu programs start executing. It has
107 a different signature depending on whether a Mu program requires Linux or can
108 run without an OS. On Linux, the signature looks like this:
111 fn main args: (addr array addr array byte) -> _/ebx: int
114 It takes an array of strings and returns a status code to Linux in register
117 Without an OS, the signature looks like this:
120 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk)
123 A screen and keyboard are explicitly passed in. The goal is for all hardware
124 dependencies to always be explicit. However there are currently gaps:
125 * The mouse is accessed implicitly
126 * The screen argument only supports text-mode graphics. Pixel graphics rely
127 on implicit access to the screen.
128 * The Mu computer has two disks, and the disk containing Mu code is not
133 Blocks are useful for grouping related statements. They're delimited by `{`
134 and `}`, each alone on a line.
147 Blocks can be named (with the name ending in a `:` on the same line as the
156 Further down we'll see primitive statements for skipping or repeating blocks.
157 Besides control flow, the other use for blocks is...
161 Functions can define new variables at any time with the keyword `var`. There
162 are two variants of the `var` statement, for defining variables in registers
167 var name/reg: type <- ...
170 Variables on the stack are never initialized. (They're always implicitly
171 zeroed out.) Variables in registers are always initialized.
173 Register variables can go in 6 integer registers (`eax`, `ebx`, `ecx`, `edx`,
174 `esi`, `edi`) or 8 floating-point registers (`xmm0`, `xmm1`, `xmm2`, `xmm3`,
175 `xmm4`, `xmm5`, `xmm6`, `xmm7`).
177 Defining a variable in a register either clobbers the previous variable (if it
178 was defined in the same block) or shadows it temporarily (if it was defined in
181 Variables exist from their definition until the end of their containing block.
182 Register variables may also die earlier if their register is clobbered by a
185 Variables on the stack can be of many types (but not `byte`). Integer registers
186 can only contain 32-bit values: `int`, `byte`, `boolean`, `(addr ...)`. Floating-point
187 registers can only contain values of type `float`.
189 ## Integer primitives
191 Here is the list of arithmetic primitive operations supported by Mu. The name
192 `n` indicates a literal integer rather than a variable, and `var/reg` indicates
193 a variable in a register, though that's not always valid Mu syntax.
200 var1/reg1 <- add var2/reg2
202 add-to var1, var2/reg
206 var1/reg1 <- subtract var2/reg2
207 var/reg <- subtract var2
208 subtract-from var1, var2/reg
209 var/reg <- subtract n
212 var1/reg1 <- xor var2/reg2
214 xor-with var1, var2/reg
221 var/reg <- copy var2/reg2
222 copy-to var1, var2/reg
227 compare var1, var2/reg
228 compare var1/reg, var2
232 var/reg <- shift-left n
233 var/reg <- shift-right n
234 var/reg <- shift-right-signed n
237 shift-right-signed var, n
239 var/reg <- multiply var2
244 var1/reg1 <- and var2/reg2
246 and-with var1, var2/reg
250 var1/reg1 <- or var2/reg2
252 or-with var1, var2/reg
260 Any statement above that takes a variable in memory can be replaced with a
261 dereference (`*`) of an address variable (of type `(addr ...)`) in a register.
262 You can't dereference variables in memory. You have to load them into a
265 Excluding dereferences, the above statements must operate on non-address
266 values with primitive types: `int`, `boolean` or `byte`. (Booleans are really
267 just `int`s, and Mu assumes any value but `0` is true.) You can copy addresses
268 to int variables, but not the other way around.
270 ## Floating-point primitives
272 These instructions may use the floating-point registers `xmm0` ... `xmm7`
273 (denoted by `/xreg2` or `/xrm32`). They also use integer values on occasion
274 (`/rm32` and `/r32`).
277 var/xreg <- add var2/xreg2
279 var/xreg <- add *var2/reg2
281 var/xreg <- subtract var2/xreg2
282 var/xreg <- subtract var2
283 var/xreg <- subtract *var2/reg2
285 var/xreg <- multiply var2/xreg2
286 var/xreg <- multiply var2
287 var/xreg <- multiply *var2/reg2
289 var/xreg <- divide var2/xreg2
290 var/xreg <- divide var2
291 var/xreg <- divide *var2/reg2
293 var/xreg <- reciprocal var2/xreg2
294 var/xreg <- reciprocal var2
295 var/xreg <- reciprocal *var2/reg2
297 var/xreg <- square-root var2/xreg2
298 var/xreg <- square-root var2
299 var/xreg <- square-root *var2/reg2
301 var/xreg <- inverse-square-root var2/xreg2
302 var/xreg <- inverse-square-root var2
303 var/xreg <- inverse-square-root *var2/reg2
305 var/xreg <- min var2/xreg2
307 var/xreg <- min *var2/reg2
309 var/xreg <- max var2/xreg2
311 var/xreg <- max *var2/reg2
314 Remember, when these instructions use indirect mode, they still use an integer
315 register. Floating-point registers can't hold addresses.
317 Two instructions in the above list are approximate. According to the Intel
318 manual, `reciprocal` and `inverse-square-root` [go off the rails around the
319 fourth decimal place](x86_approx.md). If you need more precision, use `divide`
322 Most instructions operate exclusively on integer or floating-point operands.
323 The only exceptions are the instructions for converting between integers and
324 floating-point numbers.
327 var/xreg <- convert var2/reg2
328 var/xreg <- convert var2
329 var/xreg <- convert *var2/reg2
331 var/reg <- convert var2/xreg2
332 var/reg <- convert var2
333 var/reg <- convert *var2/reg2
335 var/reg <- truncate var2/xreg2
336 var/reg <- truncate var2
337 var/reg <- truncate *var2/reg2
340 There are no instructions accepting floating-point literals. To obtain integer
341 literals in floating-point registers, copy them to general-purpose registers
342 and then convert them to floating-point.
344 The floating-point instructions above always write to registers. The only
345 instructions that can write floats to memory are `copy` instructions.
348 var/xreg <- copy var2/xreg2
349 copy-to var1, var2/xreg
350 var/xreg <- copy var2
351 var/xreg <- copy *var2/reg2
354 Finally, there are floating-point comparisons. They must always put a register
355 on the left-hand side:
358 compare var1/xreg1, var2/xreg2
359 compare var1/xreg1, var2
362 ## Operating on individual bytes
364 A special case is variables of type `byte`. Mu is a 32-bit platform so for the
365 most part only supports types that are multiples of 32 bits. However, we do
366 want to support strings in ASCII and UTF-8, which will be arrays of 8-bit
369 Since most x86 instructions implicitly load 32 bits at a time from memory,
370 variables of type 'byte' are only allowed in registers, not on the stack. Here
371 are the possible statements for reading bytes to/from memory:
374 var/reg <- copy-byte var2/reg2 # var: byte
375 var/reg <- copy-byte *var2/reg2 # var: byte
376 copy-byte-to *var1/reg1, var2/reg2 # var1: (addr byte)
379 In addition, variables of type 'byte' are restricted to (the lowest bytes of)
380 just 4 registers: `eax`, `ecx`, `edx` and `ebx`. As always, this is due to
381 constraints of the x86 instruction set.
385 There are two kinds of jumps, both with many variations: `break` and `loop`.
386 `break` instructions jump to the end of the containing block. `loop` instructions
387 jump to the beginning of the containing block.
389 All jumps can take an optional label starting with '$':
395 This instruction jumps to the beginning of the block called $foo. The corresponding
396 `break` jumps to the end of the block. Either jump statement must lie somewhere
397 inside such a block. Jumps are only legal to containing blocks. (Use named
398 blocks with restraint; jumps to places far away can get confusing.)
400 There are two unconditional jumps:
409 The remaining jump instructions are all conditional. Conditional jumps rely on
410 the result of the most recently executed `compare` instruction. (To keep
411 programs easy to read, keep `compare` instructions close to the jump that uses
421 Inequalities are similar, but have additional variants for addresses and floats.
438 break-if-addr<= label
440 break-if-addr>= label
443 break-if-float< label
445 break-if-float> label
447 break-if-float<= label
449 break-if-float>= label
452 Similarly, conditional loops:
483 loop-if-float<= label
485 loop-if-float>= label
490 Passing objects by reference requires the `address` operation, which returns
491 an object of type `addr`.
494 var/reg: (addr T) <- address var2: T
497 Here `var2` can't live in a register.
501 Here's an example definition of a fixed-length array:
507 The length (here `3`) must be an integer literal. We'll show how to create
508 dynamically-sized arrays further down.
510 Arrays can be large; to avoid copying them around on every function call
511 you'll usually want to manage `addr`s to them. Here's an example computing the
515 var n/eax: (addr array int) <- address x
518 Addresses to arrays don't include the array length in their type. However, you
519 can obtain the length of an array like this:
522 var/reg: int <- length arr/reg: (addr array T)
525 To operate on elements of an array, use the `index` statement:
528 var/reg: (addr T) <- index arr/reg: (addr array T), n
529 var/reg: (addr T) <- index arr: (array T len), n
532 The index can also be a variable in a register, with a caveat:
535 var/reg: (addr T) <- index arr/reg: (addr array T), idx/reg: int
536 var/reg: (addr T) <- index arr: (array T len), idx/reg: int
539 The caveat: the size of T must be 1, 2, 4 or 8 bytes. The x86 instruction set
540 has complex addressing modes that can index into an array in a single instruction
543 For other sizes of T you'll need to split up the work, performing a `compute-offset`
547 var/reg: (offset T) <- compute-offset arr: (addr array T), idx/reg: int # arr can be in reg or mem
548 var/reg: (offset T) <- compute-offset arr: (addr array T), idx: int # arr can be in reg or mem
551 The `compute-offset` statement returns a value of type `(offset T)` after
552 performing any necessary bounds checking. Now the offset can be passed to
556 var/reg: (addr T) <- index arr/reg: (addr array T), idx/reg: (offset T)
561 A common use for arrays is as buffers. Save a few items to a scratch space and
562 then process them. This pattern is so common (we use it in files) that there's
563 special support for it with a built-in type: `stream`.
565 Streams are like arrays in many ways. You can initialize them with a length:
568 var x: (stream int 3)
571 However, streams don't provide random access with an `index` instruction.
572 Instead, you write to them sequentially, and read back what you wrote.
575 read-from-stream s: (addr stream T), out: (addr T)
576 write-to-stream s: (addr stream T), in: (addr T)
577 var/eax: boolean <- stream-empty? s: (addr stream)
578 var/eax: boolean <- stream-full? s: (addr stream)
581 You can clear streams:
584 clear-stream f: (addr stream _)
587 You can also rewind them to reread what's been written:
590 rewind-stream f: (addr stream _)
595 Primitive types can be combined together using the `type` keyword. For
605 Mu programs are currently sequences of `fn` and `type` definitions.
607 Compound types can't include `addr` types for safety reasons (use `handle` instead,
608 which is described below). They also can't currently include `array`, `stream`
609 or `byte` types. Since arrays and streams carry their size with them, supporting
610 them in compound types complicates variable initialization. Instead of
611 defining them inline in a type definition, define a `handle` to them. Bytes
612 shouldn't be used for anything but utf-8 strings.
614 To access within a compound type, use the `get` instruction. There are two
615 forms. You need either a variable of the type itself (say `T`) in memory, or a
616 variable of type `(addr T)` in a register.
619 var/reg: (addr T_f) <- get var/reg: (addr T), f
620 var/reg: (addr T_f) <- get var: T, f
623 The `f` here is the field name from the `type` definition, and its type `T_f`
624 must match the type of `f` in the `type` definition. For example, some legal
625 instructions for the definition of `point` above:
628 var a/eax: (addr int) <- get p, x
629 var a/eax: (addr int) <- get p, y
632 You can clear arbitrary types using the `clear-object` function:
635 clear-object var: (addr T)
638 Don't clear arrays or streams using `clear-object`; doing so will irreversibly
639 make their length 0 as well.
641 You can shallow-copy arbitrary types using the `copy-object` function:
644 copy-object src: (addr T), dest: (addr T)
647 ## Handles for safe access to the heap
649 We've seen the `addr` type, but it's intended to be short-lived. `addr` values
650 should never escape from functions. Function outputs can't be `addr`s,
651 function inouts can't include `addr` in their payload type. Finally, you can't
652 save `addr` values inside compound `type`s. To do that you need a "fat
653 pointer" called a `handle` that is safe to keep around for extended periods
654 and ensures it's used safely without corrupting the heap and causing security
655 issues or hard-to-debug misbehavior.
657 To actually _use_ a `handle`, we have to turn it into an `addr` first using
658 the `lookup` statement.
661 var y/reg: (addr T) <- lookup x: (handle T)
664 Now operate on `y` as usual, safe in the knowledge that you can later recover
665 any writes to its payload from `x`.
667 It's illegal to continue to use an `addr` after a function that reclaims heap
668 memory. You have to repeat the lookup from the `handle`. (Luckily Mu doesn't
669 implement reclamation yet.)
671 Having two kinds of addresses takes some getting used to. Do we pass in
672 variables by value, by `addr` or by `handle`? In inputs or outputs? Here are 3
675 * Functions that need to look at the payload should accept an `(addr ...)`
677 * Functions that need to treat a handle as a value, without looking at its
678 payload, should accept a `(handle ...)`. Helpers that save handles into
679 data structures are a common example.
680 * Functions that need to allocate memory should accept an `(addr handle ...)`.
682 Try to avoid mixing these use cases.
684 If you have a variable `src` of type `(handle ...)`, you can save it inside a
685 compound type like this (provided the types match):
688 var dest/reg: (addr handle T_f) <- get var: (addr T), f
689 copy-handle src, dest
695 var dest/reg: (addr handle T) <- index arr: (addr array handle T), n
696 copy-handle src, dest
699 To create handles to non-array types, use `allocate`:
702 var x: (addr handle T)
707 To create handles to array types (of potentially dynamic size), use `populate`:
710 var x: (addr handle array T)
712 populate x, 3 # array of 3 T's
717 I said at the start that most instructions map 1:1 to x86 machine code. To
718 enforce type- and memory-safety, I was forced to carve out a few exceptions:
720 * the `index` instruction on arrays, for bounds-checking
721 * the `length` instruction on arrays, for translating the array size in bytes
722 into the number of elements.
723 * the `lookup` instruction on handles, for validating fat-pointer metadata
724 * `var` instructions, to initialize memory
725 * byte copies, to initialize memory
727 If you're curious, [the compiler summary page](http://akkartik.github.io/mu/html/mu_instructions.html)
728 has the complete nitty-gritty on how each instruction is implemented. Including
729 the above exceptions.
733 Anything not allowed here is forbidden, even if the compiler doesn't currently
734 detect and complain about it. Please [contact me](mailto:ak@akkartik.com) or
735 [report issues](https://github.com/akkartik/mu/issues) when you encounter a
736 missing or misleading error message.