From fe34dc47187ed489b4268a7dbc85ae5b93ca6588 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Mon, 5 Oct 2020 10:12:34 -0700 Subject: 6955 --- html/mu_instructions.html | 57 +++++++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/html/mu_instructions.html b/html/mu_instructions.html index 476b7133..8f21aa08 100644 --- a/html/mu_instructions.html +++ b/html/mu_instructions.html @@ -13,17 +13,16 @@ pre { font-family: monospace; color: #000000; background-color: #c6c6c6; } body { font-family: monospace; color: #000000; background-color: #c6c6c6; } * { font-size: 1em; } -.Comment { color: #005faf; } +.muComment { color: #005faf; } .SpecialChar { color: #d70000; } .Constant { color: #008787; } .PreProc { color: #c000c0; } -.SalientComment { color: #0000af; } -->
-## Mu's instructions and their table-driven translation
+## Mu's instructions and their table-driven translation
 
 See http://akkartik.name/akkartik-convivial-20200607.pdf for the complete
 story. In brief: Mu is a statement-oriented language. Blocks consist of flat
@@ -106,6 +105,10 @@ var/reg <- xor n                  => "81 6/subop/xor *(ebp+" var.stack-offset ") " n "/imm32"
 xor-with *var/reg, n              => "81 6/subop/xor *" reg " " n "/imm32"
 
+var/reg <- negate                 => "f7 3/subop/negate %" reg
+negate var                        => "f7 3/subop/negate *(ebp+" var.stack-offset ")"
+negate *var/reg                   => "f7 3/subop/negate *" reg
+
 var/reg <- shift-left n           => "c1/shift 4/subop/left %" reg " " n "/imm32"
 var/reg <- shift-right n          => "c1/shift 5/subop/right %" reg " " n "/imm32"
 var/reg <- shift-right-signed n   => "c1/shift 7/subop/right-signed %" reg " " n "/imm32"
@@ -202,7 +205,7 @@ var/reg <- multiply *var2/reg2    => loop-if-addr>=                    => "0f 83/jump-if-addr>= loop/disp32"
 loop-if-addr>= label              => "0f 83/jump-if-addr>= " label ":loop/disp32"
 
-Similar float variants like `break-if-float<` are aliases for the corresponding
+Similar float variants like `break-if-float<` are aliases for the corresponding
 `addr` equivalents. The x86 instruction set stupidly has floating-point
 operations only update a subset of flags.
 
@@ -211,12 +214,12 @@ operations only update a subset of flags.
 In the following instructions types are provided for clarity even if they must
 be provided in an earlier 'var' declaration.
 
-# Address operations
+# Address operations
 
 var/reg: (addr T) <- address var2: T
   => "8d/copy-address *(ebp+" var2.stack-offset ") " reg "/r32"
 
-# Array operations
+# Array operations
 (TODO: bounds-checking)
 
 var/reg <- index arr/rega: (addr array T), idx/regi: int
@@ -229,9 +232,9 @@ var/reg <- index arr/rega: (addr array T), n
 var/reg <- index arr: (array T sz), n
   => "8d/copy-address *(ebp+" (arr.stack-offset+4+n*size-of(T)) ") " reg "/r32"
 
-var/reg: (offset T) <- compute-offset arr: (addr array T), idx/regi: int  # arr can be in reg or mem
+var/reg: (offset T) <- compute-offset arr: (addr array T), idx/regi: int  # arr can be in reg or mem
   => "69/multiply %" regi " " size-of(T) "/imm32 " reg "/r32"
-var/reg: (offset T) <- compute-offset arr: (addr array T), idx: int       # arr can be in reg or mem
+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-of(T) "/imm32 " reg "/r32"
 var/reg <- index arr/rega: (addr array T), o/rego: offset
   => "8d/copy-address *(" rega "+" rego "+4) " reg "/r32"
@@ -254,7 +257,7 @@ var/reg <- length arr/reg2: (addr array T)
          if reg is not edx
           "52/push-edx"
          "8b/-> *" reg2 " eax/r32"
-         "31/xor %edx 2/r32/edx"  # sign-extend, but array size can't be negative
+         "31/xor %edx 2/r32/edx"  # sign-extend, but array size can't be negative
          "b9/copy-to-ecx " size-of(T) "/imm32"
          "f7 7/subop/idiv-eax-edx-by %ecx"
          if reg is not eax
@@ -266,7 +269,7 @@ var/reg <- length arr/reg2: (addr array T)
          if reg is not eax
           "58/pop-to-eax"
 
-# User-defined types
+# 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:
@@ -276,15 +279,15 @@ var/reg: (addr T_f) <- get var2/reg2: (addr
 var/reg: (addr T_f) <- get var2: T, f
   => "8d/copy-address *(ebp+" var2.stack-offset "+" offset(f) ") " reg "/r32"
 
-# Allocating memory
+# Allocating memory
 
 allocate in: (addr handle T)
   => "(allocate Heap " size-of(T) " " in ")"
 
-populate in: (addr handle array T), num  # can be literal or variable on stack or register
+populate in: (addr handle array T), num  # can be literal or variable on stack or register
   => "(allocate-array2 Heap " size-of(T) " " num " " in ")"
 
-populate-stream in: (addr handle stream T), num  # can be literal or variable on stack or register
+populate-stream in: (addr handle stream T), num  # can be literal or variable on stack or register
   => "(new-stream Heap " size-of(T) " " num " " in ")"
 
 read-from-stream s: (addr stream T), out: (addr T)
@@ -293,47 +296,47 @@ read-from-stream s: (addr stream T), out: (addr T)
 write-to-stream s: (addr stream T), in: (addr T)
   => "(write-to-stream " s " " in " " size-of(T) ")"
 
-# Floating-point operations
+# Floating-point operations
 
 All the instructions so far use Intel's general-purpose integer registers.
 However, some of them translate to different SubX if their arguments are in
 floating-point registers.
 
-var/xreg <- add var2/xreg2        => "f3 0f 58/add 3/mod " xreg2 "/xm32 " xreg1 "/x32"
+var/xreg <- add var2/xreg2        => "f3 0f 58/add %" xreg2 " " xreg1 "/x32"
 var/xreg <- add var2              => "f3 0f 58/add *(ebp+" var2.stack-offset ") " xreg "/x32"
 var/xreg <- add *var2/reg2        => "f3 0f 58/add *" reg2 " " xreg "/x32"
 
-var/xreg <- subtract var2/xreg2   => "f3 0f 5c/subtract 3/mod " xreg2 "/xm32 " xreg1 "/x32"
+var/xreg <- subtract var2/xreg2   => "f3 0f 5c/subtract %" xreg2 " " xreg1 "/x32"
 var/xreg <- subtract var2         => "f3 0f 5c/subtract *(ebp+" var2.stack-offset ") " xreg "/x32"
 var/xreg <- subtract *var2/reg2   => "f3 0f 5c/subtract *" reg2 " " xreg "/x32"
 
-var/xreg <- multiply var2/xreg2   => "f3 0f 59/multiply 3/mod " xreg2 "/xm32 " xreg1 "/x32"
+var/xreg <- multiply var2/xreg2   => "f3 0f 59/multiply %" xreg2 " " xreg1 "/x32"
 var/xreg <- multiply var2         => "f3 0f 59/multiply *(ebp+" var2.stack-offset ") " xreg "/x32"
 var/xreg <- multiply *var2/reg2   => "f3 0f 59/multiply *" reg2 " " xreg "/x32"
 
-var/xreg <- divide var2/xreg2     => "f3 0f 5e/divide 3/mod " xreg2 "/xm32 " xreg1 "/x32"
+var/xreg <- divide var2/xreg2     => "f3 0f 5e/divide %" xreg2 " " xreg1 "/x32"
 var/xreg <- divide var2           => "f3 0f 5e/divide *(ebp+" var2.stack-offset ") " xreg "/x32"
 var/xreg <- divide *var2/reg2     => "f3 0f 5e/divide *" reg2 " " xreg "/x32"
 
 There are also some exclusively floating-point instructions:
 
-var/xreg <- reciprocal var2/xreg2 => "f3 0f 53/reciprocal 3/mod " xreg2 "/xm32 " xreg1 "/x32"
+var/xreg <- reciprocal var2/xreg2 => "f3 0f 53/reciprocal %" xreg2 " " xreg1 "/x32"
 var/xreg <- reciprocal var2       => "f3 0f 53/reciprocal *(ebp+" var2.stack-offset ") " xreg "/x32"
 var/xreg <- reciprocal *var2/reg2 => "f3 0f 53/reciprocal *" reg2 " " xreg "/x32"
 
-var/xreg <- square-root var2/xreg2 => "f3 0f 51/square-root 3/mod " xreg2 "/xm32 " xreg1 "/x32"
+var/xreg <- square-root var2/xreg2 => "f3 0f 51/square-root %" xreg2 " " xreg1 "/x32"
 var/xreg <- square-root var2       => "f3 0f 51/square-root *(ebp+" var2.stack-offset ") " xreg "/x32"
 var/xreg <- square-root *var2/reg2 => "f3 0f 51/square-root *" reg2 " " xreg "/x32"
 
-var/xreg <- inverse-square-root var2/xreg2 => "f3 0f 52/inverse-square-root 3/mod " xreg2 "/xm32 " xreg1 "/x32"
+var/xreg <- inverse-square-root var2/xreg2 => "f3 0f 52/inverse-square-root %" xreg2 " " xreg1 "/x32"
 var/xreg <- inverse-square-root var2       => "f3 0f 52/inverse-square-root *(ebp+" var2.stack-offset ") " xreg "/x32"
 var/xreg <- inverse-square-root *var2/reg2 => "f3 0f 52/inverse-square-root *" reg2 " " xreg "/x32"
 
-var/xreg <- min var2/xreg2        => "f3 0f 5d/min 3/mod " xreg2 "/xm32 " xreg1 "/x32"
+var/xreg <- min var2/xreg2        => "f3 0f 5d/min %" xreg2 " " xreg1 "/x32"
 var/xreg <- min var2              => "f3 0f 5d/min *(ebp+" var2.stack-offset ") " xreg "/x32"
 var/xreg <- min *var2/reg2        => "f3 0f 5d/min *" reg2 " " xreg "/x32"
 
-var/xreg <- max var2/xreg2        => "f3 0f 5f/max 3/mod " xreg2 "/xm32 " xreg1 "/x32"
+var/xreg <- max var2/xreg2        => "f3 0f 5f/max %" xreg2 " " xreg1 "/x32"
 var/xreg <- max var2              => "f3 0f 5f/max *(ebp+" var2.stack-offset ") " xreg "/x32"
 var/xreg <- max *var2/reg2        => "f3 0f 5f/max *" reg2 " " xreg "/x32"
 
@@ -348,7 +351,7 @@ var/xreg <- convert var2/reg2     => <- convert var2          => "f3 0f 2a/convert-to-float *(ebp+" var2.stack-offset ") " xreg "/x32"
 var/xreg <- convert *var2/reg2    => "f3 0f 2a/convert-to-float *" reg2 " " xreg "/x32"
 
-var/reg <- convert var2/xreg2     => "f3 0f 2d/convert-to-int 3/mod " xreg2 "/xm32 " reg "/r32"
+var/reg <- convert var2/xreg2     => "f3 0f 2d/convert-to-int %" xreg2 " " reg "/r32"
 var/reg <- convert var2           => "f3 0f 2d/convert-to-int *(ebp+" var2.stack-offset ") " reg "/r32"
 var/reg <- convert *var2/reg2     => "f3 0f 2d/convert-to-int *" reg2 " " reg "/r32"
 
@@ -360,15 +363,15 @@ One pattern you may have noticed above is that the floating-point instructions
 above always write to registers. The only exceptions are `copy` instructions,
 which can write to memory locations.
 
-var/xreg <- copy var2/xreg2       => "f3 0f 11/<- 3/mod " xreg "/xm32 " xreg2 "/x32"
+var/xreg <- copy var2/xreg2       => "f3 0f 11/<- %" xreg " " xreg2 "/x32"
 copy-to var1, var2/xreg           => "f3 0f 11/<- *(ebp+" var1.stack-offset ") " xreg "/x32"
 var/xreg <- copy var2             => "f3 0f 10/-> *(ebp+" var2.stack-offset ") " xreg "/x32"
 var/xreg <- copy *var2/reg2       => "f3 0f 10/-> *" reg2 " " xreg "/x32"
 
 Comparisons must always start with a register:
 
-compare var1/xreg1, var2/xreg2    => "0f 2f/compare 3/mod " xreg2 "/xm32 " xreg1 "/x32"
-compare var1/xreg1, var2          => "0f 2f/compare 2/mod *(ebp+" var2.stack-offset ") " xreg1 "/x32"
+compare var1/xreg1, var2/xreg2    => "0f 2f/compare %" xreg2 " " xreg1 "/x32"
+compare var1/xreg1, var2          => "0f 2f/compare *(ebp+" var2.stack-offset ") " xreg1 "/x32"
 
 vim:ft=mu:nowrap:textwidth=0
 
-- cgit 1.4.1-2-gfad0