about summary refs log tree commit diff stats
path: root/apps/mu.subx
Commit message (Collapse)AuthorAgeFilesLines
* 6118 - support records on the stackKartik Agaram2020-03-101-12/+96
|
* 6117 - fix offset computationKartik Agaram2020-03-101-13/+15
| | | | | | It makes no sense to know where the next variable will start before I've seen it or how much space it needs. Things have only been working so far because all variables take 4 bytes.
* 6116 - stack locations now computed during codegenKartik Agaram2020-03-101-66/+91
| | | | | | | | | | | | | We can't do it during parsing time because we may not have all type definitions available yet. Mu supports using types before defining them. At first I thought I should do it in populate-mu-type-sizes (appropriately renamed). But there's enough complexity to tracking when stuff lands on the stack that it's easiest to do while emitting code. I don't think we need this information earlier in the compiler. If I'm right, it seems simpler to colocate the computation of state close to where it's used.
* 6115Kartik Agaram2020-03-101-27/+0
|
* 6114Kartik Agaram2020-03-101-2/+2
|
* 6113Kartik Agaram2020-03-101-58/+41
|
* 6112Kartik Agaram2020-03-081-21/+112
| | | | | Move computation of offsets to record fields into the new phase as well. Now we should be robust to type definitions in any order.
* 6111Kartik Agaram2020-03-081-5/+185
| | | | | | | | | | Move out total-size computation from parsing to a separate phase. I don't have any new tests yet, but it's encouraging that existing tests continue to pass. This may be the first time I've ever written this much machine code (with mutual recursion!) and gotten it to work the first time.
* 6110Kartik Agaram2020-03-081-2/+3
|
* 6109Kartik Agaram2020-03-081-2/+0
|
* 6108Kartik Agaram2020-03-081-13/+6
|
* 6107Kartik Agaram2020-03-081-2/+15
| | | | | Finally we're now able to track the index of a field in a record/struct/product type.
* 6106Kartik Agaram2020-03-081-9/+6
| | | | Free up eax using the newly available register.
* 6105Kartik Agaram2020-03-081-6/+9
| | | | Create space for another local.
* 6104Kartik Agaram2020-03-081-7/+12
| | | | | parse-mu-types has a lot of local state. Move a local to the stack to free up a register.
* 6103Kartik Agaram2020-03-081-3/+1
|
* 6102Kartik Agaram2020-03-081-26/+0
|
* 6101Kartik Agaram2020-03-081-45/+92
| | | | | | | | | Make room for additional information for each field in a record/product type. Fields can be used before they're declared, and we may not know the offsets they correspond to at that point. This is going to necessitate a lot of restructuring.
* 6100Kartik Agaram2020-03-081-2/+9
| | | | Fix a bug with a live register being clobbered.
* 6099Kartik Agaram2020-03-081-38/+5
|
* 6096Kartik Agaram2020-03-071-3/+58
| | | | A new test, and a new bugfix.
* 6094 - new 'compute-offset' instructionKartik Agaram2020-03-071-21/+165
| | | | | | | | | | | | | | | | | | | | | | | If indexing into a type with power-of-2-sized elements we can access them in one instruction: x/reg1: (addr int) <- index A/reg2: (addr array int), idx/reg3: int This translates to a single instruction because x86 instructions support an addressing mode with left-shifts. For non-powers-of-2, however, we need a multiply. To keep things type-safe, it is performed like this: x/reg1: (offset T) <- compute-offset A: (addr array T), idx: int y/reg2: (addr T) <- index A, x An offset is just an int that is guaranteed to be a multiple of size-of(T). Offsets can only be used in index instructions, and the types will eventually be required to line up. In the process, I have to expand Input-size because mu.subx is growing big.
* 6093Kartik Agaram2020-03-071-111/+168
| | | | Some much-needed reorganization.
* 6092Kartik Agaram2020-03-061-10/+10
|
* 6088 - start using setCC instructionsKartik Agaram2020-03-061-20/+8
|
* 6086 - `index` into arrays with a literalKartik Agaram2020-03-061-30/+114
|
* 6082 - bugfix in spilling register varsKartik Agaram2020-03-061-3/+263
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | In the process I'm starting to realize that my approach to avoiding spills isn't ideal. It works for local variables but not to avoid spilling outputs. To correctly decide whether to spill to an output register or not, we really need to analyze when a variable is live. If we don't do that, we'll end up in one of two bad situations: a) Don't spill the outermost use of an output register (or just the outermost scope in a function). This is weird because it's hard to explain to the programmer why they can overwrite a local with an output above a '{' but not below. b) Disallow overwriting entirely. This is easier to communicate but quite inconvenient. It's nice to be able to use eax for some temporary purpose before overwriting it with the final result of a function. If we instead track liveness, things are convenient and also easier to explain. If a temporary is used after the output has been written that's an obvious problem: "you clobbered the output". (It seems more reasonable to disallow multiple live ranges for the output. Once an output is written it can only be shadowed in a nested block.) That's the bad news. Now for some good news: One lovely property Mu the language has at the moment is that live ranges are guaranteed to be linear segments of code. We don't need to analyze loop-carried dependences. This means that we can decide whether a variable is live purely by scanning later statements for its use. (Defining 'register use' is slightly non-trivial; primitives must somehow specify when they read their output register.) So we don't actually need to worry about a loop reading a register with one type and writing to another type at the end of an iteration. The only way that can happen is if the write at the end was to a local variable, and we're guaranteeing that local variables will be reclaimed at the end of the iteration. So, the sequence of tasks: a) compute register liveness b1) verify that all register variables used at any point in a program are always the topmost use of that register. b2) decide whether to spill/shadow, clobber or flag an error. There's still the open question of where to attach liveness state. It can't be on a var, because liveness varies by use of the var. It can't be on a statement because we may want to know the liveness of variables not referenced in a given statement. Conceptually we want a matrix of locals x stmts (flattened). But I think it's simpler than that. We just want to know liveness at the time of variable declarations. A new register variable can be in one of three states w.r.t. its previous definition: either it's shadowing it, or it can clobber it, or there's a conflict and we need to raise an error. I think we can compute this information for each variable definition by an analysis similar to existing ones, maintaining a stack of variable definitions. The major difference is that we don't pop variables when a block ends. Details to be worked out. But when we do I hope to get these pending tests passing.
* 6079 - optimize register spillsKartik Agaram2020-03-051-23/+211
| | | | | The second var to the same register in a block doesn't need to spill. We're never going to restore the var it's shadowing.
* 6074Kartik Agaram2020-02-291-21/+25
|
* 6073Kartik Agaram2020-02-291-11/+28
|
* 6071 - array indexing for non-int power-of-2 typesKartik Agaram2020-02-291-11/+163
|
* 6070Kartik Agaram2020-02-291-1/+1
|
* 6069Kartik Agaram2020-02-291-24/+24
|
* 6062Kartik Agaram2020-02-271-10/+92
|
* 6061Kartik Agaram2020-02-271-22/+22
|
* 6055 - record types and the 'get' instructionKartik Agaram2020-02-271-6/+487
| | | | | | | | | | | This is a lot of code for a single test, and it took a long time to get my data model just right. But the test coverage seems ok because it feels mostly like straight-line code. We'll see. I've also had to add a lot of prints. We really need app-level trace generation pretty urgently. That requires deciding how to turn it on/off from the commandline. And I've been reluctant to start relying on the hairy interface that is POSIX open().
* 6054Kartik Agaram2020-02-241-3/+21
|
* 6053Kartik Agaram2020-02-231-2/+2
|
* 6052Kartik Agaram2020-02-231-10/+21
|
* 6051Kartik Agaram2020-02-231-13/+25
|
* 6050Kartik Agaram2020-02-231-26/+34
|
* 6049Kartik Agaram2020-02-231-11/+11
|
* 6048Kartik Agaram2020-02-211-28/+9
|
* 6047Kartik Agaram2020-02-211-2/+2
|
* 6045Kartik Agaram2020-02-211-16/+16
|
* 6044Kartik Agaram2020-02-211-68/+68
|
* 6043Kartik Agaram2020-02-211-0/+52
| | | | Test for 'index'.
* 6041 - array indexing starting to workKartik Agaram2020-02-211-5/+99
| | | | | | | | | | | | | And we're using it now in factorial.mu! In the process I had to fix a couple of bugs in pointer dereferencing. There are still some limitations: a) Indexing by a literal doesn't work yet. b) Only arrays of ints supported so far. Looking ahead, I'm not sure how I can support indexing arrays by non-literals (variables in registers) unless the element size is a power of 2.
* 6037 - first passing test for pointer lookupKartik Agaram2020-02-201-67/+192
|
* 6036Kartik Agaram2020-02-201-5/+6
|