about summary refs log tree commit diff stats
path: root/021check_instruction.cc
Commit message (Expand)AuthorAgeFilesLines
* 5001 - drop the :(scenario) DSLKartik Agaram2019-03-121-42/+70
* 4987 - support `browse_trace` tool in SubXKartik Agaram2019-02-251-1/+1
* 4266 - space for alloc-id in heap allocationsKartik Agaram2018-06-241-33/+17
* 4265Kartik Agaram2018-06-171-5/+5
* 4263Kartik Agaram2018-06-171-7/+1
* 4262 - literal 'null'Kartik Agaram2018-06-171-2/+6
* 4261 - start using literals for 'true' and 'false'Kartik Agaram2018-06-171-18/+1
* 4260 - make address coercions explicitKartik Agaram2018-06-161-9/+0
* 4258 - undo 4257Kartik Agaram2018-06-151-18/+7
* 4257 - abortive attempt at safe fat pointersKartik Agaram2018-06-151-7/+18
* 4243Kartik Agaram2018-05-121-8/+7
* 4120Kartik K. Agaram2017-11-101-0/+8
* 3963Kartik K. Agaram2017-07-081-7/+18
* 3877Kartik K. Agaram2017-05-261-1/+1
* 3836Kartik K. Agaram2017-04-191-0/+2
* 3833Kartik K. Agaram2017-04-181-1/+16
* 3812Kartik K. Agaram2017-04-041-3/+3
* 3811Kartik K. Agaram2017-04-041-2/+2
* 3752 - fix a couple of segfaultsKartik K. Agaram2017-03-021-0/+1
* 3707Kartik K. Agaram2016-12-121-2/+1
* 3663 - fix a refcounting bug: '(type)' != 'type'Kartik K. Agaram2016-11-101-4/+3
* 3653Kartik K. Agaram2016-11-081-2/+8
* 3522Kartik K. Agaram2016-10-191-2/+2
* 3381Kartik K. Agaram2016-09-171-3/+3
* 3380Kartik K. Agaram2016-09-171-13/+13
* 3378Kartik K. Agaram2016-09-171-3/+2
* 3309Kartik K. Agaram2016-09-091-29/+47
* 3210 - new primitive: character-to-codeKartik K. Agaram2016-08-171-0/+7
* 3120Kartik K. Agaram2016-07-211-1/+1
* 3097Kartik K. Agaram2016-07-031-2/+2
* 2991Kartik K. Agaram2016-05-201-4/+4
* 2931 - be explicit about making copiesKartik K. Agaram2016-05-061-7/+12
* 2929 - fix a bug in static dispatchKartik K. Agaram2016-05-051-9/+0
* 2836 - arcane bug in generic functionsKartik K. Agaram2016-04-151-0/+13
* 2803Kartik K. Agaram2016-03-211-2/+1
* 2773 - switch to 'int'Kartik K. Agaram2016-03-131-2/+2
* 2735 - define recipes using 'def'Kartik K. Agaram2016-03-081-7/+7
* 2712Kartik K. Agaram2016-02-261-2/+2
* 2711 - permit boolean<-number conversionsKartik K. Agaram2016-02-251-0/+9
* 2709Kartik K. Agaram2016-02-251-2/+0
* 2681 - drop reagent types from reagent propertiesKartik K. Agaram2016-02-211-3/+3
* 2678Kartik K. Agaram2016-02-201-3/+3
* 2685Kartik K. Agaram2016-02-191-1/+1
* 2646 - redo static dispatch algorithmKartik K. Agaram2016-02-111-0/+9
* 2620Kartik K. Agaram2016-01-301-27/+27
* 2619 - actually allow coercing booleans to numbersKartik K. Agaram2016-01-301-3/+19
* 2578Kartik K. Agaram2016-01-201-4/+0
* 2549Kartik K. Agaram2015-12-281-1/+3
* 2607 - resolve some edge cases in static dispatchKartik K. Agaram2015-11-291-9/+16
* 2494Kartik K. Agaram2015-11-281-1/+1
'n93' href='#n93'>93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226

                                                       











                                                                               

















































































































































                                                                                                  
 
                    
 

                                                               
 
                                        
 
                                          


                                                                                
                                                 
                                                                                                
                                            
                                                                
                                     
                                                                            

                                                                                                    
                                                          
                                                                                                    
                                                                            
                                                         
                                                         
 
                    



                                                                             



                                                                             
 
                                     




























                                                               
## Mu's instructions and their table-driven translation

See http://akkartik.name/akkartik-convivial-20200315.pdf for the complete
story. In brief: Mu is a statement-oriented language. Blocks consist of flat
lists of instructions. Instructions can have inputs after the operation, and
outputs to the left of a '<-'. Inputs and outputs must be variables. They can't
include nested expressions. Variables can be literals ('n'), or live in a
register ('var/reg') or in memory ('var') at some 'stack-offset' from the 'ebp'
register. Outputs must be registers. To modify a variable in memory, pass it in
by reference as an input. (Inputs are more precisely called 'inouts'.)
Conversely, registers that are just read from must not be passed as inputs.

The following chart shows all the instruction forms supported by Mu, along with
the SubX instruction they're translated to.

var/eax <- increment              => "40/increment-eax"
var/ecx <- increment              => "41/increment-ecx"
var/edx <- increment              => "42/increment-edx"
var/ebx <- increment              => "43/increment-ebx"
var/esi <- increment              => "46/increment-esi"
var/edi <- increment              => "47/increment-edi"
increment var                     => "ff 0/subop/increment *(ebp+" var.stack-offset ")"
increment *var/reg                => "ff 0/subop/increment *" reg

var/eax <- decrement              => "48/decrement-eax"
var/ecx <- decrement              => "49/decrement-ecx"
var/edx <- decrement              => "4a/decrement-edx"
var/ebx <- decrement              => "4b/decrement-ebx"
var/esi <- decrement              => "4e/decrement-esi"
var/edi <- decrement              => "4f/decrement-edi"
decrement var                     => "ff 1/subop/decrement *(ebp+" var.stack-offset ")"
decrement *var/reg                => "ff 1/subop/decrement *" reg

var/reg <- add var2/reg2          => "01/add-to %" reg " " reg2 "/r32"
var/reg <- add var2               => "03/add *(ebp+" var2.stack-offset ") " reg "/r32"
var/reg <- add *var2/reg2         => "03/add *" reg2 " " reg "/r32"
add-to var1, var2/reg             => "01/add-to *(ebp+" var1.stack-offset ") " reg "/r32"
var/eax <- add n                  => "05/add-to-eax " n "/imm32"
var/reg <- add n                  => "81 0/subop/add %" reg " " n "/imm32"
add-to var, n                     => "81 0/subop/add *(ebp+" var.stack-offset ") " n "/imm32"
add-to *var/reg, n                => "81 0/subop/add *" reg " " n "/imm32"

var/reg <- subtract var2/reg2     => "29/subtract-from %" reg " " reg2 "/r32"
var/reg <- subtract var2          => "2b/subtract *(ebp+" var2.stack-offset ") " reg "/r32"
var/reg <- subtract *var2/reg2    => "2b/subtract *" reg2 " " reg1 "/r32"
subtract-from var1, var2/reg2     => "29/subtract-from *(ebp+" var1.stack-offset ") " reg2 "/r32"
var/eax <- subtract n             => "2d/subtract-from-eax " n "/imm32"
var/reg <- subtract n             => "81 5/subop/subtract %" reg " " n "/imm32"
subtract-from var, n              => "81 5/subop/subtract *(ebp+" var.stack-offset ") " n "/imm32"
subtract-from *var/reg, n         => "81 5/subop/subtract *" reg " " n "/imm32"

var/reg <- and var2/reg2          => "21/and-with %" reg " " reg2 "/r32"
var/reg <- and var2               => "23/and *(ebp+" var2.stack-offset " " reg "/r32"
var/reg <- and *var2/reg2         => "23/and *" reg2 " " reg "/r32"
and-with var1, var2/reg           => "21/and-with *(ebp+" var1.stack-offset ") " reg "/r32"
var/eax <- and n                  => "25/and-with-eax " n "/imm32"
var/reg <- and n                  => "81 4/subop/and %" reg " " n "/imm32"
and-with var, n                   => "81 4/subop/and *(ebp+" var.stack-offset ") " n "/imm32"
and-with *var/reg, n              => "81 4/subop/and *" reg " " n "/imm32"

var/reg <- or var2/reg2           => "09/or-with %" reg " " reg2 "/r32"
var/reg <- or var2                => "0b/or *(ebp+" var2.stack-offset ") " reg "/r32"
var/reg <- or *var2/reg2          => "0b/or *" reg2 " " reg "/r32"
or-with var1, var2/reg2           => "09/or-with *(ebp+" var1.stack-offset " " reg2 "/r32"
var/eax <- or n                   => "0d/or-with-eax " n "/imm32"
var/reg <- or n                   => "81 1/subop/or %" reg " " n "/imm32"
or-with var, n                    => "81 1/subop/or *(ebp+" var.stack-offset ") " n "/imm32"
or-with *var/reg, n               => "81 1/subop/or *" reg " " n "/imm32"

var/reg <- xor var2/reg2          => "31/xor-with %" reg " " reg2 "/r32"
var/reg <- xor var2               => "33/xor *(ebp+" var2.stack-offset ") " reg "/r32"
var/reg <- xor *var2/reg2         => "33/xor *" reg2 " " reg "/r32"
xor-with var1, var2/reg           => "31/xor-with *(ebp+" var1.stack-offset ") " reg "/r32"
var/eax <- xor n                  => "35/xor-with-eax " n "/imm32"
var/reg <- xor n                  => "81 6/subop/xor %" reg " " n "/imm32"
xor-with var, n                   => "81 6/subop/xor *(ebp+" var.stack-offset ") " n "/imm32"
xor-with *var/reg, n              => "81 6/subop/xor *" reg " " n "/imm32"

var/eax <- copy n                 => "b8/copy-to-eax " n "/imm32"
var/ecx <- copy n                 => "b9/copy-to-ecx " n "/imm32"
var/edx <- copy n                 => "ba/copy-to-edx " n "/imm32"
var/ebx <- copy n                 => "bb/copy-to-ebx " n "/imm32"
var/esi <- copy n                 => "be/copy-to-esi " n "/imm32"
var/edi <- copy n                 => "bf/copy-to-edi " n "/imm32"
var/reg <- copy var2/reg2         => "89/<- %" reg " " reg2 "/r32"
copy-to var1, var2/reg            => "89/<- *(ebp+" var1.stack-offset ") " reg "/r32"
var/reg <- copy var2              => "8b/-> *(ebp+" var2.stack-offset ") " reg "/r32"
var/reg <- copy *var2/reg2        => "8b/-> *" reg2 " " reg "/r32"
var/reg <- copy n                 => "c7 0/subop/copy %" reg " " n "/imm32"
copy-to var, n                    => "c7 0/subop/copy *(ebp+" var.stack-offset ") " n "/imm32"
copy-to *var/reg, n               => "c7 0/subop/copy *" reg " " n "/imm32"

compare var1, var2/reg2           => "39/compare *(ebp+" var1.stack-offset ") " reg2 "/r32"
compare *var1/reg1, var2/reg2     => "39/compare *" reg1 " " reg2 "/r32"
compare var1/reg1, var2           => "3b/compare<- *(ebp+" var2.stack-offset ") " reg1 "/r32"
compare var/reg, *var2/reg2       => "3b/compare<- *" reg " " n "/imm32"
compare var/eax, n                => "3d/compare-eax-with " n "/imm32"
compare var, n                    => "81 7/subop/compare *(ebp+" var.stack-offset ") " n "/imm32"
compare *var/reg, n               => "81 7/subop/compare *" reg " " n "/imm32"

var/reg <- multiply var2          => "0f af/multiply *(ebp+" var2.stack-offset ") " reg "/r32"
var/reg <- multiply *var2/reg2    => "0f af/multiply *" reg2 " " reg "/r32"

break                             => "e9/jump break/disp32"
break label                       => "e9/jump " label ":break/disp32"
loop                              => "e9/jump loop/disp32"
loop label                        => "e9/jump " label ":loop/disp32"

break-if-=                        => "0f 84/jump-if-= break/disp32"
break-if-= label                  => "0f 84/jump-if-= " label ":break/disp32"
loop-if-=                         => "0f 84/jump-if-= loop/disp32"
loop-if-= label                   => "0f 84/jump-if-= " label ":loop/disp32"

break-if-!=                       => "0f 85/jump-if-!= break/disp32"
break-if-!= label                 => "0f 85/jump-if-!= " label ":break/disp32"
loop-if-!=                        => "0f 85/jump-if-!= loop/disp32"
loop-if-!= label                  => "0f 85/jump-if-!= " label ":loop/disp32"

break-if-<                        => "0f 8c/jump-if-< break/disp32"
break-if-< label                  => "0f 8c/jump-if-< " label ":break/disp32"
loop-if-<                         => "0f 8c/jump-if-< loop/disp32"
loop-if-< label                   => "0f 8c/jump-if-< " label ":loop/disp32"

break-if->                        => "0f 8f/jump-if-> break/disp32"
break-if-> label                  => "0f 8f/jump-if-> " label ":break/disp32"
loop-if->                         => "0f 8f/jump-if-> loop/disp32"
loop-if-> label                   => "0f 8f/jump-if-> " label ":loop/disp32"

break-if-<=                       => "0f 8e/jump-if-<= break/disp32"
break-if-<= label                 => "0f 8e/jump-if-<= " label ":break/disp32"
loop-if-<=                        => "0f 8e/jump-if-<= loop/disp32"
loop-if-<= label                  => "0f 8e/jump-if-<= " label ":loop/disp32"

break-if->=                       => "0f 8d/jump-if->= break/disp32"
break-if->= label                 => "0f 8d/jump-if->= " label ":break/disp32"
loop-if->=                        => "0f 8d/jump-if->= loop/disp32"
loop-if->= label                  => "0f 8d/jump-if->= " label ":loop/disp32"

break-if-addr<                    => "0f 82/jump-if-addr< break/disp32"
break-if-addr< label              => "0f 82/jump-if-addr< " label ":break/disp32"
loop-if-addr<                     => "0f 82/jump-if-addr< loop/disp32"
loop-if-addr< label               => "0f 82/jump-if-addr< " label ":loop/disp32"

break-if-addr>                    => "0f 87/jump-if-addr> break/disp32"
break-if-addr> label              => "0f 87/jump-if-addr> " label ":break/disp32"
loop-if-addr>                     => "0f 87/jump-if-addr> loop/disp32"
loop-if-addr> label               => "0f 87/jump-if-addr> " label ":loop/disp32"

break-if-addr<=                   => "0f 86/jump-if-addr<= break/disp32"
break-if-addr<= label             => "0f 86/jump-if-addr<= " label ":break/disp32"
loop-if-addr<=                    => "0f 86/jump-if-addr<= loop/disp32"
loop-if-addr<= label              => "0f 86/jump-if-addr<= " label ":loop/disp32"

break-if-addr>=                   => "0f 83/jump-if-addr>= break/disp32"
break-if-addr>= label             => "0f 83/jump-if-addr>= " label ":break/disp32"
loop-if-addr>=                    => "0f 83/jump-if-addr>= loop/disp32"
loop-if-addr>= label              => "0f 83/jump-if-addr>= " label ":loop/disp32"

In the following instructions types are provided for clarity even if they must
be provided in an earlier 'var' declaration.

# Address operations

var/reg: (addr T) <- address var2: T
  => "8d/copy-address *(ebp+" var2.stack-offset ") " reg "/r32"

Array operations (TODO: bounds-checking)

var/reg <- length arr/reg2: (addr array T)
  => "8b/-> *" reg2 " " reg "/r32"
var/reg <- index arr/rega: (addr array T), idx/regi: int  # if size(T) is 4 or 8
  => "8d/copy-address *(" rega "+" regi "<<" log2(size(T)) "+4) " reg "/r32"
var/reg <- index arr: (array T sz), idx/regi: int
  => "8d/copy-address *(ebp+" regi "<<" log2(size(T)) "+" (arr.stack-offset + 4) ") " reg "/r32"
var/reg <- index arr/rega: (addr array T), n
  => "8d/copy-address *(" rega "+" (n*size(T)+4) ") " reg "/r32"
var/reg <- index arr: (array T sz), n
  => "8d/copy-address *(ebp+" (arr.stack-offset+4+n*size(T)) ") " reg "/r32"

var/reg: (offset T) <- compute-offset arr: (addr array T), idx/regi: int  # arr can be in reg or mem
  => "69/multiply %" regi " " size(T) "/imm32 " reg "/r32"
var/reg: (offset T) <- compute-offset arr: (addr array T), idx: int       # arr can be in reg or mem
  => "69/multiply *(ebp+" idx.stack-offset ") " size(T) "/imm32 " reg "/r32"
var/reg <- index arr/rega: (addr array T), o/rego: offset
  => "8d/copy-address *(" rega "+" rego "+4) " reg "/r32"

# User-defined types

If a record (product) type T was defined to have elements a, b, c, ... of
types T_a, T_b, T_c, ..., then accessing one of those elements f of type T_f:

var/reg: (addr T_f) <- get var2/reg2: (addr F), f
  => "8d/copy-address *(" reg2 "+" offset(f) ") " reg "/r32"
var/reg: (addr T_f) <- get var2: (addr F), f
  => "8d/copy-address *(ebp+" var2.stack-offset "+" offset(f) ") " reg "/r32"

# Handles for safe access to the heap

copy-handle-to dest: (handle T), src: (handle T)
  => "50/push-eax"
     "8b/-> *(ebp+" src.stack-offset ") 0/r32/eax"
     "89/<- *(ebp+" dest.stack-offset ") 0/r32/eax"
     "8b/-> *(ebp+" src.stack-offset+4 ") 0/r32/eax"
     "89/<- *(ebp+" dest.stack-offset+4 ") 0/r32/eax"
     "58/pop-to-eax"

copy-handle-to *dest/reg: (addr handle T), src: (handle T)
  => "50/push-eax"
     "8b/-> *(ebp+" src.stack-offset ") 0/r32/eax"
     "89/<- *" reg " 0/r32/eax"
     "8b/-> *(ebp+" src.stack-offset+4 ") 0/r32/eax"
     "89/<- *(" reg "+4) 0/r32/eax"
     "58/pop-to-eax"

out/reg: (addr T) <- lookup in: (handle T)
  => # payload_allocid = in->address->allocid
     "8b/-> *(epb+" (in.stack-offset+4) ") " reg "/r32"
     "8b/-> *" reg " " reg "/r32"
     # if (payload_allocid != handle->allocid) abort
     "39/compare *(ebp+" in.stack-offset ") " reg "/r32"
     "0f 85/jump-if-!= $lookup:abort/disp32"
     # return payload
     "8b/-> *(epb+" (in.stack-offset+4) ") " reg "/r32"
     "81 0/subop/add %" reg " 4/imm32"  # skip payload->allocid

vim:ft=mu:nowrap:textwidth=0