summary refs log tree commit diff stats
path: root/compiler/linter.nim
blob: f3e2d620711f563068604846eb9a89c61fb565a5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
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
#
#
#           The Nim Compiler
#        (c) Copyright 2015 Andreas Rumpf
#
#    See the file "copying.txt", included in this
#    distribution, for details about the copyright.
#

## This module implements the style checker.

import std/strutils
from std/sugar import dup

import options, ast, msgs, idents, lineinfos, wordrecg, astmsgs, semdata, packages
export packages

const
  Letters* = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '_'}

proc identLen*(line: string, start: int): int =
  while start+result < line.len and line[start+result] in Letters:
    inc result

proc `=~`(s: string, a: openArray[string]): bool =
  for x in a:
    if s.startsWith(x): return true

proc beautifyName(s: string, k: TSymKind): string =
  # minimal set of rules here for transition:
  # GC_ is allowed

  let allUpper = allCharsInSet(s, {'A'..'Z', '0'..'9', '_'})
  if allUpper and k in {skConst, skEnumField, skType}: return s
  result = newStringOfCap(s.len)
  var i = 0
  case k
  of skType, skGenericParam:
    # Types should start with a capital unless builtins like 'int' etc.:
    if s =~ ["int", "uint", "cint", "cuint", "clong", "cstring", "string",
             "char", "byte", "bool", "openArray", "seq", "array", "void",
             "pointer", "float", "csize", "csize_t", "cdouble", "cchar", "cschar",
             "cshort", "cu", "nil", "typedesc", "auto", "any",
             "range", "openarray", "varargs", "set", "cfloat", "ref", "ptr",
             "untyped", "typed", "static", "sink", "lent", "type", "owned", "iterable"]:
      result.add s[i]
    else:
      result.add toUpperAscii(s[i])
  of skConst, skEnumField:
    # for 'const' we keep how it's spelt; either upper case or lower case:
    result.add s[0]
  else:
    # as a special rule, don't transform 'L' to 'l'
    if s.len == 1 and s[0] == 'L': result.add 'L'
    elif '_' in s: result.add(s[i])
    else: result.add toLowerAscii(s[0])
  inc i
  while i < s.len:
    if s[i] == '_':
      if i+1 >= s.len:
        discard "trailing underscores should be stripped off"
      elif i > 0 and s[i-1] in {'A'..'Z'}:
        # don't skip '_' as it's essential for e.g. 'GC_disable'
        result.add('_')
        inc i
        result.add s[i]
      else:
        inc i
        result.add toUpperAscii(s[i])
    elif allUpper:
      result.add toLowerAscii(s[i])
    else:
      result.add s[i]
    inc i

proc differ*(line: string, a, b: int, x: string): string =
  proc substrEq(s: string, pos, last: int, substr: string): bool =
    result = true
    for i in 0..<substr.len:
      if pos+i > last or s[pos+i] != substr[i]: return false

  result = ""
  if not substrEq(line, a, b, x):
    let y = line[a..b]
    if cmpIgnoreStyle(y, x) == 0:
      result = y

proc nep1CheckDefImpl(conf: ConfigRef; info: TLineInfo; s: PSym; k: TSymKind) =
  let beau = beautifyName(s.name.s, k)
  if s.name.s != beau:
    lintReport(conf, info, beau, s.name.s)

template styleCheckDef*(ctx: PContext; info: TLineInfo; sym: PSym; k: TSymKind) =
  ## Check symbol definitions adhere to NEP1 style rules.
  if optStyleCheck in ctx.config.options and # ignore if styleChecks are off
     {optStyleHint, optStyleError} * ctx.config.globalOptions != {} and # check only if hint/error is enabled
     hintName in ctx.config.notes and # ignore if name checks are not requested
     ctx.config.belongsToProjectPackage(sym) and # ignore foreign packages
     optStyleUsages notin ctx.config.globalOptions and # ignore if requested to only check name usage
     sym.kind != skResult and # ignore `result`
     sym.kind != skTemp and # ignore temporary variables created by the compiler
     sym.name.s[0] in Letters and # ignore operators TODO: what about unicode symbols???
     k notin {skType, skGenericParam} and # ignore types and generic params
     (sym.typ == nil or sym.typ.kind != tyTypeDesc) and # ignore `typedesc`
     {sfImportc, sfExportc} * sym.flags == {} and # ignore FFI
     sfAnon notin sym.flags: # ignore if created by compiler
    nep1CheckDefImpl(ctx.config, info, sym, k)

template styleCheckDef*(ctx: PContext; info: TLineInfo; s: PSym) =
  ## Check symbol definitions adhere to NEP1 style rules.
  styleCheckDef(ctx, info, s, s.kind)

template styleCheckDef*(ctx: PContext; s: PSym) =
  ## Check symbol definitions adhere to NEP1 style rules.
  styleCheckDef(ctx, s.info, s, s.kind)

proc differs(conf: ConfigRef; info: TLineInfo; newName: string): string =
  let line = sourceLine(conf, info)
  var first = min(info.col.int, line.len)
  if first < 0: return
  #inc first, skipIgnoreCase(line, "proc ", first)
  while first > 0 and line[first-1] in Letters: dec first
  if first < 0: return
  if first+1 < line.len and line[first] == '`': inc first

  let last = first+identLen(line, first)-1
  result = differ(line, first, last, newName)

proc styleCheckUseImpl(conf: ConfigRef; info: TLineInfo; s: PSym) =
  let newName = s.name.s
  let badName = differs(conf, info, newName)
  if badName.len > 0:
    lintReport(conf, info, newName, badName, "".dup(addDeclaredLoc(conf, s)))

template styleCheckUse*(ctx: PContext; info: TLineInfo; sym: PSym) =
  ## Check symbol uses match their definition's style.
  if {optStyleHint, optStyleError} * ctx.config.globalOptions != {} and # ignore if styleChecks are off
     hintName in ctx.config.notes and # ignore if name checks are not requested
     ctx.config.belongsToProjectPackage(sym) and # ignore foreign packages
     sym.kind != skTemp and # ignore temporary variables created by the compiler
     sym.name.s[0] in Letters and # ignore operators TODO: what about unicode symbols???
     sfAnon notin sym.flags: # ignore temporary variables created by the compiler
    styleCheckUseImpl(ctx.config, info, sym)

proc checkPragmaUseImpl(conf: ConfigRef; info: TLineInfo; w: TSpecialWord; pragmaName: string) =
  let wanted = $w
  if pragmaName != wanted:
    lintReport(conf, info, wanted, pragmaName)

template checkPragmaUse*(ctx: PContext; info: TLineInfo; w: TSpecialWord; pragmaName: string, sym: PSym) =
  ## Check builtin pragma uses match their definition's style.
  ## Note: This only applies to builtin pragmas, not user pragmas.
  if {optStyleHint, optStyleError} * ctx.config.globalOptions != {} and # ignore if styleChecks are off
     hintName in ctx.config.notes and # ignore if name checks are not requested
     (sym != nil and ctx.config.belongsToProjectPackage(sym)): # ignore foreign packages
    checkPragmaUseImpl(ctx.config, info, w, pragmaName)
">span class="Constant">&quot;/r32&quot;</span> subtract-from *var1/reg1, var2/reg2 =&gt; <span class="Constant">&quot;29/subtract-from *&quot;</span> reg1 <span class="Constant">&quot; &quot;</span> reg2 <span class="Constant">&quot;/r32&quot;</span> var/<span class="Constant">eax</span> <span class="Special">&lt;-</span> subtract n =&gt; <span class="Constant">&quot;2d/subtract-from-eax &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> var/reg <span class="Special">&lt;-</span> subtract n =&gt; <span class="Constant">&quot;81 5/subop/subtract %&quot;</span> reg <span class="Constant">&quot; &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> subtract-from var, n =&gt; <span class="Constant">&quot;81 5/subop/subtract *(ebp+&quot;</span> var.stack-offset <span class="Constant">&quot;) &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> subtract-from *var/reg, n =&gt; <span class="Constant">&quot;81 5/subop/subtract *&quot;</span> reg <span class="Constant">&quot; &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> var/reg <span class="Special">&lt;-</span> and var2/reg2 =&gt; <span class="Constant">&quot;21/and-with %&quot;</span> reg <span class="Constant">&quot; &quot;</span> reg2 <span class="Constant">&quot;/r32&quot;</span> var/reg <span class="Special">&lt;-</span> and var2 =&gt; <span class="Constant">&quot;23/and *(ebp+&quot;</span> var2.stack-offset <span class="Constant">&quot; &quot;</span> reg <span class="Constant">&quot;/r32&quot;</span> var/reg <span class="Special">&lt;-</span> and *var2/reg2 =&gt; <span class="Constant">&quot;23/and *&quot;</span> reg2 <span class="Constant">&quot; &quot;</span> reg <span class="Constant">&quot;/r32&quot;</span> and-with var1, var2/reg =&gt; <span class="Constant">&quot;21/and-with *(ebp+&quot;</span> var1.stack-offset <span class="Constant">&quot;) &quot;</span> reg <span class="Constant">&quot;/r32&quot;</span> and-with *var1/reg1, var2/reg2 =&gt; <span class="Constant">&quot;21/and-with *&quot;</span> reg1 <span class="Constant">&quot; &quot;</span> reg2 <span class="Constant">&quot;/r32&quot;</span> var/<span class="Constant">eax</span> <span class="Special">&lt;-</span> and n =&gt; <span class="Constant">&quot;25/and-with-eax &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> var/reg <span class="Special">&lt;-</span> and n =&gt; <span class="Constant">&quot;81 4/subop/and %&quot;</span> reg <span class="Constant">&quot; &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> and-with var, n =&gt; <span class="Constant">&quot;81 4/subop/and *(ebp+&quot;</span> var.stack-offset <span class="Constant">&quot;) &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> and-with *var/reg, n =&gt; <span class="Constant">&quot;81 4/subop/and *&quot;</span> reg <span class="Constant">&quot; &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> var/reg <span class="Special">&lt;-</span> or var2/reg2 =&gt; <span class="Constant">&quot;09/or-with %&quot;</span> reg <span class="Constant">&quot; &quot;</span> reg2 <span class="Constant">&quot;/r32&quot;</span> var/reg <span class="Special">&lt;-</span> or var2 =&gt; <span class="Constant">&quot;0b/or *(ebp+&quot;</span> var2.stack-offset <span class="Constant">&quot;) &quot;</span> reg <span class="Constant">&quot;/r32&quot;</span> var/reg <span class="Special">&lt;-</span> or *var2/reg2 =&gt; <span class="Constant">&quot;0b/or *&quot;</span> reg2 <span class="Constant">&quot; &quot;</span> reg <span class="Constant">&quot;/r32&quot;</span> or-with var1, var2/reg2 =&gt; <span class="Constant">&quot;09/or-with *(ebp+&quot;</span> var1.stack-offset <span class="Constant">&quot; &quot;</span> reg2 <span class="Constant">&quot;/r32&quot;</span> or-with *var1/reg1, var2/reg2 =&gt; <span class="Constant">&quot;09/or-with *&quot;</span> reg1 <span class="Constant">&quot; &quot;</span> reg2 <span class="Constant">&quot;/r32&quot;</span> var/<span class="Constant">eax</span> <span class="Special">&lt;-</span> or n =&gt; <span class="Constant">&quot;0d/or-with-eax &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> var/reg <span class="Special">&lt;-</span> or n =&gt; <span class="Constant">&quot;81 1/subop/or %&quot;</span> reg <span class="Constant">&quot; &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> or-with var, n =&gt; <span class="Constant">&quot;81 1/subop/or *(ebp+&quot;</span> var.stack-offset <span class="Constant">&quot;) &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> or-with *var/reg, n =&gt; <span class="Constant">&quot;81 1/subop/or *&quot;</span> reg <span class="Constant">&quot; &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> var/reg <span class="Special">&lt;-</span> not =&gt; <span class="Constant">&quot;f7 2/subop/not %&quot;</span> reg not var =&gt; <span class="Constant">&quot;f7 2/subop/not *(ebp+&quot;</span> var.stack-offset <span class="Constant">&quot;)&quot;</span> not *var/reg =&gt; <span class="Constant">&quot;f7 2/subop/not *&quot;</span> reg var/reg <span class="Special">&lt;-</span> xor var2/reg2 =&gt; <span class="Constant">&quot;31/xor-with %&quot;</span> reg <span class="Constant">&quot; &quot;</span> reg2 <span class="Constant">&quot;/r32&quot;</span> var/reg <span class="Special">&lt;-</span> xor var2 =&gt; <span class="Constant">&quot;33/xor *(ebp+&quot;</span> var2.stack-offset <span class="Constant">&quot;) &quot;</span> reg <span class="Constant">&quot;/r32&quot;</span> var/reg <span class="Special">&lt;-</span> xor *var2/reg2 =&gt; <span class="Constant">&quot;33/xor *&quot;</span> reg2 <span class="Constant">&quot; &quot;</span> reg <span class="Constant">&quot;/r32&quot;</span> xor-with var1, var2/reg =&gt; <span class="Constant">&quot;31/xor-with *(ebp+&quot;</span> var1.stack-offset <span class="Constant">&quot;) &quot;</span> reg <span class="Constant">&quot;/r32&quot;</span> xor-with *var1/reg1, var2/reg2 =&gt; <span class="Constant">&quot;31/xor-with *&quot;</span> reg1 <span class="Constant">&quot; &quot;</span> reg2 <span class="Constant">&quot;/r32&quot;</span> var/<span class="Constant">eax</span> <span class="Special">&lt;-</span> xor n =&gt; <span class="Constant">&quot;35/xor-with-eax &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> var/reg <span class="Special">&lt;-</span> xor n =&gt; <span class="Constant">&quot;81 6/subop/xor %&quot;</span> reg <span class="Constant">&quot; &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> xor-with var, n =&gt; <span class="Constant">&quot;81 6/subop/xor *(ebp+&quot;</span> var.stack-offset <span class="Constant">&quot;) &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> xor-with *var/reg, n =&gt; <span class="Constant">&quot;81 6/subop/xor *&quot;</span> reg <span class="Constant">&quot; &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> var/reg <span class="Special">&lt;-</span> negate =&gt; <span class="Constant">&quot;f7 3/subop/negate %&quot;</span> reg negate var =&gt; <span class="Constant">&quot;f7 3/subop/negate *(ebp+&quot;</span> var.stack-offset <span class="Constant">&quot;)&quot;</span> negate *var/reg =&gt; <span class="Constant">&quot;f7 3/subop/negate *&quot;</span> reg var/reg <span class="Special">&lt;-</span> shift-left n =&gt; <span class="Constant">&quot;c1/shift 4/subop/left %&quot;</span> reg <span class="Constant">&quot; &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> var/reg <span class="Special">&lt;-</span> shift-right n =&gt; <span class="Constant">&quot;c1/shift 5/subop/right %&quot;</span> reg <span class="Constant">&quot; &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> var/reg <span class="Special">&lt;-</span> shift-right-signed n =&gt; <span class="Constant">&quot;c1/shift 7/subop/right-signed %&quot;</span> reg <span class="Constant">&quot; &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> shift-left var, n =&gt; <span class="Constant">&quot;c1/shift 4/subop/left *(ebp+&quot;</span> var.stack-offset <span class="Constant">&quot;) &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> shift-left *var/reg, n =&gt; <span class="Constant">&quot;c1/shift 4/subop/left *&quot;</span> reg <span class="Constant">&quot; &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> shift-right var, n =&gt; <span class="Constant">&quot;c1/shift 5/subop/right *(ebp+&quot;</span> var.stack-offset <span class="Constant">&quot;) &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> shift-right *var/reg, n =&gt; <span class="Constant">&quot;c1/shift 5/subop/right *&quot;</span> reg <span class="Constant">&quot; &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> shift-right-signed var, n =&gt; <span class="Constant">&quot;c1/shift 7/subop/right-signed *(ebp+&quot;</span> var.stack-offset <span class="Constant">&quot;) &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> shift-right-signed *var/reg, n =&gt; <span class="Constant">&quot;c1/shift 7/subop/right-signed *&quot;</span> reg <span class="Constant">&quot; &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> var/<span class="Constant">eax</span> <span class="Special">&lt;-</span> copy n =&gt; <span class="Constant">&quot;b8/copy-to-eax &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> var/<span class="Constant">ecx</span> <span class="Special">&lt;-</span> copy n =&gt; <span class="Constant">&quot;b9/copy-to-ecx &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> var/<span class="Constant">edx</span> <span class="Special">&lt;-</span> copy n =&gt; <span class="Constant">&quot;ba/copy-to-edx &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> var/<span class="Constant">ebx</span> <span class="Special">&lt;-</span> copy n =&gt; <span class="Constant">&quot;bb/copy-to-ebx &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> var/<span class="Constant">esi</span> <span class="Special">&lt;-</span> copy n =&gt; <span class="Constant">&quot;be/copy-to-esi &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> var/<span class="Constant">edi</span> <span class="Special">&lt;-</span> copy n =&gt; <span class="Constant">&quot;bf/copy-to-edi &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> var/reg <span class="Special">&lt;-</span> copy var2/reg2 =&gt; <span class="Constant">&quot;89/&lt;- %&quot;</span> reg <span class="Constant">&quot; &quot;</span> reg2 <span class="Constant">&quot;/r32&quot;</span> copy-to var1, var2/reg =&gt; <span class="Constant">&quot;89/&lt;- *(ebp+&quot;</span> var1.stack-offset <span class="Constant">&quot;) &quot;</span> reg <span class="Constant">&quot;/r32&quot;</span> copy-to *var1/reg1, var2/reg2 =&gt; <span class="Constant">&quot;89/&lt;- *&quot;</span> reg1 <span class="Constant">&quot; &quot;</span> reg2 <span class="Constant">&quot;/r32&quot;</span> var/reg <span class="Special">&lt;-</span> copy var2 =&gt; <span class="Constant">&quot;8b/-&gt; *(ebp+&quot;</span> var2.stack-offset <span class="Constant">&quot;) &quot;</span> reg <span class="Constant">&quot;/r32&quot;</span> var/reg <span class="Special">&lt;-</span> copy *var2/reg2 =&gt; <span class="Constant">&quot;8b/-&gt; *&quot;</span> reg2 <span class="Constant">&quot; &quot;</span> reg <span class="Constant">&quot;/r32&quot;</span> var/reg <span class="Special">&lt;-</span> copy n =&gt; <span class="Constant">&quot;c7 0/subop/copy %&quot;</span> reg <span class="Constant">&quot; &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> copy-to var, n =&gt; <span class="Constant">&quot;c7 0/subop/copy *(ebp+&quot;</span> var.stack-offset <span class="Constant">&quot;) &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> copy-to *var/reg, n =&gt; <span class="Constant">&quot;c7 0/subop/copy *&quot;</span> reg <span class="Constant">&quot; &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> var/reg <span class="Special">&lt;-</span> copy-byte var2/reg2 =&gt; <span class="Constant">&quot;8a/byte-&gt; %&quot;</span> reg2 <span class="Constant">&quot; &quot;</span> reg <span class="Constant">&quot;/r32&quot;</span> <span class="Constant">&quot;81 4/subop/and %&quot;</span> reg <span class="Constant">&quot; 0xff/imm32&quot;</span> var/reg <span class="Special">&lt;-</span> copy-byte *var2/reg2 =&gt; <span class="Constant">&quot;8a/byte-&gt; *&quot;</span> reg2 <span class="Constant">&quot; &quot;</span> reg <span class="Constant">&quot;/r32&quot;</span> <span class="Constant">&quot;81 4/subop/and %&quot;</span> reg <span class="Constant">&quot; 0xff/imm32&quot;</span> copy-byte-to *var1/reg1, var2/reg2 =&gt; <span class="Constant">&quot;88/byte&lt;- *&quot;</span> reg1 <span class="Constant">&quot; &quot;</span> reg2 <span class="Constant">&quot;/r32&quot;</span> compare var1, var2/reg2 =&gt; <span class="Constant">&quot;39/compare *(ebp+&quot;</span> var1.stack-offset <span class="Constant">&quot;) &quot;</span> reg2 <span class="Constant">&quot;/r32&quot;</span> compare *var1/reg1, var2/reg2 =&gt; <span class="Constant">&quot;39/compare *&quot;</span> reg1 <span class="Constant">&quot; &quot;</span> reg2 <span class="Constant">&quot;/r32&quot;</span> compare var1/reg1, var2 =&gt; <span class="Constant">&quot;3b/compare&lt;- *(ebp+&quot;</span> var2.stack-offset <span class="Constant">&quot;) &quot;</span> reg1 <span class="Constant">&quot;/r32&quot;</span> compare var/reg, *var2/reg2 =&gt; <span class="Constant">&quot;3b/compare&lt;- *&quot;</span> reg <span class="Constant">&quot; &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> compare var/<span class="Constant">eax</span>, n =&gt; <span class="Constant">&quot;3d/compare-eax-with &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> compare var/reg, n =&gt; <span class="Constant">&quot;81 7/subop/compare %&quot;</span> reg <span class="Constant">&quot; &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> compare var, n =&gt; <span class="Constant">&quot;81 7/subop/compare *(ebp+&quot;</span> var.stack-offset <span class="Constant">&quot;) &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> compare *var/reg, n =&gt; <span class="Constant">&quot;81 7/subop/compare *&quot;</span> reg <span class="Constant">&quot; &quot;</span> n <span class="Constant">&quot;/imm32&quot;</span> var/reg <span class="Special">&lt;-</span> multiply var2 =&gt; <span class="Constant">&quot;0f af/multiply *(ebp+&quot;</span> var2.stack-offset <span class="Constant">&quot;) &quot;</span> reg <span class="Constant">&quot;/r32&quot;</span> var/reg <span class="Special">&lt;-</span> multiply var2/reg2 =&gt; <span class="Constant">&quot;0f af/multiply %&quot;</span> reg2 <span class="Constant">&quot; &quot;</span> reg <span class="Constant">&quot;/r32&quot;</span> var/reg <span class="Special">&lt;-</span> multiply *var2/reg2 =&gt; <span class="Constant">&quot;0f af/multiply *&quot;</span> reg2 <span class="Constant">&quot; &quot;</span> reg <span class="Constant">&quot;/r32&quot;</span> <span class="muComment">## Floating-point operations</span> These instructions operate on either floating-point registers (xreg) or general-purpose registers (reg) in indirect mode. var/xreg <span class="Special">&lt;-</span> add var2/xreg2 =&gt; <span class="Constant">&quot;f3 0f 58/add %&quot;</span> xreg2 <span class="Constant">&quot; &quot;</span> xreg1 <span class="Constant">&quot;/x32&quot;</span> var/xreg <span class="Special">&lt;-</span> add var2 =&gt; <span class="Constant">&quot;f3 0f 58/add *(ebp+&quot;</span> var2.stack-offset <span class="Constant">&quot;) &quot;</span> xreg <span class="Constant">&quot;/x32&quot;</span> var/xreg <span class="Special">&lt;-</span> add *var2/reg2 =&gt; <span class="Constant">&quot;f3 0f 58/add *&quot;</span> reg2 <span class="Constant">&quot; &quot;</span> xreg <span class="Constant">&quot;/x32&quot;</span> var/xreg <span class="Special">&lt;-</span> subtract var2/xreg2 =&gt; <span class="Constant">&quot;f3 0f 5c/subtract %&quot;</span> xreg2 <span class="Constant">&quot; &quot;</span> xreg1 <span class="Constant">&quot;/x32&quot;</span> var/xreg <span class="Special">&lt;-</span> subtract var2 =&gt; <span class="Constant">&quot;f3 0f 5c/subtract *(ebp+&quot;</span> var2.stack-offset <span class="Constant">&quot;) &quot;</span> xreg <span class="Constant">&quot;/x32&quot;</span> var/xreg <span class="Special">&lt;-</span> subtract *var2/reg2 =&gt; <span class="Constant">&quot;f3 0f 5c/subtract *&quot;</span> reg2 <span class="Constant">&quot; &quot;</span> xreg <span class="Constant">&quot;/x32&quot;</span> var/xreg <span class="Special">&lt;-</span> multiply var2/xreg2 =&gt; <span class="Constant">&quot;f3 0f 59/multiply %&quot;</span> xreg2 <span class="Constant">&quot; &quot;</span> xreg1 <span class="Constant">&quot;/x32&quot;</span> var/xreg <span class="Special">&lt;-</span> multiply var2 =&gt; <span class="Constant">&quot;f3 0f 59/multiply *(ebp+&quot;</span> var2.stack-offset <span class="Constant">&quot;) &quot;</span> xreg <span class="Constant">&quot;/x32&quot;</span> var/xreg <span class="Special">&lt;-</span> multiply *var2/reg2 =&gt; <span class="Constant">&quot;f3 0f 59/multiply *&quot;</span> reg2 <span class="Constant">&quot; &quot;</span> xreg <span class="Constant">&quot;/x32&quot;</span> var/xreg <span class="Special">&lt;-</span> divide var2/xreg2 =&gt; <span class="Constant">&quot;f3 0f 5e/divide %&quot;</span> xreg2 <span class="Constant">&quot; &quot;</span> xreg1 <span class="Constant">&quot;/x32&quot;</span> var/xreg <span class="Special">&lt;-</span> divide var2 =&gt; <span class="Constant">&quot;f3 0f 5e/divide *(ebp+&quot;</span> var2.stack-offset <span class="Constant">&quot;) &quot;</span> xreg <span class="Constant">&quot;/x32&quot;</span> var/xreg <span class="Special">&lt;-</span> divide *var2/reg2 =&gt; <span class="Constant">&quot;f3 0f 5e/divide *&quot;</span> reg2 <span class="Constant">&quot; &quot;</span> xreg <span class="Constant">&quot;/x32&quot;</span> There are also some exclusively floating-point instructions: var/xreg <span class="Special">&lt;-</span> reciprocal var2/xreg2 =&gt; <span class="Constant">&quot;f3 0f 53/reciprocal %&quot;</span> xreg2 <span class="Constant">&quot; &quot;</span> xreg1 <span class="Constant">&quot;/x32&quot;</span> var/xreg <span class="Special">&lt;-</span> reciprocal var2 =&gt; <span class="Constant">&quot;f3 0f 53/reciprocal *(ebp+&quot;</span> var2.stack-offset <span class="Constant">&quot;) &quot;</span> xreg <span class="Constant">&quot;/x32&quot;</span> var/xreg <span class="Special">&lt;-</span> reciprocal *var2/reg2 =&gt; <span class="Constant">&quot;f3 0f 53/reciprocal *&quot;</span> reg2 <span class="Constant">&quot; &quot;</span> xreg <span class="Constant">&quot;/x32&quot;</span> var/xreg <span class="Special">&lt;-</span> square-root var2/xreg2 =&gt; <span class="Constant">&quot;f3 0f 51/square-root %&quot;</span> xreg2 <span class="Constant">&quot; &quot;</span> xreg1 <span class="Constant">&quot;/x32&quot;</span> var/xreg <span class="Special">&lt;-</span> square-root var2 =&gt; <span class="Constant">&quot;f3 0f 51/square-root *(ebp+&quot;</span> var2.stack-offset <span class="Constant">&quot;) &quot;</span> xreg <span class="Constant">&quot;/x32&quot;</span> var/xreg <span class="Special">&lt;-</span> square-root *var2/reg2 =&gt; <span class="Constant">&quot;f3 0f 51/square-root *&quot;</span> reg2 <span class="Constant">&quot; &quot;</span> xreg <span class="Constant">&quot;/x32&quot;</span> var/xreg <span class="Special">&lt;-</span> inverse-square-root var2/xreg2 =&gt; <span class="Constant">&quot;f3 0f 52/inverse-square-root %&quot;</span> xreg2 <span class="Constant">&quot; &quot;</span> xreg1 <span class="Constant">&quot;/x32&quot;</span> var/xreg <span class="Special">&lt;-</span> inverse-square-root var2 =&gt; <span class="Constant">&quot;f3 0f 52/inverse-square-root *(ebp+&quot;</span> var2.stack-offset <span class="Constant">&quot;) &quot;</span> xreg <span class="Constant">&quot;/x32&quot;</span> var/xreg <span class="Special">&lt;-</span> inverse-square-root *var2/reg2 =&gt; <span class="Constant">&quot;f3 0f 52/inverse-square-root *&quot;</span> reg2 <span class="Constant">&quot; &quot;</span> xreg <span class="Constant">&quot;/x32&quot;</span> var/xreg <span class="Special">&lt;-</span> min var2/xreg2 =&gt; <span class="Constant">&quot;f3 0f 5d/min %&quot;</span> xreg2 <span class="Constant">&quot; &quot;</span> xreg1 <span class="Constant">&quot;/x32&quot;</span> var/xreg <span class="Special">&lt;-</span> min var2 =&gt; <span class="Constant">&quot;f3 0f 5d/min *(ebp+&quot;</span> var2.stack-offset <span class="Constant">&quot;) &quot;</span> xreg <span class="Constant">&quot;/x32&quot;</span> var/xreg <span class="Special">&lt;-</span> min *var2/reg2 =&gt; <span class="Constant">&quot;f3 0f 5d/min *&quot;</span> reg2 <span class="Constant">&quot; &quot;</span> xreg <span class="Constant">&quot;/x32&quot;</span> var/xreg <span class="Special">&lt;-</span> max var2/xreg2 =&gt; <span class="Constant">&quot;f3 0f 5f/max %&quot;</span> xreg2 <span class="Constant">&quot; &quot;</span> xreg1 <span class="Constant">&quot;/x32&quot;</span> var/xreg <span class="Special">&lt;-</span> max var2 =&gt; <span class="Constant">&quot;f3 0f 5f/max *(ebp+&quot;</span> var2.stack-offset <span class="Constant">&quot;) &quot;</span> xreg <span class="Constant">&quot;/x32&quot;</span> var/xreg <span class="Special">&lt;-</span> max *var2/reg2 =&gt; <span class="Constant">&quot;f3 0f 5f/max *&quot;</span> reg2 <span class="Constant">&quot; &quot;</span> xreg <span class="Constant">&quot;/x32&quot;</span> Remember, when these instructions use indirect mode, they still use an integer register. Floating-point registers can't hold addresses. Most instructions operate exclusively on integer or floating-point operands. The only exceptions are the instructions for converting between integers and floating-point numbers. var/xreg <span class="Special">&lt;-</span> convert var2/reg2 =&gt; <span class="Constant">&quot;f3 0f 2a/convert-to-float %&quot;</span> reg2 <span class="Constant">&quot; &quot;</span> xreg <span class="Constant">&quot;/x32&quot;</span> var/xreg <span class="Special">&lt;-</span> convert var2 =&gt; <span class="Constant">&quot;f3 0f 2a/convert-to-float *(ebp+&quot;</span> var2.stack-offset <span class="Constant">&quot;) &quot;</span> xreg <span class="Constant">&quot;/x32&quot;</span> var/xreg <span class="Special">&lt;-</span> convert *var2/reg2 =&gt; <span class="Constant">&quot;f3 0f 2a/convert-to-float *&quot;</span> reg2 <span class="Constant">&quot; &quot;</span> xreg <span class="Constant">&quot;/x32&quot;</span> Converting floats to ints performs rounding by default. (We don't mess with the MXCSR control register.) var/reg <span class="Special">&lt;-</span> convert var2/xreg2 =&gt; <span class="Constant">&quot;f3 0f 2d/convert-to-int %&quot;</span> xreg2 <span class="Constant">&quot; &quot;</span> reg <span class="Constant">&quot;/r32&quot;</span> var/reg <span class="Special">&lt;-</span> convert var2 =&gt; <span class="Constant">&quot;f3 0f 2d/convert-to-int *(ebp+&quot;</span> var2.stack-offset <span class="Constant">&quot;) &quot;</span> reg <span class="Constant">&quot;/r32&quot;</span> var/reg <span class="Special">&lt;-</span> convert *var2/reg2 =&gt; <span class="Constant">&quot;f3 0f 2d/convert-to-int *&quot;</span> reg2 <span class="Constant">&quot; &quot;</span> reg <span class="Constant">&quot;/r32&quot;</span> There's a separate instruction for truncating the fractional part. var/reg <span class="Special">&lt;-</span> truncate var2/xreg2 =&gt; <span class="Constant">&quot;f3 0f 2c/truncate-to-int %&quot;</span> xreg2 <span class="Constant">&quot; &quot;</span> reg <span class="Constant">&quot;/r32&quot;</span> var/reg <span class="Special">&lt;-</span> truncate var2 =&gt; <span class="Constant">&quot;f3 0f 2c/truncate-to-int *(ebp+&quot;</span> var2.stack-offset <span class="Constant">&quot;) &quot;</span> reg <span class="Constant">&quot;/r32&quot;</span> var/reg <span class="Special">&lt;-</span> truncate *var2/reg2 =&gt; <span class="Constant">&quot;f3 0f 2c/truncate-to-int *&quot;</span> reg2 <span class="Constant">&quot; &quot;</span> reg <span class="Constant">&quot;/r32&quot;</span> There are no instructions accepting floating-point literals. To obtain integer literals in floating-point registers, copy them to general-purpose registers and then convert them to floating-point. 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 <span class="Special">&lt;-</span> copy var2/xreg2 =&gt; <span class="Constant">&quot;f3 0f 11/&lt;- %&quot;</span> xreg <span class="Constant">&quot; &quot;</span> xreg2 <span class="Constant">&quot;/x32&quot;</span> copy-to var1, var2/xreg =&gt; <span class="Constant">&quot;f3 0f 11/&lt;- *(ebp+&quot;</span> var1.stack-offset <span class="Constant">&quot;) &quot;</span> xreg <span class="Constant">&quot;/x32&quot;</span> var/xreg <span class="Special">&lt;-</span> copy var2 =&gt; <span class="Constant">&quot;f3 0f 10/-&gt; *(ebp+&quot;</span> var2.stack-offset <span class="Constant">&quot;) &quot;</span> xreg <span class="Constant">&quot;/x32&quot;</span> var/xreg <span class="Special">&lt;-</span> copy *var2/reg2 =&gt; <span class="Constant">&quot;f3 0f 10/-&gt; *&quot;</span> reg2 <span class="Constant">&quot; &quot;</span> xreg <span class="Constant">&quot;/x32&quot;</span> Comparisons must always start with a register: compare var1/xreg1, var2/xreg2 =&gt; <span class="Constant">&quot;0f 2f/compare %&quot;</span> xreg2 <span class="Constant">&quot; &quot;</span> xreg1 <span class="Constant">&quot;/x32&quot;</span> compare var1/xreg1, var2 =&gt; <span class="Constant">&quot;0f 2f/compare *(ebp+&quot;</span> var2.stack-offset <span class="Constant">&quot;) &quot;</span> xreg1 <span class="Constant">&quot;/x32&quot;</span> <span class="muComment">## Blocks</span> In themselves, blocks generate no instructions. However, if a block contains variable declarations, they must be cleaned up when the block ends. Clean up var on the stack =&gt; <span class="Constant">&quot;81 0/subop/add %esp &quot;</span> size-of(var) <span class="Constant">&quot;/imm32&quot;</span> Clean up var/reg =&gt; <span class="Constant">&quot;8f 0/subop/pop %&quot;</span> reg Clean up var/xreg =&gt; <span class="Constant">&quot;f3 0f 10/-&gt; *esp &quot;</span> xreg <span class="Constant">&quot;/x32&quot;</span> <span class="Constant">&quot;81 0/subop/add %esp 4/imm32&quot;</span> <span class="muComment">## Jumps</span> Besides having to clean up any variable declarations (see above) between themselves and their target, jumps translate like this: <span class="PreProc">break</span> =&gt; <span class="Constant">&quot;e9/jump break/disp32&quot;</span> <span class="PreProc">break</span> label =&gt; <span class="Constant">&quot;e9/jump &quot;</span> label <span class="Constant">&quot;:break/disp32&quot;</span> <span class="PreProc">loop</span> =&gt; <span class="Constant">&quot;e9/jump loop/disp32&quot;</span> <span class="PreProc">loop</span> label =&gt; <span class="Constant">&quot;e9/jump &quot;</span> label <span class="Constant">&quot;:loop/disp32&quot;</span> <span class="PreProc">break-if-=</span> =&gt; <span class="Constant">&quot;0f 84/jump-if-= break/disp32&quot;</span> <span class="PreProc">break-if-=</span> label =&gt; <span class="Constant">&quot;0f 84/jump-if-= &quot;</span> label <span class="Constant">&quot;:break/disp32&quot;</span> <span class="PreProc">loop-if-=</span> =&gt; <span class="Constant">&quot;0f 84/jump-if-= loop/disp32&quot;</span> <span class="PreProc">loop-if-=</span> label =&gt; <span class="Constant">&quot;0f 84/jump-if-= &quot;</span> label <span class="Constant">&quot;:loop/disp32&quot;</span> <span class="PreProc">break-if-!=</span> =&gt; <span class="Constant">&quot;0f 85/jump-if-!= break/disp32&quot;</span> <span class="PreProc">break-if-!=</span> label =&gt; <span class="Constant">&quot;0f 85/jump-if-!= &quot;</span> label <span class="Constant">&quot;:break/disp32&quot;</span> <span class="PreProc">loop-if-!=</span> =&gt; <span class="Constant">&quot;0f 85/jump-if-!= loop/disp32&quot;</span> <span class="PreProc">loop-if-!=</span> label =&gt; <span class="Constant">&quot;0f 85/jump-if-!= &quot;</span> label <span class="Constant">&quot;:loop/disp32&quot;</span> <span class="PreProc">break-if-&lt;</span> =&gt; <span class="Constant">&quot;0f 8c/jump-if-&lt; break/disp32&quot;</span> <span class="PreProc">break-if-&lt;</span> label =&gt; <span class="Constant">&quot;0f 8c/jump-if-&lt; &quot;</span> label <span class="Constant">&quot;:break/disp32&quot;</span> <span class="PreProc">loop-if-&lt;</span> =&gt; <span class="Constant">&quot;0f 8c/jump-if-&lt; loop/disp32&quot;</span> <span class="PreProc">loop-if-&lt;</span> label =&gt; <span class="Constant">&quot;0f 8c/jump-if-&lt; &quot;</span> label <span class="Constant">&quot;:loop/disp32&quot;</span> <span class="PreProc">break-if-&gt;</span> =&gt; <span class="Constant">&quot;0f 8f/jump-if-&gt; break/disp32&quot;</span> <span class="PreProc">break-if-&gt;</span> label =&gt; <span class="Constant">&quot;0f 8f/jump-if-&gt; &quot;</span> label <span class="Constant">&quot;:break/disp32&quot;</span> <span class="PreProc">loop-if-&gt;</span> =&gt; <span class="Constant">&quot;0f 8f/jump-if-&gt; loop/disp32&quot;</span> <span class="PreProc">loop-if-&gt;</span> label =&gt; <span class="Constant">&quot;0f 8f/jump-if-&gt; &quot;</span> label <span class="Constant">&quot;:loop/disp32&quot;</span> <span class="PreProc">break-if-&lt;=</span> =&gt; <span class="Constant">&quot;0f 8e/jump-if-&lt;= break/disp32&quot;</span> <span class="PreProc">break-if-&lt;=</span> label =&gt; <span class="Constant">&quot;0f 8e/jump-if-&lt;= &quot;</span> label <span class="Constant">&quot;:break/disp32&quot;</span> <span class="PreProc">loop-if-&lt;=</span> =&gt; <span class="Constant">&quot;0f 8e/jump-if-&lt;= loop/disp32&quot;</span> <span class="PreProc">loop-if-&lt;=</span> label =&gt; <span class="Constant">&quot;0f 8e/jump-if-&lt;= &quot;</span> label <span class="Constant">&quot;:loop/disp32&quot;</span> <span class="PreProc">break-if-&gt;=</span> =&gt; <span class="Constant">&quot;0f 8d/jump-if-&gt;= break/disp32&quot;</span> <span class="PreProc">break-if-&gt;=</span> label =&gt; <span class="Constant">&quot;0f 8d/jump-if-&gt;= &quot;</span> label <span class="Constant">&quot;:break/disp32&quot;</span> <span class="PreProc">loop-if-&gt;=</span> =&gt; <span class="Constant">&quot;0f 8d/jump-if-&gt;= loop/disp32&quot;</span> <span class="PreProc">loop-if-&gt;=</span> label =&gt; <span class="Constant">&quot;0f 8d/jump-if-&gt;= &quot;</span> label <span class="Constant">&quot;:loop/disp32&quot;</span> <span class="PreProc">break-if-addr&lt;</span> =&gt; <span class="Constant">&quot;0f 82/jump-if-addr&lt; break/disp32&quot;</span> <span class="PreProc">break-if-addr&lt;</span> label =&gt; <span class="Constant">&quot;0f 82/jump-if-addr&lt; &quot;</span> label <span class="Constant">&quot;:break/disp32&quot;</span> <span class="PreProc">loop-if-addr&lt;</span> =&gt; <span class="Constant">&quot;0f 82/jump-if-addr&lt; loop/disp32&quot;</span> <span class="PreProc">loop-if-addr&lt;</span> label =&gt; <span class="Constant">&quot;0f 82/jump-if-addr&lt; &quot;</span> label <span class="Constant">&quot;:loop/disp32&quot;</span> <span class="PreProc">break-if-addr&gt;</span> =&gt; <span class="Constant">&quot;0f 87/jump-if-addr&gt; break/disp32&quot;</span> <span class="PreProc">break-if-addr&gt;</span> label =&gt; <span class="Constant">&quot;0f 87/jump-if-addr&gt; &quot;</span> label <span class="Constant">&quot;:break/disp32&quot;</span> <span class="PreProc">loop-if-addr&gt;</span> =&gt; <span class="Constant">&quot;0f 87/jump-if-addr&gt; loop/disp32&quot;</span> <span class="PreProc">loop-if-addr&gt;</span> label =&gt; <span class="Constant">&quot;0f 87/jump-if-addr&gt; &quot;</span> label <span class="Constant">&quot;:loop/disp32&quot;</span> <span class="PreProc">break-if-addr&lt;=</span> =&gt; <span class="Constant">&quot;0f 86/jump-if-addr&lt;= break/disp32&quot;</span> <span class="PreProc">break-if-addr&lt;=</span> label =&gt; <span class="Constant">&quot;0f 86/jump-if-addr&lt;= &quot;</span> label <span class="Constant">&quot;:break/disp32&quot;</span> <span class="PreProc">loop-if-addr&lt;=</span> =&gt; <span class="Constant">&quot;0f 86/jump-if-addr&lt;= loop/disp32&quot;</span> <span class="PreProc">loop-if-addr&lt;=</span> label =&gt; <span class="Constant">&quot;0f 86/jump-if-addr&lt;= &quot;</span> label <span class="Constant">&quot;:loop/disp32&quot;</span> <span class="PreProc">break-if-addr&gt;=</span> =&gt; <span class="Constant">&quot;0f 83/jump-if-addr&gt;= break/disp32&quot;</span> <span class="PreProc">break-if-addr&gt;=</span> label =&gt; <span class="Constant">&quot;0f 83/jump-if-addr&gt;= &quot;</span> label <span class="Constant">&quot;:break/disp32&quot;</span> <span class="PreProc">loop-if-addr&gt;=</span> =&gt; <span class="Constant">&quot;0f 83/jump-if-addr&gt;= loop/disp32&quot;</span> <span class="PreProc">loop-if-addr&gt;=</span> label =&gt; <span class="Constant">&quot;0f 83/jump-if-addr&gt;= &quot;</span> label <span class="Constant">&quot;:loop/disp32&quot;</span> Similar float variants like `<span class="PreProc">break-if-float&lt;`</span> are aliases for the corresponding `addr` equivalents. The x86 instruction set stupidly has floating-point operations only update a subset of flags. Four sets of conditional jumps are useful for detecting overflow. <span class="PreProc">break-if-carry</span> =&gt; <span class="Constant">&quot;0f 82/jump-if-carry break/disp32&quot;</span> <span class="PreProc">break-if-carry</span> label =&gt; <span class="Constant">&quot;0f 82/jump-if-carry &quot;</span> label <span class="Constant">&quot;/disp32&quot;</span> <span class="PreProc">loop-if-carry</span> =&gt; <span class="Constant">&quot;0f 82/jump-if-carry break/disp32&quot;</span> <span class="PreProc">loop-if-carry</span> label =&gt; <span class="Constant">&quot;0f 82/jump-if-carry &quot;</span> label <span class="Constant">&quot;/disp32&quot;</span> <span class="PreProc">break-if-not-carry</span> =&gt; <span class="Constant">&quot;0f 83/jump-if-not-carry break/disp32&quot;</span> <span class="PreProc">break-if-not-carry</span> label =&gt; <span class="Constant">&quot;0f 83/jump-if-not-carry &quot;</span> label <span class="Constant">&quot;/disp32&quot;</span> <span class="PreProc">loop-if-not-carry</span> =&gt; <span class="Constant">&quot;0f 83/jump-if-not-carry break/disp32&quot;</span> <span class="PreProc">loop-if-not-carry</span> label =&gt; <span class="Constant">&quot;0f 83/jump-if-not-carry &quot;</span> label <span class="Constant">&quot;/disp32&quot;</span> <span class="PreProc">break-if-overflow</span> =&gt; <span class="Constant">&quot;0f 80/jump-if-overflow break/disp32&quot;</span> <span class="PreProc">break-if-overflow</span> label =&gt; <span class="Constant">&quot;0f 80/jump-if-overflow &quot;</span> label <span class="Constant">&quot;:break/disp32&quot;</span> <span class="PreProc">loop-if-overflow</span> =&gt; <span class="Constant">&quot;0f 80/jump-if-overflow loop/disp32&quot;</span> <span class="PreProc">loop-if-overflow</span> label =&gt; <span class="Constant">&quot;0f 80/jump-if-overflow &quot;</span> label <span class="Constant">&quot;:loop/disp32&quot;</span> <span class="PreProc">break-if-not-overflow</span> =&gt; <span class="Constant">&quot;0f 81/jump-if-not-overflow break/disp32&quot;</span> <span class="PreProc">break-if-not-overflow</span> label =&gt; <span class="Constant">&quot;0f 81/jump-if-not-overflow &quot;</span> label <span class="Constant">&quot;:break/disp32&quot;</span> <span class="PreProc">loop-if-not-overflow</span> =&gt; <span class="Constant">&quot;0f 81/jump-if-not-overflow loop/disp32&quot;</span> <span class="PreProc">loop-if-not-overflow</span> label =&gt; <span class="Constant">&quot;0f 81/jump-if-not-overflow &quot;</span> label <span class="Constant">&quot;:loop/disp32&quot;</span> All this relies on a convention that every `<span class="Delimiter">{}</span>` block is delimited by labels ending in `:<span class="PreProc">loop</span>` and `:<span class="PreProc">break</span>`. <span class="muComment">## Returns</span> The `<span class="PreProc">return</span>` instruction cleans up variable declarations just like an unconditional `<span class="PreProc">jump</span>` to end of function, but also emits a series of copies before the final `<span class="PreProc">jump</span>`, copying each argument of `<span class="PreProc">return</span>` to the register appropriate to the respective function output. This doesn't work if a function output register contains a later `<span class="PreProc">return</span>` argument (e.g. if the registers for two outputs are swapped in `<span class="PreProc">return</span>`), so you can't do that. <span class="PreProc">return</span> =&gt; <span class="Constant">&quot;c3/return&quot;</span> --- In the following instructions types are provided for clarity even if they must be provided in an earlier 'var' declaration. <span class="muComment"># Address operations</span> var/reg: (addr T) <span class="Special">&lt;-</span> address var2: T =&gt; <span class="Constant">&quot;8d/copy-address *(ebp+&quot;</span> var2.stack-offset <span class="Constant">&quot;) &quot;</span> reg <span class="Constant">&quot;/r32&quot;</span> <span class="muComment"># Array operations</span> var/reg: (addr T) <span class="Special">&lt;-</span> index arr/rega: (addr array T), idx/regi: int | if size-of(T) is <span class="Constant">1</span>, <span class="Constant">2</span>, <span class="Constant">4</span> or <span class="Constant">8</span> =&gt; <span class="Constant">&quot;81 7/subop/compare %&quot;</span> rega <span class="Constant">&quot; 0/imm32&quot;</span> <span class="Constant">&quot;0f 84/jump-if-= __mu-abort-null-index-base-address/disp32&quot;</span> <span class="Constant">&quot;(__check-mu-array-bounds *&quot;</span> rega <span class="Constant">&quot; %&quot;</span> regi <span class="Constant">&quot; &quot;</span> size-of(T) <span class="Constant">&quot;)&quot;</span> <span class="Constant">&quot;8d/copy-address *(&quot;</span> rega <span class="Constant">&quot;+&quot;</span> regi <span class="Constant">&quot;&lt;&lt;&quot;</span> log2(size-of(T)) <span class="Constant">&quot;+4) &quot;</span> reg <span class="Constant">&quot;/r32&quot;</span> var/reg: (addr T) <span class="Special">&lt;-</span> index arr: (array T len), idx/regi: int =&gt; <span class="Constant">&quot;(__check-mu-array-bounds *(ebp+&quot;</span> arr.stack-offset <span class="Constant">&quot;) %&quot;</span> regi <span class="Constant">&quot; &quot;</span> size-of(T) <span class="Constant">&quot;)&quot;</span> <span class="Constant">&quot;8d/copy-address *(ebp+&quot;</span> regi <span class="Constant">&quot;&lt;&lt;&quot;</span> log2(size-of(T)) <span class="Constant">&quot;+&quot;</span> (arr.stack-offset + <span class="Constant">4</span>) <span class="Constant">&quot;) &quot;</span> reg <span class="Constant">&quot;/r32&quot;</span> var/reg: (addr T) <span class="Special">&lt;-</span> index arr/rega: (addr array T), n =&gt; <span class="Constant">&quot;81 7/subop/compare %&quot;</span> rega <span class="Constant">&quot; 0/imm32&quot;</span> <span class="Constant">&quot;0f 84/jump-if-= __mu-abort-null-index-base-address/disp32&quot;</span> <span class="Constant">&quot;(__check-mu-array-bounds *&quot;</span> rega <span class="Constant">&quot; &quot;</span> n <span class="Constant">&quot; &quot;</span> size-of(T) <span class="Constant">&quot;)&quot;</span> <span class="Constant">&quot;8d/copy-address *(&quot;</span> rega <span class="Constant">&quot;+&quot;</span> (n*size-of(T)+<span class="Constant">4</span>) <span class="Constant">&quot;) &quot;</span> reg <span class="Constant">&quot;/r32&quot;</span> var/reg: (addr T) <span class="Special">&lt;-</span> index arr: (array T len), n =&gt; <span class="Constant">&quot;(__check-mu-array-bounds *(ebp+&quot;</span> arr.stack-offset <span class="Constant">&quot;) &quot;</span> n <span class="Constant">&quot; &quot;</span> size-of(T) <span class="Constant">&quot;)&quot;</span> <span class="Constant">&quot;8d/copy-address *(ebp+&quot;</span> (arr.stack-offset+<span class="Constant">4</span>+n*size-of(T)) <span class="Constant">&quot;) &quot;</span> reg <span class="Constant">&quot;/r32&quot;</span> var/reg: (offset T) <span class="Special">&lt;-</span> compute-offset arr: (addr array T), idx/regi: int <span class="muComment"># arr can be in reg or mem</span> =&gt; <span class="Constant">&quot;69/multiply %&quot;</span> regi <span class="Constant">&quot; &quot;</span> size-of(T) <span class="Constant">&quot;/imm32 &quot;</span> reg <span class="Constant">&quot;/r32&quot;</span> var/reg: (offset T) <span class="Special">&lt;-</span> compute-offset arr: (addr array T), idx: int <span class="muComment"># arr can be in reg or mem</span> =&gt; <span class="Constant">&quot;69/multiply *(ebp+&quot;</span> idx.stack-offset <span class="Constant">&quot;) &quot;</span> size-of(T) <span class="Constant">&quot;/imm32 &quot;</span> reg <span class="Constant">&quot;/r32&quot;</span> var/reg: (addr T) <span class="Special">&lt;-</span> index arr/rega: (addr array T), o/rego: (offset T) =&gt; <span class="Constant">&quot;81 7/subop/compare %&quot;</span> rega <span class="Constant">&quot; 0/imm32&quot;</span> <span class="Constant">&quot;0f 84/jump-if-= __mu-abort-null-index-base-address/disp32&quot;</span> <span class="Constant">&quot;(__check-mu-array-bounds %&quot;</span> rega <span class="Constant">&quot; %&quot;</span> rego <span class="Constant">&quot; 1 \&quot;&quot; function-name &quot;</span>\<span class="Constant">&quot;)&quot;</span> <span class="Constant">&quot;8d/copy-address *(&quot;</span> rega <span class="Constant">&quot;+&quot;</span> rego <span class="Constant">&quot;+4) &quot;</span> reg <span class="Constant">&quot;/r32&quot;</span> Computing the length of an array is complex. var/reg: int <span class="Special">&lt;-</span> length arr/reg2: (addr array T) | if T is byte (TODO) =&gt; <span class="Constant">&quot;8b/-&gt; *&quot;</span> reg2 <span class="Constant">&quot; &quot;</span> reg <span class="Constant">&quot;/r32&quot;</span> | if size-of(T) is <span class="Constant">4</span> or <span class="Constant">8</span> or <span class="Constant">16</span> or <span class="Constant">32</span> or <span class="Constant">64</span> or <span class="Constant">128</span> =&gt; <span class="Constant">&quot;8b/-&gt; *&quot;</span> reg2 <span class="Constant">&quot; &quot;</span> reg <span class="Constant">&quot;/r32&quot;</span> <span class="Constant">&quot;c1/shift 5/subop/logic-right %&quot;</span> reg <span class="Constant">&quot; &quot;</span> log2(size-of(T)) <span class="Constant">&quot;/imm8&quot;</span> | otherwise x86 has no instruction to divide by a literal, so we need up to <span class="Constant">3</span> extra registers! <span class="Constant">eax</span>/<span class="Constant">edx</span> for division and say <span class="Constant">ecx</span> =&gt; if reg is not <span class="Constant">eax</span> <span class="Constant">&quot;50/push-eax&quot;</span> if reg is not <span class="Constant">ecx</span> <span class="Constant">&quot;51/push-ecx&quot;</span> if reg is not <span class="Constant">edx</span> <span class="Constant">&quot;52/push-edx&quot;</span> <span class="Constant">&quot;8b/-&gt; *&quot;</span> reg2 <span class="Constant">&quot; eax/r32&quot;</span> <span class="Constant">&quot;31/xor %edx 2/r32/edx&quot;</span> <span class="muComment"># sign-extend, but array size can't be negative</span> <span class="Constant">&quot;b9/copy-to-ecx &quot;</span> size-of(T) <span class="Constant">&quot;/imm32&quot;</span> <span class="Constant">&quot;f7 7/subop/idiv-eax-edx-by %ecx&quot;</span> if reg is not <span class="Constant">eax</span> <span class="Constant">&quot;89/&lt;- %&quot;</span> reg <span class="Constant">&quot; 0/r32/eax&quot;</span> if reg is not <span class="Constant">edx</span> <span class="Constant">&quot;5a/pop-to-edx&quot;</span> if reg is not <span class="Constant">ecx</span> <span class="Constant">&quot;59/pop-to-ecx&quot;</span> if reg is not <span class="Constant">eax</span> <span class="Constant">&quot;58/pop-to-eax&quot;</span> <span class="muComment"># User-defined types</span> If a record (product) <span class="PreProc">type</span> 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 <span class="PreProc">type</span> T_f: var/reg: (addr T_f) <span class="Special">&lt;-</span> get var2/reg2: (addr T), f =&gt; <span class="Constant">&quot;81 7/subop/compare %&quot;</span> reg2 <span class="Constant">&quot; 0/imm32&quot;</span> <span class="Constant">&quot;0f 84/jump-if-= __mu-abort-null-get-base-address/disp32&quot;</span> <span class="Constant">&quot;8d/copy-address *(&quot;</span> reg2 <span class="Constant">&quot;+&quot;</span> offset(f) <span class="Constant">&quot;) &quot;</span> reg <span class="Constant">&quot;/r32&quot;</span> var/reg: (addr T_f) <span class="Special">&lt;-</span> get var2: T, f =&gt; <span class="Constant">&quot;8d/copy-address *(ebp+&quot;</span> var2.stack-offset <span class="Constant">&quot;+&quot;</span> offset(f) <span class="Constant">&quot;) &quot;</span> reg <span class="Constant">&quot;/r32&quot;</span> When the base is an address we perform a null check. <span class="muComment"># Allocating memory</span> allocate in: (addr handle T) =&gt; <span class="Constant">&quot;(allocate Heap &quot;</span> size-of(T) <span class="Constant">&quot; &quot;</span> in <span class="Constant">&quot;)&quot;</span> populate in: (addr handle array T), num <span class="muComment"># can be literal or variable on stack or register</span> =&gt; <span class="Constant">&quot;(allocate-array2 Heap &quot;</span> size-of(T) <span class="Constant">&quot; &quot;</span> num <span class="Constant">&quot; &quot;</span> in <span class="Constant">&quot;)&quot;</span> populate-stream in: (addr handle stream T), num <span class="muComment"># can be literal or variable on stack or register</span> =&gt; <span class="Constant">&quot;(new-stream Heap &quot;</span> size-of(T) <span class="Constant">&quot; &quot;</span> num <span class="Constant">&quot; &quot;</span> in <span class="Constant">&quot;)&quot;</span> <span class="muComment"># Some miscellaneous helpers to avoid error-prone size computations</span> clear x: (addr T) =&gt; <span class="Constant">&quot;(zero-out &quot;</span> s <span class="Constant">&quot; &quot;</span> size-of(T) <span class="Constant">&quot;)&quot;</span> read-from-stream s: (addr stream T), out: (addr T) =&gt; <span class="Constant">&quot;(read-from-stream &quot;</span> s <span class="Constant">&quot; &quot;</span> out <span class="Constant">&quot; &quot;</span> size-of(T) <span class="Constant">&quot;)&quot;</span> write-to-stream s: (addr stream T), in: (addr T) =&gt; <span class="Constant">&quot;(write-to-stream &quot;</span> s <span class="Constant">&quot; &quot;</span> in <span class="Constant">&quot; &quot;</span> size-of(T) <span class="Constant">&quot;)&quot;</span> vim&#0058;ft=mu:nowrap:textwidth=<span class="Constant">0</span> </pre> </body> </html> <!-- vim: set foldmethod=manual : -->