This commit is contained in:
Kartik Agaram 2020-11-15 23:51:40 -08:00
parent 264aba4d92
commit 8d2dece291
6 changed files with 17 additions and 25 deletions

View File

@ -13,7 +13,7 @@ fn main -> _/ebx: int {
}
fn do-add a: int, b: int -> _/eax: int {
var result/ebx: int <- copy a
var result/ecx: int <- copy a
result <- add b
return result
}

2
html/apps/ex2.mu.html generated
View File

@ -71,7 +71,7 @@ if ('onhashchange' in window) {
<span id="L13" class="LineNr">13 </span><span class="Delimiter">}</span>
<span id="L14" class="LineNr">14 </span>
<span id="L15" class="LineNr">15 </span><span class="PreProc">fn</span> <span class="muFunction"><a href='ex2.mu.html#L15'>do-add</a></span> a: int, b: int<span class="PreProc"> -&gt; </span>_/<span class="Constant">eax</span>: int <span class="Delimiter">{</span>
<span id="L16" class="LineNr">16 </span> <span class="PreProc">var</span> result/<span class="Constant">ebx</span>: int <span class="SpecialChar">&lt;-</span> copy a
<span id="L16" class="LineNr">16 </span> <span class="PreProc">var</span> result/<span class="Constant">ecx</span>: int <span class="SpecialChar">&lt;-</span> copy a
<span id="L17" class="LineNr">17 </span> result <span class="SpecialChar">&lt;-</span> add b
<span id="L18" class="LineNr">18 </span> <span class="PreProc">return</span> result
<span id="L19" class="LineNr">19 </span><span class="Delimiter">}</span>

BIN
html/ex2.mu.png generated

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 98 KiB

View File

@ -59,9 +59,9 @@ if ('onhashchange' in window) {
<span id="L3" class="LineNr"> 3 </span><span class="subxComment"># See translate_mu for how this file is used.</span>
<span id="L4" class="LineNr"> 4 </span><span class="subxComment">#</span>
<span id="L5" class="LineNr"> 5 </span><span class="subxComment"># Mu programs start at a function called 'main' with this signature:</span>
<span id="L6" class="LineNr"> 6 </span><span class="subxComment"># fn main args: (addr array addr array byte) -&gt; exit-status/ebx: int</span>
<span id="L6" class="LineNr"> 6 </span><span class="subxComment"># fn main args: (addr array addr array byte) -&gt; _/ebx: int</span>
<span id="L7" class="LineNr"> 7 </span><span class="subxComment"># If your program doesn't need commandline arguments you can drop it:</span>
<span id="L8" class="LineNr"> 8 </span><span class="subxComment"># fn main -&gt; exit-status/ebx: int</span>
<span id="L8" class="LineNr"> 8 </span><span class="subxComment"># fn main -&gt; _/ebx: int</span>
<span id="L9" class="LineNr"> 9 </span><span class="subxComment">#</span>
<span id="L10" class="LineNr">10 </span><span class="subxComment"># Notice that the output must be in ebx, so that the exit() syscall can pick</span>
<span id="L11" class="LineNr">11 </span><span class="subxComment"># it up.</span>

View File

@ -3,9 +3,9 @@
# See translate_mu for how this file is used.
#
# Mu programs start at a function called 'main' with this signature:
# fn main args: (addr array addr array byte) -> exit-status/ebx: int
# fn main args: (addr array addr array byte) -> _/ebx: int
# If your program doesn't need commandline arguments you can drop it:
# fn main -> exit-status/ebx: int
# fn main -> _/ebx: int
#
# Notice that the output must be in ebx, so that the exit() syscall can pick
# it up.

30
mu.md
View File

@ -12,25 +12,17 @@ short, the former increments a value in memory, while the latter increments a
value in a register.
Most languages start from some syntax and do what it takes to implement it.
Mu, however, is designed as a safe[1] way to program in [a regular subset of
Mu, however, is designed as a safe way to program in [a regular subset of
32-bit x86 machine code](subx.md), _satisficing_ rather than optimizing for a
clean syntax. To keep the mapping to machine code lightweight, Mu exclusively
uses statements. Most statements map to a single instruction of machine code.
[1] While it's designed to be memory-safe, and already performs many safety
checks, the Mu compiler is still a work in progress and can currently corrupt
memory just like C can. I estimate that it'll currently point out 90% of the
mistakes you make.
Since the x86 instruction set restricts how many memory locations an instruction
can use, Mu makes registers explicit as well. Variables must be explicitly
mapped to specific registers; otherwise they live in memory. While you have to
do your own register allocation, Mu will helpfully point out[2] when you get it
do your own register allocation, Mu will helpfully point out when you get it
wrong.
[2] Again, there are some known issues here at the moment. I estimate that
it'll currently catch 95% of register allocation errors.
Statements consist of 3 parts: the operation, optional _inouts_ and optional
_outputs_. Outputs come before the operation name and `<-`.
@ -67,9 +59,9 @@ fn _name_ _inout_ ... -> _output_ ... {
Each function has a header line, and some number of statements, each on a
separate line. Headers describe inouts and outputs. Inouts can't be registers,
and outputs _must_ be registers. In the above example, the outputs of both
`do-add` and `main` have type `int` and are available in register `ebx` at the
end of the respective calls.
and outputs _must_ be registers. Outputs can't take names. In the above
example, the outputs of both `do-add` and `main` have type `int` and are
available in register `ebx` at the end of the respective calls.
The above program also demonstrates a function call (to the function `do-add`).
Function calls look the same as primitive statements: they can return (multiple)
@ -78,7 +70,7 @@ there's one more constraint: output registers must match the function header.
For example:
```
fn f -> x/eax: int {
fn f -> _/eax: int {
...
}
fn g {
@ -97,8 +89,8 @@ process). It can also optionally accept an array of strings as input (from the
shell command-line). To be precise, `main` must have one of the following
two signatures:
- `fn main -> x/ebx: int`
- `fn main args: (addr array (addr array byte)) -> x/ebx: int`
- `fn main -> _/ebx: int`
- `fn main args: (addr array (addr array byte)) -> _/ebx: int`
(The names of the inout and output are flexible.)
@ -150,9 +142,9 @@ var name/reg: type <- ...
Variables on the stack are never initialized. (They're always implicitly
zeroed out.) Variables in registers are always initialized.
Register variables can go in 6 integer registers: `eax`, `ebx`, `ecx`, `edx`,
`esi` and `edi`. Floating-point values can go in 8 other registers: `xmm0`,
`xmm1`, `xmm2`, `xmm3`, `xmm4`, `xmm5`, `xmm6` and `xmm7`.
Register variables can go in 6 integer registers (`eax`, `ebx`, `ecx`, `edx`,
`esi`, `edi`) or 8 floating-point registers (`xmm0`, `xmm1`, `xmm2`, `xmm3`,
`xmm4`, `xmm5`, `xmm6`, `xmm7`).
Defining a variable in a register either clobbers the previous variable (if it
was defined in the same block) or shadows it temporarily (if it was defined in