On this page:
5.10.1 Preface:   What’s wrong with Exprs-Lang v7
5.10.2 Exposing Heap Pointers in the Back-end
5.10.2.1 generate-x64
generate-x64
5.10.2.2 Em-Ops:   Abstracting Memory Operations
implement-mops
patch-instructions
5.10.2.3 Exposing mops up the pipeline
5.10.2.4 Implementing Allocation
expose-allocation-pointer
5.10.2.5 Abstracting Mops
select-instructions
normalize-bind
sequentialize-let
remove-complex-opera*
5.10.2.6 Implementing Structured Data
specify-representation
5.10.2.7 New Safe Primops
implement-safe-primops
5.10.2.8 uniquify
5.10.3 Appendix:   Overview
5.10.4 Appendix:   Languages
exprs-lang-v8?
exprs-lang-v8
exprs-unique-lang-v8?
exprs-unique-lang-v8
exprs-unsafe-data-lang-v8?
exprs-unsafe-data-lang-v8
exprs-bits-lang-v8/  contexts?
exprs-bits-lang-v8/  contexts
values-bits-lang-v8?
values-bits-lang-v8
proc-imp-mf-lang-v8?
proc-imp-mf-lang-v8
imp-mf-lang-v8?
imp-mf-lang-v8
imp-cmf-lang-v8?
imp-cmf-lang-v8
asm-alloc-lang-v8?
asm-alloc-lang-v8
asm-pred-lang-v8?
asm-pred-lang-v8
asm-pred-lang-v8/  locals?
asm-pred-lang-v8/  locals
asm-pred-lang-v8/  undead?
asm-pred-lang-v8/  undead
asm-pred-lang-v8/  conflicts?
asm-pred-lang-v8/  conflicts
asm-pred-lang-v8/  pre-framed?
asm-pred-lang-v8/  pre-framed
asm-pred-lang-v8/  framed?
asm-pred-lang-v8/  framed
asm-pred-lang-v8/  spilled?
asm-pred-lang-v8/  spilled
asm-pred-lang-v8/  assignments?
asm-pred-lang-v8/  assignments
nested-asm-lang-fvars-v8?
nested-asm-lang-fvars-v8
nested-asm-lang-v8?
nested-asm-lang-v8
block-pred-lang-v8?
block-pred-lang-v8
block-asm-lang-v8?
block-asm-lang-v8
para-asm-lang-v8?
para-asm-lang-v8
paren-x64-mops-v8?
paren-x64-mops-v8
paren-x64-v8?
paren-x64-v8

5.10 Data types: Structured Data and Heap Allocation

5.10.1 Preface: What’s wrong with Exprs-Lang v7

Exprs-lang v7 gained proper data types and algebraic expressions, which is a huge step forward in expressivity and high-level reasoning. However, it still does not allow us to express structured data. Real languages require structured data—such as strings, vectors, and linked lists—to express interesting programs over data larger than a single word. Functional languages use procedures, a data structure, to provide functions as first-class values.

To express data larger than a single word, we need support from the low-level languages to get access to locations larger than a single word in size. All our locations so far, registers and frame locations, are only a single word in size. We need access to heap pointers, memory locations whose size can be arbitrary.

Our strategy is to add three forms that specify-representation use to create new data structures for its surface language. These forms are:
  • (alloc e) allocates a number of bytes specified by e and returns a pointer to the base address of those bytes.

  • (mref e_base e_index) dereferences the pointer at e_base with the offset specified by e_index. Thinking in terms of pointer arithmetic, this dereferences (+ e_base e_index). The value of (+ e_base e_index) should always be word-aligned, i.e., a multiple of 8, and point to a an initialized heap allocated value.

  • (mset! e_base e_index e) stores the value of e in the address (+ e_base e_index), i.e., in the address given by pointer at e_base with the offset specified by e_index. The value of (+ e_base e_index) should always be word-aligned, i.e., a multiple of 8.

To implement these new memory operations, or mops (pronounced em ops), we need to expose additional features from x64.

5.10.2 Exposing Heap Pointers in the Back-end
5.10.2.1 generate-x64

We start by exposing a generalized addr form in Paren-x64 v8 below, which will allow us to access arbitrary memory locations.

  p ::= (begin s ...)
     
  s ::= (set! addr int32)
  | (set! addr trg)
  | (set! reg loc)
  | (set! reg triv)
  | (set! reg_1 (binop reg_1 int32))
  | (set! reg_1 (binop reg_1 loc))
  | (with-label label? s)
  | (jump trg)
  | (compare reg opand)
  | (jump-if relop label)
     
  trg ::= reg
  | label
     
  triv ::= trg
  | int64
     
  opand ::= int64
  | reg
     
  loc ::= reg
  | addr
     
  addr ::= (fbp - dispoffset)
  | (reg + int32)
  | (reg + reg)
  p ::= (begin s ...)
     
  s ::= (set! addr int32)
  | (set! addr trg)
  | (set! reg loc)
  | (set! reg triv)
  | (set! reg_1 (binop reg_1 int32))
  | (set! reg_1 (binop reg_1 loc))
  | (with-label label? s)
  | (jump trg)
  | (compare reg opand)
  | (jump-if relop label)
     
  trg ::= reg
  | label
     
  triv ::= trg
  | int64
     
  opand ::= int64
  | reg
     
  loc ::= reg
  | addr
     
  reg ::= rsp
  | rbp
  | rax
  | rbx
  | rcx
  | rdx
  | rsi
  | rdi
  | r8
  | r9
  | r10
  | r11
  | r12
  | r13
  | r14
  | r15
     
  addr ::= (fbp - dispoffset)
  | (reg + int32)
  | (reg + reg)
     
  fbp ::= frame-base-pointer-register?
     
  binop ::= *
  | +
  | -
  | bitwise-and
  | bitwise-ior
  | bitwise-xor
  | arithmetic-shift-right
     
  relop ::= <
  | <=
  | =
  | >=
  | >
  | !=
     
  int32 ::= int32?
     
  int64 ::= int64?
     
  label ::= label?
     
  dispoffset ::= dispoffset?

The language contains a new addr representing the x64 index-mode operand (reg + reg). This supports accessing a memory location by the index stored in another register. For example, in x64, we represent loading the nth element of an array into r10 using mov r10 [r11 + r12], where the base of the array is stored at r11 and the value of n is stored in r12.

The index-mode operand is not restricted to use a particular register, unlike the displacement-mode operand from Paren-x64 v7. We will use this feature to store pointers to structured data, and the register allocator will move those pointers into whichever registers it chooses.

We also allow a generalized form of displacement-mode operand. We can access the value pointed to by a base register reg at offset int32. by (reg + int32). This allows optimizing heap accesses when a constant offset is known, which is often the case for some data structures. The index is not restricted to be a multiple of 8, but it should be the case in our compiler that the value of the base plus the value of the offset is a multiple of 8.

All languages with direct access to registers, including Paren-x64 v8, are now parameterized by a new register, current-heap-base-pointer-register (abbreviated hbp). The run-time system initializes this register to point to the base of the heap. Allocation is implemented by copying the current value of this pointer, and incrementing it by the number of bytes we wish to allocate. The pointer must only be incremented by word-size multiples of bytes. Any other access to this register is now undefined behavior, similar to accesses to fbp that do not obey the stack of frames discipline.

Design digression:
A real language implementation might abstract access to the mmap system call for allocation, and implement a strategy (such as garbage collection) to deallocate memory that is no longer used. Garbage collection is tricky to implement and requires too much time for this course, so we use a different strategy. Our implementation of allocation is trivial, and does not support de-allocation. We rely on the operating system to clean up memory after our process exits.

For a quick introduction to garbage collection, see this short video https://twitter.com/TartanLlama/status/1296413612907663361?s=20.

procedure

(generate-x64 s)  string?

  s : paren-x64-v8
Compile the Paren-x64 v8 program into a valid sequence of x64 instructions, represented as a string.

5.10.2.2 Em-Ops: Abstracting Memory Operations

Like when we implemented fvars to support working with frame locations, we implement primitive memory operations, mops , to simplify working with heap addresses. We should do this before patch-instructions to avoid complicating the already complex logic for rewriting set! instructions.

Below, we define Paren-x64-mops v8, with differences compared to Paren-x64-v8.

  p ::= (begin s ...)
     
  s ::= (set! addr int32)
  | (set! addr trg)
  | (set! reg loc)
  | (set! reg triv)
  | (set! reg_1 (binop reg_1 int32))
  | (set! reg_1 (binop reg_1 loc))
  | (set! reg_1 (mref reg_2 index))
  | (mset! reg_1 index triv)
  | (with-label label label? s)
  | (jump trg)
  | (compare reg opand)
  | (jump-if relop label)
     
  addr ::= (fbp - dispoffset)
  p ::= (begin s ...)
     
  s ::= (set! addr int32)
  | (set! addr trg)
  | (set! reg loc)
  | (set! reg triv)
  | (set! reg_1 (binop reg_1 int32))
  | (set! reg_1 (binop reg_1 loc))
  | (set! reg_1 (mref reg_2 index))
  | (mset! reg_1 index triv)
  | (with-label label s)
  | (jump trg)
  | (compare reg opand)
  | (jump-if relop label)
     
  trg ::= reg
  | label
     
  triv ::= trg
  | int64
     
  opand ::= int64
  | reg
     
  loc ::= reg
  | addr
     
  index ::= int32
  | reg
     
  reg ::= rsp
  | rbp
  | rax
  | rbx
  | rcx
  | rdx
  | rsi
  | rdi
  | r8
  | r9
  | r10
  | r11
  | r12
  | r13
  | r14
  | r15
     
  addr ::= (fbp - dispoffset)
     
  fbp ::= frame-base-pointer-register?
     
  binop ::= *
  | +
  | -
  | bitwise-and
  | bitwise-ior
  | bitwise-xor
  | arithmetic-shift-right
     
  relop ::= <
  | <=
  | =
  | >=
  | >
  | !=
     
  int64 ::= int64?
     
  int32 ::= int32?
     
  label ::= label?
     
  dispoffset ::= dispoffset?

We add two new instructions that directly map to operations on heap addresses, either as index- or displacement-mode operands.

We could encode the restricted form of addr, used for frame variables, as an mref, but the rest of our compiler already knows about addrs, and it represents a semantically different concept, so we leave it alone.

procedure

(implement-mops p)  paren-x64-v8?

  p : paren-x64-mops-v8?
Compiles mops to instructions on pointers with index- and displacement-mode operands.

Next we design Para-asm-lang v8. Below, we give a definition.

  p ::= (begin s ...)
     
  s ::= (set! loc triv)
  | (set! loc_1 (binop loc_1 opand))
  | (set! loc_1 (mref loc_2 index))
  | (mset! loc_1 index triv)
  | (with-label label s)
  | (jump trg)
  | (compare loc opand)
  | (jump-if relop trg)
     
  triv ::= opand
  | label
     
  loc ::= reg
  | addr
     
  index ::= int64
  | loc
     
  addr ::= (fbp - dispoffset)
     
  fbp ::= frame-base-pointer-register?
     
  int32 ::= int32?
     
  dispoffset ::= dispoffset?
  p ::= (begin s ...)
     
  s ::= (set! addr int32)
  | (set! addr trg)
  | (set! reg loc triv)
  | (set! reg triv)
  | (set! loc_1 reg_1 (binop loc_1 opand reg_1 int32))
  | (set! reg_1 (binop reg_1 loc))
  | (set! loc_1 reg_1 (mref loc_2 reg_2 index))
  | (mset! loc_1 reg_1 index triv)
  | (with-label label s)
  | (jump trg)
  | (compare loc reg opand)
  | (jump-if relop trg label)
     
  trg ::= reg
  | label
  | loc
     
  triv ::= opand
  | label
  | trg
  | int64
     
  opand ::= int64
  | loc
  | reg
     
  loc ::= reg
  | addr
     
  index ::= int64
  | loc
  | int32
  | reg
     
  reg ::= rsp
  | rbp
  | rax
  | rbx
  | rcx
  | rdx
  | rsi
  | rdi
  | r8
  | r9
  | r10
  | r11
  | r12
  | r13
  | r14
  | r15
     
  addr ::= (fbp - dispoffset)
     
  fbp ::= frame-base-pointer-register?
     
  binop ::= *
  | +
  | -
  | bitwise-and
  | bitwise-ior
  | bitwise-xor
  | arithmetic-shift-right
     
  relop ::= <
  | <=
  | =
  | >=
  | >
  | !=
     
  int64 ::= int64?
     
  int32 ::= int32?
     
  label ::= label?
     
  dispoffset ::= dispoffset?
  p ::= (begin s ...)
     
  s ::= (set! loc triv)
  | (set! loc_1 (binop loc_1 opand))
  | (set! loc_1 (mref loc_2 index))
  | (mset! loc_1 index triv)
  | (with-label label s)
  | (jump trg)
  | (compare loc opand)
  | (jump-if relop trg)
     
  trg ::= label
  | loc
     
  triv ::= opand
  | label
     
  opand ::= int64
  | loc
     
  loc ::= reg
  | addr
     
  index ::= int64
  | loc
     
  reg ::= rsp
  | rbp
  | rax
  | rbx
  | rcx
  | rdx
  | rsi
  | rdi
  | r8
  | r9
  | r12
  | r13
  | r14
  | r15
     
  addr ::= (fbp - dispoffset)
     
  fbp ::= frame-base-pointer-register?
     
  binop ::= *
  | +
  | -
  | bitwise-and
  | bitwise-ior
  | bitwise-xor
  | arithmetic-shift-right
     
  relop ::= <
  | <=
  | =
  | >=
  | >
  | !=
     
  int64 ::= int64?
     
  int32 ::= int32?
     
  label ::= label?
     
  dispoffset ::= dispoffset?

By introducing mops, we implicitly restrict how heap addresses appear in the language and simplify the job of patch-instructions. The mops implicitly restrict heap addresses to being part of a move instruction, so we do not have to patch binary operation instructions despite apparently adding a new form of physical location. By making them separate forms, we only need to patch the new instructions, and leave old code untouched.

In patch-instructions, we also lift the restriction on index, so int64s can appear as an index. This makes index and opand coincide, syntactically, but they are conceptually different so we maintain separate non-terminal definitions.

Patches instructions that have no x64 analogue into to a sequence of instructions and an auxiliary register from current-patch-instructions-registers.

5.10.2.3 Exposing mops up the pipeline

The new mops require minor changes to most of the pipeline up to Asm-alloc-lang v8, where we will use them to implement data structures.

Exercise 9: Redesign and extend the implementation of
  • flatten-program, should require no changes

  • resolve-predicates, should require no changes

  • expose-basic-blocks, should require no changes

  • implement-fvars, should require minor changes to support mops. Note that we assume the fbp is not modified by mops.

  • optimize-predicates, could require minor changes.

  • replace-locations, should require minor changes to support mops.

  • assign-frame-variables, should require no changes.

  • assign-registers, should require no changes.

  • allocate-frames, should require no changes.

  • assign-call-undead-variables, should require no changes.

  • conflict-analysis, should require minor changes. Note that mops do not assign any registers or frame variables.

  • undead-analysis, should require minor changes. Note that mops do not assign any registers or frame variables.

  • uncover-locals, should require minor changes.

5.10.2.4 Implementing Allocation

Before we introduce structured data, we implement the alloc instruction to allow programs to allocate a bunch of bytes and not worry about the details of the allocation pointer. We want to do this after the passes that analyze physical locations, since then we do not have to update those passes to know that alloc introduces a reference to a register. However, we want to do this before we abstract away from all machine details so we do not need to expose registers beyond Asm-alloc-lang v8.

We choose to insert this pass between uncover-locals and select-instructions.

Below, we design Asm-alloc-lang v8, the source language for this pass. We typeset the differences compared to Asm-pred-lang v7.

  p ::= (module info (define label info tail) ... tail)
     
  info ::= (#:from-contract (info/c (new-frames (frame ...))))
     
  frame ::= (aloc ...)
     
  pred ::= (relop loc opand)
  | (true)
  | (false)
  | (not pred)
  | (begin effect ... pred)
  | (if pred pred pred)
     
  tail ::= (jump trg loc ...)
  | (begin effect ... tail)
  | (if pred tail tail)
     
  effect ::= (set! loc triv)
  | (set! loc_1 (binop loc_1 opand))
  | (set! loc_1 (mref loc_2 index))
  | (set! loc (alloc index))
  | (mset! loc index triv)
  | (begin effect ... effect)
  | (if pred effect effect)
  | (return-point label tail)
     
  index ::= int64
  | loc
     
  int32 ::= int32?
  p ::= (module info (define label info tail) ... tail)
     
  info ::= (#:from-contract (info/c (new-frames (frame ...))))
     
  frame ::= (aloc ...)
     
  pred ::= (relop loc opand)
  | (true)
  | (false)
  | (not pred)
  | (begin effect ... pred)
  | (if pred pred pred)
     
  tail ::= (jump trg loc ...)
  | (begin effect ... tail)
  | (if pred tail tail)
     
  effect ::= (set! loc triv)
  | (set! loc_1 (binop loc_1 opand))
  | (set! loc_1 (mref loc_2 index))
  | (set! loc (alloc index))
  | (mset! loc index triv)
  | (begin effect ... effect)
  | (if pred effect effect)
  | (return-point label tail)
     
  opand ::= int64
  | loc
     
  triv ::= opand
  | label
     
  loc ::= rloc
  | aloc
     
  trg ::= label
  | loc
     
  index ::= int64
  | loc
     
  binop ::= *
  | +
  | -
  | bitwise-and
  | bitwise-ior
  | bitwise-xor
  | arithmetic-shift-right
     
  relop ::= <
  | <=
  | =
  | >=
  | >
  | !=
     
  int64 ::= int64?
     
  int32 ::= int32?
     
  aloc ::= aloc?
     
  label ::= label?
     
  rloc ::= register?
  | fvar?

We expose the earlier mops, and add a new one, (set! loc (alloc index)). This is the low-level form of our allocation operation, which we will abstract into an expression in Exprs-lang v8. In (set! loc (alloc index)), the index is restricted to be an int32 if it is an integer literal, for the same reasons as the restriction on binops. It must also be a multiple of a word size. This requirement is partly from the operating system’s mmap (which will usually ignore us if we violate the restriction and give us page-aligned memory anyway), but mostly to ensure every pointer we get has #b000 as its final three bits so we can tag all pointers.

We design the target language, Asm-pred-lang v8, below. This language removes the (alloc index) form and is the highest-level language parameterized by current-heap-base-pointer-register. This language, and all languages between it and x64, assumes all accesses to hbp obey the restrictions described in Paren-x64 v8.

  p ::= (module info (define label info tail) ... tail)
     
  info ::= (#:from-contract (info/c (new-frames (frame ...))))
     
  frame ::= (aloc ...)
     
  pred ::= (relop loc opand)
  | (true)
  | (false)
  | (not pred)
  | (begin effect ... pred)
  | (if pred pred pred)
     
  tail ::= (jump trg loc ...)
  | (begin effect ... tail)
  | (if pred tail tail)
     
  effect ::= (set! loc triv)
  | (set! loc_1 (binop loc_1 opand))
  | (set! loc_1 (mref loc_2 index))
  | (set! loc (alloc index))
  | (mset! loc index triv)
  | (begin effect ... effect)
  | (if pred effect effect)
  | (return-point label tail)
     
  index ::= int64
  | loc
  p ::= (module info (define label info tail) ... tail)
     
  info ::= (#:from-contract (info/c (new-frames (frame ...))))
     
  frame ::= (aloc ...)
     
  pred ::= (relop loc opand)
  | (true)
  | (false)
  | (not pred)
  | (begin effect ... pred)
  | (if pred pred pred)
     
  tail ::= (jump trg loc ...)
  | (begin effect ... tail)
  | (if pred tail tail)
     
  effect ::= (set! loc triv)
  | (set! loc_1 (binop loc_1 opand))
  | (set! loc_1 (mref loc_2 index))
  | (mset! loc index triv)
  | (begin effect ... effect)
  | (if pred effect effect)
  | (return-point label tail)
     
  index ::= int64
  | loc
     
  int32 ::= int32?
  p ::= (module info (define label info tail) ... tail)
     
  info ::= (#:from-contract (info/c (new-frames (frame ...))))
     
  frame ::= (aloc ...)
     
  pred ::= (relop loc opand)
  | (true)
  | (false)
  | (not pred)
  | (begin effect ... pred)
  | (if pred pred pred)
     
  tail ::= (jump trg loc ...)
  | (begin effect ... tail)
  | (if pred tail tail)
     
  effect ::= (set! loc triv)
  | (set! loc_1 (binop loc_1 opand))
  | (set! loc_1 (mref loc_2 index))
  | (mset! loc index triv)
  | (begin effect ... effect)
  | (if pred effect effect)
  | (return-point label tail)
     
  opand ::= int64
  | loc
     
  triv ::= opand
  | label
     
  loc ::= rloc
  | aloc
     
  trg ::= label
  | loc
     
  index ::= int64
  | loc
     
  binop ::= *
  | +
  | -
  | bitwise-and
  | bitwise-ior
  | bitwise-xor
  | arithmetic-shift-right
     
  relop ::= <
  | <=
  | =
  | >=
  | >
  | !=
     
  int64 ::= int64?
     
  int32 ::= int32?
     
  aloc ::= aloc?
     
  label ::= label?
     
  rloc ::= register?
  | fvar?

Intuitively, we will transform each `(set! ,loc (alloc ,index)) into
`(begin
   (set! ,loc ,hbp)
   (set! ,hbp (+ ,hbp ,index)))

Implements the allocation primitive in terms of pointer arithmetic on the current-heap-base-pointer-register.

5.10.2.5 Abstracting Mops

Before we implement structured data, we expose our mops through a few layers of abstractions. Below we design Imp-cmf-lang v8 with support for mops. We typeset the differences compared to Imp-cmf-lang v7.

  p ::= (module info (define label info tail) ... tail)
     
  pred ::= (relop opand opand)
  | (true)
  | (false)
  | (not pred)
  | (begin effect ... pred)
  | (if pred pred pred)
     
  tail ::= (jump trg loc ...)
  | (begin effect ... tail)
  | (if pred tail tail)
     
  value ::= triv
  | (binop opand opand)
  | (mref loc opand)
  | (alloc opand)
     
  effect ::= (set! loc value)
  | (mset! loc opand triv)
  | (begin effect ... effect)
  | (if pred effect effect)
  | (return-point label tail)
  p ::= (module info (define label info tail) ... tail)
     
  pred ::= (relop loc opand opand)
  | (true)
  | (false)
  | (not pred)
  | (begin effect ... pred)
  | (if pred pred pred)
     
  tail ::= (jump trg loc ...)
  | (begin effect ... tail)
  | (if pred tail tail)
     
  value ::= triv
  | (binop opand opand)
  | (mref loc opand)
  | (alloc opand)
     
  effect ::= (set! loc triv)
  | (set! loc_1 (binop loc_1 opand))
  | (set! loc_1 (mref loc_2 index))
  | (set! loc (alloc index) value)
  | (mset! loc index opand triv)
  | (begin effect ... effect)
  | (if pred effect effect)
  | (return-point label tail)
     
  index ::= int64
  | loc
     
  int32 ::= int32?
  p ::= (module info (define label info tail) ... tail)
     
  info ::= (#:from-contract (info/c (new-frames (frame ...))))
     
  frame ::= (aloc ...)
     
  pred ::= (relop opand opand)
  | (true)
  | (false)
  | (not pred)
  | (begin effect ... pred)
  | (if pred pred pred)
     
  tail ::= (jump trg loc ...)
  | (begin effect ... tail)
  | (if pred tail tail)
     
  value ::= triv
  | (binop opand opand)
  | (mref loc opand)
  | (alloc opand)
     
  effect ::= (set! loc value)
  | (mset! loc opand triv)
  | (begin effect ... effect)
  | (if pred effect effect)
  | (return-point label tail)
     
  opand ::= int64
  | loc
     
  triv ::= opand
  | label
     
  loc ::= rloc
  | aloc
     
  trg ::= label
  | loc
     
  binop ::= *
  | +
  | -
  | bitwise-and
  | bitwise-ior
  | bitwise-xor
  | arithmetic-shift-right
     
  relop ::= <
  | <=
  | =
  | >=
  | >
  | !=
     
  int64 ::= int64?
     
  aloc ::= aloc?
     
  label ::= label?
     
  rloc ::= register?
  | fvar?

We add value forms of mref and alloc. We require these forms are used in a well-typed way. This is a simple extension.

Selects appropriate sequences of abstract assembly instructions to implement the operations of the source language.

Next we design Imp-mf-lang v8 with support for mops.

  p ::= (module info (define label info tail) ... tail)
     
  info ::= (#:from-contract (info/c (new-frames (frame ...))))
     
  frame ::= (aloc ...)
     
  pred ::= (relop opand opand)
  | (true)
  | (false)
  | (not pred)
  | (begin effect ... pred)
  | (if pred pred pred)
     
  tail ::= (jump trg loc ...)
  | (begin effect ... tail)
  | (if pred tail tail)
     
  value ::= triv
  | (binop opand opand)
  | (mref loc opand)
  | (alloc opand)
  | (begin effect ... value)
  | (if pred value value)
  | (return-point label tail)
     
  effect ::= (set! loc value)
  | (mset! loc opand value)
  | (begin effect ... effect)
  | (if pred effect effect)
  p ::= (module info (define label info tail) ... tail)
     
  info ::= (#:from-contract (info/c (new-frames (frame ...))))
     
  frame ::= (aloc ...)
     
  pred ::= (relop opand opand)
  | (true)
  | (false)
  | (not pred)
  | (begin effect ... pred)
  | (if pred pred pred)
     
  tail ::= (jump trg loc ...)
  | (begin effect ... tail)
  | (if pred tail tail)
     
  value ::= triv
  | (binop opand opand)
  | (mref loc opand)
  | (alloc opand)
  | (begin effect ... value)
  | (if pred value value)
  | (return-point label tail)
     
  effect ::= (set! loc value)
  | (mset! loc opand value)
  | (begin effect ... effect)
  | (if pred effect effect)
     
  opand ::= int64
  | loc
     
  triv ::= opand
  | label
     
  loc ::= rloc
  | aloc
     
  trg ::= label
  | loc
     
  binop ::= *
  | +
  | -
  | bitwise-and
  | bitwise-ior
  | bitwise-xor
  | arithmetic-shift-right
     
  relop ::= <
  | <=
  | =
  | >=
  | >
  | !=
     
  int64 ::= int64?
     
  aloc ::= aloc?
     
  label ::= label?
     
  rloc ::= register?
  | fvar?

We introduce the value context, but notice that the index position for an mset! instruction is still restricted.

Question: Why can’t (or shouldn’t) we allow the index position to also be a value?

procedure

(normalize-bind p)  imp-cmf-lang-v8?

  p : imp-mf-lang-v8?
Pushes set! and mset! under begin and if so that the right-hand-side of each is simple value-producing operand.

This normalizes Imp-mf-lang v8 with respect to the equations

(set! loc (begin effect_1 ... value))

=

(begin effect_1 ... (set! loc value))

(set! loc (if pred value_1 value_2))

=

(if pred (set! loc value_1) (set! loc value_2))

(mset! loc opand (begin effect_1 ... value))

=

(begin effect_1 ... (mset! loc opand value))

(mset! loc opand (if pred value_1 value_2))

=

(if pred (mset! loc opand value_1) (mset! loc opand value_2))

The impose-calling-conventions pass requires only minor changes.

For sequentialize-let, we need to design an effect context in order to expose mset!. We design Values-bits-lang v8 to include a few imperative features.

  p ::= (module (define label (lambda (aloc ...) tail)) ... tail)
     
  pred ::= (relop opand opand)
  | (true)
  | (false)
  | (not pred)
  | (let ([aloc value] ...) pred)
  | (if pred pred pred)
  | (begin effect ... pred)
     
  tail ::= value
  | (let ([aloc value] ...) tail)
  | (if pred tail tail)
  | (call triv opand ...)
  | (begin effect ... tail)
     
  value ::= triv
  | (binop opand opand)
  | (mref aloc opand)
  | (alloc opand)
  | (let ([aloc value] ...) value)
  | (if pred value value)
  | (call triv opand ...)
  | (begin effect ... value)
     
  effect ::= (mset! aloc opand value)
  | (let ([aloc value] ...) effect)
  | (begin effect ... effect)
  p ::= (module (define label (lambda (aloc ...) entry tail)) ... entry tail)
     
  entry ::= tail
     
  pred ::= (relop opand opand)
  | (true)
  | (false)
  | (not pred)
  | (begin effect ... pred)
  | (let ([aloc value] ...) pred)
  | (if pred pred pred)
  | (begin effect ... pred)
     
  tail ::= value
  | (let ([aloc value] ...) tail)
  | (if pred tail tail)
  | (call triv opand ...)
  | (begin effect ... tail)
  | (if pred tail tail)
     
  value ::= triv
  | (binop opand opand)
  | (mref aloc opand)
  | (alloc opand)
  | (begin effect ... value)
  | (let ([aloc value] ...) value)
  | (if pred value value)
  | (call triv opand ...)
  | (begin effect ... value)
     
  effect ::= (set! aloc value)
  | (mset! aloc opand value)
  | (let ([aloc value] ...) effect)
  | (begin effect ... effect)
  | (if pred effect effect)
  p ::= (module (define label (lambda (aloc ...) tail)) ... tail)
     
  pred ::= (relop opand opand)
  | (true)
  | (false)
  | (not pred)
  | (let ([aloc value] ...) pred)
  | (if pred pred pred)
  | (begin effect ... pred)
     
  tail ::= value
  | (let ([aloc value] ...) tail)
  | (if pred tail tail)
  | (call triv opand ...)
  | (begin effect ... tail)
     
  value ::= triv
  | (binop opand opand)
  | (mref aloc opand)
  | (alloc opand)
  | (let ([aloc value] ...) value)
  | (if pred value value)
  | (call triv opand ...)
  | (begin effect ... value)
     
  effect ::= (mset! aloc opand value)
  | (let ([aloc value] ...) effect)
  | (begin effect ... effect)
     
  opand ::= int64
  | aloc
     
  triv ::= opand
  | label
     
  binop ::= *
  | +
  | -
  | bitwise-and
  | bitwise-ior
  | bitwise-xor
  | arithmetic-shift-right
     
  relop ::= <
  | <=
  | =
  | >=
  | >
  | !=
     
  int64 ::= int64?
     
  aloc ::= aloc?
     
  label ::= label?

We add an effect context to support mset!, and a begin expression for convenience. Previously, all expressions in the Values-lang languages were purethey evaluated and produced the same value regardless of in which order expressions were evaluated. We could freely reorder expressions, as long as we respected scope. Now, however, mset! modifies memory during its execution. It not safe to reorder expressions after an mset!. Furthermore, mset! does not return a useful value.

To deal with this, we introduce a contextual distinction in the language. We add the nonterminal effect to represent an impure computation. A effect represents an expression that does not have a value, and is executed only for its effect. We can use effect in certain expression contexts using begin. If we’re already in an impure context, that is, in a effect, then we can freely nest other effects.

This contextual distinction is similar to the one we introduce to distinguish tail calls from non-tail calls.

Despite the conceptually complex change to the language, the transformation is still straightforward.

Design digression:
Now that effects can appear on the right-hand side of a let expression, it MAY not longer be safe to reorder them. This is a design choice: we could make it clear to the programmer that let does not guarantee a particular order of evaluation for its bindings, but then effects on the right-hand side lead to undefined behaviour. Or, we could impose a particular order, such as left-to-right, forbidding an optimization. A middle ground is to impose such an order only if any effects are detected in the right-hand side of a let (or rather, if we can guarantee no effects are present, because Rice still does not let us know for sure).

Picks a particular order to implement let expressions using set!.

Finally, we enable arbitrary nesting in value position. We design Exprs-bits-lang v8/contexts below.

  p ::= (module b ... tail)
     
  b ::= (define label (lambda (aloc ...) tail))
     
  pred ::= (relop value value)
  | (true)
  | (false)
  | (not pred)
  | (let ([aloc value] ...) pred)
  | (if pred pred pred)
  | (begin effect ... pred)
     
  tail ::= value
  | (let ([aloc value] ...) tail)
  | (if pred tail tail)
  | (begin effect ... tail)
     
  value ::= triv
  | (binop value value)
  | (mref value value)
  | (alloc value)
  | (call value value ...)
  | (let ([aloc value] ...) value)
  | (if pred value value)
  | (begin effect ... value)
     
  effect ::= (mset! value value value)
  | (begin effect ... effect)
  p ::= (module b ... tail)
     
  b ::= (define label (lambda (aloc ...) tail))
     
  pred ::= (relop value value)
  | (true)
  | (false)
  | (not pred)
  | (let ([aloc value] ...) pred)
  | (if pred pred pred)
  | (begin effect ... pred)
     
  tail ::= value
  | (let ([aloc value] ...) tail)
  | (if pred tail tail)
  | (begin effect ... tail)
     
  value ::= triv
  | (binop value value)
  | (mref value value)
  | (alloc value)
  | (call value value ...)
  | (let ([aloc value]) value)
  | (if pred value value)
  | (begin effect ... value)
     
  effect ::= (mset! value value value)
  | (begin effect ... effect)
     
  triv ::= label
  | aloc
  | int64
     
  binop ::= *
  | +
  | -
  | bitwise-and
  | bitwise-ior
  | bitwise-xor
  | arithmetic-shift-right
     
  aloc ::= aloc?
     
  label ::= label?
     
  relop ::= <
  | <=
  | =
  | >=
  | >
  | !=
     
  int64 ::= int64?

Supporting effect context requires paying attention to order when designing remove-complex-opera*, but does not significantly complicate anything.

Performs the monadic form transformation, unnesting all non-trivial operators and operands, making data flow explicit and and simple to implement imperatively.

5.10.2.6 Implementing Structured Data

Now we have all the abstractions necessary to implement structured data.

We design a new Exprs-unsafe-data-lang v8 below. The language is large, as we include several new structured data types and their primitives.

  p ::= (module b ... e)
     
  b ::= (define label (lambda (aloc ...) e))
     
  pred ::= e
  | (true)
  | (false)
  | (not pred)
  | (let ([aloc e] ...) pred)
  | (if pred pred pred)
     
  e ::= v
  | (primop e ...)
  | (call e e ...)
  | (let ([aloc e] ...) e)
  | (if pred e e)
  | (begin effect ... e)
     
  effect ::= (primop e ...)
  | (begin effect ... effect)
     
  primop ::= unsafe-fx*
  | unsafe-fx+
  | unsafe-fx-
  | eq?
  | unsafe-fx<
  | unsafe-fx<=
  | unsafe-fx>
  | unsafe-fx>=
  | fixnum?
  | boolean?
  | empty?
  | void?
  | ascii-char?
  | error?
  | not
  | pair?
  | vector?
  | cons
  | unsafe-car
  | unsafe-cdr
  | unsafe-make-vector
  | unsafe-vector-length
  | unsafe-vector-set!
  | unsafe-vector-ref
     
  primop ::= binop
  | unop
     
  binop ::= unsafe-fx*
  | unsafe-fx+
  | unsafe-fx-
  | eq?
  | unsafe-fx<
  | unsafe-fx<=
  | unsafe-fx>
  | unsafe-fx>=
     
  unop ::= fixnum?
  | boolean?
  | empty?
  | void?
  | ascii-char?
  | error?
  | not
  p ::= (module b ... e)
     
  b ::= (define label (lambda (aloc ...) e))
     
  pred ::= e
  | (true)
  | (false)
  | (not pred)
  | (let ([aloc e] ...) pred)
  | (if pred pred pred)
     
  e ::= v
  | (primop e ...)
  | (call e e ...)
  | (let ([aloc e] ...) e)
  | (if pred e e)
  | (begin effect ... e)
     
  effect ::= (primop e ...)
  | (begin effect ... effect)
     
  v ::= label
  | aloc
  | fixnum
  | #t
  | #f
  | empty
  | (void)
  | (error uint8)
  | ascii-char-literal
     
  primop ::= unsafe-fx*
  | unsafe-fx+
  | unsafe-fx-
  | eq?
  | unsafe-fx<
  | unsafe-fx<=
  | unsafe-fx>
  | unsafe-fx>=
  | fixnum?
  | boolean?
  | empty?
  | void?
  | ascii-char?
  | error?
  | not
  | pair?
  | vector?
  | cons
  | unsafe-car
  | unsafe-cdr
  | unsafe-make-vector
  | unsafe-vector-length
  | unsafe-vector-set!
  | unsafe-vector-ref
     
  aloc ::= aloc?
     
  label ::= label?
     
  fixnum ::= int61?
     
  uint8 ::= uint8?
     
  ascii-char-literal ::= ascii-char-literal?

We add new primops for each of our new data types. Since the number of primitive operations is growing, we simplify the syntax to only give primops, rather than distinguishing unops, binops, and so on, so we can easily group like primops with like.

We also add impure computations, since vectors are a mutable data structure. Only effectful primops, those ending with !, are allowed in effect context.

We add two heap-allocated data types, described below:
  • Pairs are constructed using (cons e_1 e_2). The predicate pair? should return #t when passed any value constructed this way, and #f for any other value—(eq? (pair? (cons e_1 e_2)) #t). (unsafe-car e) returns the value of the first element of the pair, and (unsafe-cdr e) returns the value of the second element. That is, (eq? (unsafe-car (cons e_1 e_2)) e_1) and (eq? (unsafe-cdr (cons e_1 e_2)) e_2).

  • Vectors are essentially arrays that know their length. They are constructed using (unsafe-make-vector e); the constructor takes the length of the vector as the argument. The predicate vector? should return #t for any value constructed this way, and #f for any other value—(eq? (vector? (unsafe-make-vector e)) #t). (unsafe-vector-ref e_1 e_2) returns the value at index e_2 in the vector e_1. (unsafe-vector-set! e_1 e_2 e_3) mutates the index e_2 in the vector e_1, setting its value to the value of e_3.

    (unsafe-vector-set! e_1 e_2 e_3) is only allowed in impure computation context.

As we’re adding new data types, we need new tags. Here is our updated list of tags: Here is the set of tags we will use in this assignment, given in base 2.
  • #b000, fixnums, fixed-sized integers

  • #b001, pairs

  • #b010, unused

  • #b011, vectors

  • #b100, unused

  • #b101, unused

  • #b110, non-fixnum immediates (booleans, etc)

  • #b111, unused

We follow the same pattern as Data types: Immediates to implement the new predicates.

To implement constructors, we need to compile to alloc. cons allocates two words of space, storing its first argument in the first word and the second element in the second word, producing `(alloc ,(current-pair-size)). The ptr we get back needs to be tagged, so we produce `(bitwise-ior (alloc ,(current-pair-size)) ,(current-pair-tag)). unsafe-make-vector allocates one word for the length, and then one word for every element of the vector. That is, it should allocate n+1 words for a vector of length n.

After allocating, we initialize the data structures using mset!. For example, we would transform `(cons ,e_1 ,e_2).
`(let ([x.1 (bitwise-ior (alloc 16) ,(current-pair-tag))])
   (begin
     (mset! (bitwise-xor x.1 ,(current-pair-tag)) 0 ,e_1)
     (mset! (bitwise-xor x.1 ,(current-pair-tag)) 8 ,e_2)
     x.1))

Since the length of the vector is dynamically determined, we do not initialize each field when implementing its constructor. Instead, we expose an unsafe constructor for vectors, and leave it to a safer language to initialize the vector.

We can optimize memory operations to avoid masking the pointer by taking advantage of pointer arithmetic. For example, (bitwise-ior (alloc 16) 1) is the same as (+ (alloc 16) 1). We can therefore adjust the index by -1 to access the base of the pointer, instead of masking the pointer. Performing this optimization for pairs, we would instead transform `(cons ,e_1 ,e_2) into
`(let ([x.1 (+ (alloc 16) 1)])
   (begin
     (mset! x.1 -1 ,e_1)
     (mset! x.1 7 ,e_2)
     x.1))
The same optimization holds for vectors with different constants.

Compiles data types and primitive operations into their implementations as ptrs and primitive bitwise operations on ptrs.

5.10.2.7 New Safe Primops

All the accessors for the new data types can result in undefined behaviour if used on the wrong ptr. Similarly, vector reference can access undefined values if the vector is constructed but never initialized.

Below we define Exprs-unique-lang v8.

  p ::= (module b ... e)
     
  b ::= (define label (lambda (aloc ...) e))
     
  e ::= v
  | (call e e ...)
  | (let ([aloc e] ...) e)
  | (if e e e)
     
  v ::= label
  | aloc
  | prim-f
  | fixnum
  | #t
  | #f
  | empty
  | (void)
  | (error uint8)
  | ascii-char-literal
     
  prim-f ::= *
  | +
  | -
  | <
  | <=
  | >
  | >=
  | eq?
  | fixnum?
  | boolean?
  | empty?
  | void?
  | ascii-char?
  | error?
  | not
  | pair?
  | vector?
  | cons
  | car
  | cdr
  | make-vector
  | vector-length
  | vector-set!
  | vector-ref
     
  prim-f ::= binop
  | unop
     
  binop ::= *
  | +
  | -
  | <
  | eq?
  | <=
  | >
  | >=
     
  unop ::= fixnum?
  | boolean?
  | empty?
  | void?
  | ascii-char?
  | error?
  | not
  p ::= (module b ... e)
     
  b ::= (define label (lambda (aloc ...) e))
     
  e ::= v
  | (call e e ...)
  | (let ([aloc e] ...) e)
  | (if e e e)
     
  v ::= label
  | aloc
  | prim-f
  | fixnum
  | #t
  | #f
  | empty
  | (void)
  | (error uint8)
  | ascii-char-literal
     
  prim-f ::= *
  | +
  | -
  | <
  | <=
  | >
  | >=
  | eq?
  | fixnum?
  | boolean?
  | empty?
  | void?
  | ascii-char?
  | error?
  | not
  | pair?
  | vector?
  | cons
  | car
  | cdr
  | make-vector
  | vector-length
  | vector-set!
  | vector-ref
     
  aloc ::= aloc?
     
  label ::= label?
     
  fixnum ::= int61?
     
  uint8 ::= uint8?
     
  ascii-char-literal ::= ascii-char-literal?

Note that in this language, we remove begin. The user must manually call impure functions and bind the result. The result of an effectful function could be void, or an error. It would be unwise, although technically safe, to simple discard errors.

To implement this safe language, we wrap all accessors to perform dynamic tag checking before using the unsafe operations. We also wrap unsafe-make-vector to initialize all elements to 0.

Writing a compiler for the following specification language may simplify this task:
; Symbol x Symbol x (List-of Parameter-Types)
; The first symbol is the name of a function in the source language.
; The second is either the name of a primop or a label in the target language implementing the
; behaviour safely, assuming well-typed parameters.
; The third is list of predicates, one for each argument to the source
; function, to check the parameters with. `any?` is specially recognized to
; not be checked.
(define prim-f-specs
  `((* unsafe-fx* (fixnum? fixnum?))
    (+ unsafe-fx+ (fixnum? fixnum?))
    (- unsafe-fx- (fixnum? fixnum?))
    (< unsafe-fx< (fixnum? fixnum?))
    (<= unsafe-fx<= (fixnum? fixnum?))
    (> unsafe-fx> (fixnum? fixnum?))
    (>= unsafe-fx>= (fixnum? fixnum?))
 
    (make-vector ,make-init-vector-label (fixnum?))
    (vector-length unsafe-vector-length (vector?))
    (vector-set! ,unsafe-vector-set!-label (vector? fixnum? any?))
    (vector-ref ,unsafe-vector-ref-label (vector? fixnum?))
 
    (car unsafe-car (pair?))
    (cdr unsafe-cdr (pair?))
 
    ,@(map (lambda (x) `(,x ,x (any?)))
           '(fixnum? boolean? empty? void? ascii-char? error? pair?
                     vector? not))
    ,@(map (lambda (x) `(,x ,x (any? any?)))
           '(cons eq?))))

All impure computations, those that end in !, should only return (void) or an error.

Implement safe primitive operations by inserting procedure definitions for each primitive operation which perform dynamic tag checking, to ensure type and memory safety.

5.10.2.8 uniquify

Finally, we define the source language. Below we define Exprs-lang v8.

  p ::= (module b ... e)
     
  b ::= (define x (lambda (x ...) e))
     
  e ::= v
  | (call e e ...)
  | (let ([x e] ...) e)
  | (if e e e)
     
  x ::= name?
  | prim-f
     
  v ::= x
  | fixnum
  | #t
  | #f
  | empty
  | (void)
  | (error uint8)
  | ascii-char-literal
     
  prim-f ::= *
  | +
  | -
  | <
  | <=
  | >
  | >=
  | eq?
  | fixnum?
  | boolean?
  | empty?
  | void?
  | ascii-char?
  | error?
  | not
  | pair?
  | vector?
  | cons
  | car
  | cdr
  | make-vector
  | vector-length
  | vector-set!
  | vector-ref
     
  prim-f ::= binop
  | unop
     
  binop ::= *
  | +
  | -
  | eq?
  | <
  | <=
  | >
  | >=
     
  unop ::= fixnum?
  | boolean?
  | empty?
  | void?
  | ascii-char?
  | error?
  | not
     
  fixnum ::= int61?
     
  uint8 ::= uint8?
     
  ascii-char-literal ::= ascii-char-literal?

5.10.3 Appendix: Overview

LxExprs-lang v8Lx->Lx check-exprs-langLyExprs-unique-lang v8Lx->Ly uniquifyLzExprs-unsafe-data-lang v8Ly->Lz implement-safe-primopsL0Exprs-bits-lang v8Lz->L0 specify-representationL1Values-bits-lang v8L0->L1 remove-complex-opera*L2Proc-imp-mf-lang v8L1->L2 sequentialize-letL3Imp-mf-lang v8L2->L3 impose-calling-conventionsL4Imp-cmf-lang v8L3->L4 normalize-bindL5_1Asm-alloc-lang v8L4->L5_1 select-instructionsL5Asm-pred-lang v8L5_1->L5 expose-allocation-pointerL6Asm-pred-lang v8/localsL5->L6 uncover-localsL7Asm-pred-lang v8/undeadL6->L7 undead-analysisL8Asm-pred-lang v8/conflictsL7->L8 conflict-analysisL81Asm-pred-lang v8/pre-framedL8->L81 assign-call-undead-variablesL82Asm-pred-lang v8/framedL81->L82 allocate-framesL83Asm-pred-lang v8/spilledL82->L83 assign-registersL9Asm-pred-lang v8/assignmentsL83->L9 assign-frame-variablesL10Nested-asm-lang-fvars v8L9->L10 replace-locationsL10_1Nested-asm-lang v8L10->L10_1 implement-fvarsL11Block-pred-lang v8L10_1->L11 expose-basic-blocksL12Block-asm-lang v8L11->L12 resolve-predicatesL12_1Para-asm-lang v8L12->L12_1 flatten-programL15_1Paren-x64-mops v8L12_1->L15_1 patch-instructionsL14x64L15integerL14->L15 executeL16Paren-x64 v8L15_1->L16 implement-mopsL16->L14 generate-x64L16->L15 interp-paren-x64L17Paren-x64-rt v8L16->L17 link-paren-x64L17->L15 interp-loop

Figure 8: Overview of Compiler Version 8

5.10.4 Appendix: Languages

procedure

(exprs-lang-v8? a)  boolean?

  a : any/c
Decides whether a is a valid program in the exprs-lang-v8 grammar. The first non-terminal in the grammar defines valid programs.

exprs-lang-v8 : grammar?

  p ::= (module b ... e)
     
  b ::= (define x (lambda (x ...) e))
     
  e ::= v
  | (call e e ...)
  | (let ([x e] ...) e)
  | (if e e e)
     
  x ::= name?
  | prim-f
     
  v ::= x
  | fixnum
  | #t
  | #f
  | empty
  | (void)
  | (error uint8)
  | ascii-char-literal
     
  prim-f ::= *
  | +
  | -
  | <
  | <=
  | >
  | >=
  | eq?
  | fixnum?
  | boolean?
  | empty?
  | void?
  | ascii-char?
  | error?
  | not
  | pair?
  | vector?
  | cons
  | car
  | cdr
  | make-vector
  | vector-length
  | vector-set!
  | vector-ref
     
  fixnum ::= int61?
     
  uint8 ::= uint8?
     
  ascii-char-literal ::= ascii-char-literal?

procedure

(exprs-unique-lang-v8? a)  boolean?

  a : any/c
Decides whether a is a valid program in the exprs-unique-lang-v8 grammar. The first non-terminal in the grammar defines valid programs.
  p ::= (module b ... e)
     
  b ::= (define label (lambda (aloc ...) e))
     
  e ::= v
  | (call e e ...)
  | (let ([aloc e] ...) e)
  | (if e e e)
     
  v ::= label
  | aloc
  | prim-f
  | fixnum
  | #t
  | #f
  | empty
  | (void)
  | (error uint8)
  | ascii-char-literal
     
  prim-f ::= *
  | +
  | -
  | <
  | <=
  | >
  | >=
  | eq?
  | fixnum?
  | boolean?
  | empty?
  | void?
  | ascii-char?
  | error?
  | not
  | pair?
  | vector?
  | cons
  | car
  | cdr
  | make-vector
  | vector-length
  | vector-set!
  | vector-ref
     
  aloc ::= aloc?
     
  label ::= label?
     
  fixnum ::= int61?
     
  uint8 ::= uint8?
     
  ascii-char-literal ::= ascii-char-literal?

procedure

(exprs-unsafe-data-lang-v8? a)  boolean?

  a : any/c
Decides whether a is a valid program in the exprs-unsafe-data-lang-v8 grammar. The first non-terminal in the grammar defines valid programs.
  p ::= (module b ... e)
     
  b ::= (define label (lambda (aloc ...) e))
     
  pred ::= e
  | (true)
  | (false)
  | (not pred)
  | (let ([aloc e] ...) pred)
  | (if pred pred pred)
     
  e ::= v
  | (primop e ...)
  | (call e e ...)
  | (let ([aloc e] ...) e)
  | (if pred e e)
  | (begin effect ... e)
     
  effect ::= (primop e ...)
  | (begin effect ... effect)
     
  v ::= label
  | aloc
  | fixnum
  | #t
  | #f
  | empty
  | (void)
  | (error uint8)
  | ascii-char-literal
     
  primop ::= unsafe-fx*
  | unsafe-fx+
  | unsafe-fx-
  | eq?
  | unsafe-fx<
  | unsafe-fx<=
  | unsafe-fx>
  | unsafe-fx>=
  | fixnum?
  | boolean?
  | empty?
  | void?
  | ascii-char?
  | error?
  | not
  | pair?
  | vector?
  | cons
  | unsafe-car
  | unsafe-cdr
  | unsafe-make-vector
  | unsafe-vector-length
  | unsafe-vector-set!
  | unsafe-vector-ref
     
  aloc ::= aloc?
     
  label ::= label?
     
  fixnum ::= int61?
     
  uint8 ::= uint8?
     
  ascii-char-literal ::= ascii-char-literal?

procedure

(exprs-bits-lang-v8/contexts? a)  boolean?

  a : any/c
Decides whether a is a valid program in the exprs-bits-lang-v8/contexts grammar. The first non-terminal in the grammar defines valid programs.
  p ::= (module b ... tail)
     
  b ::= (define label (lambda (aloc ...) tail))
     
  pred ::= (relop value value)
  | (true)
  | (false)
  | (not pred)
  | (let ([aloc value] ...) pred)
  | (if pred pred pred)
  | (begin effect ... pred)
     
  tail ::= value
  | (let ([aloc value] ...) tail)
  | (if pred tail tail)
  | (begin effect ... tail)
     
  value ::= triv
  | (binop value value)
  | (mref value value)
  | (alloc value)
  | (call value value ...)
  | (let ([aloc value]) value)
  | (if pred value value)
  | (begin effect ... value)
     
  effect ::= (mset! value value value)
  | (begin effect ... effect)
     
  triv ::= label
  | aloc
  | int64
     
  binop ::= *
  | +
  | -
  | bitwise-and
  | bitwise-ior
  | bitwise-xor
  | arithmetic-shift-right
     
  aloc ::= aloc?
     
  label ::= label?
     
  relop ::= <
  | <=
  | =
  | >=
  | >
  | !=
     
  int64 ::= int64?

procedure

(values-bits-lang-v8? a)  boolean?

  a : any/c
Decides whether a is a valid program in the values-bits-lang-v8 grammar. The first non-terminal in the grammar defines valid programs.

values-bits-lang-v8 : grammar?

  p ::= (module (define label (lambda (aloc ...) tail)) ... tail)
     
  pred ::= (relop opand opand)
  | (true)
  | (false)
  | (not pred)
  | (let ([aloc value] ...) pred)
  | (if pred pred pred)
  | (begin effect ... pred)
     
  tail ::= value
  | (let ([aloc value] ...) tail)
  | (if pred tail tail)
  | (call triv opand ...)
  | (begin effect ... tail)
     
  value ::= triv
  | (binop opand opand)
  | (mref aloc opand)
  | (alloc opand)
  | (let ([aloc value] ...) value)
  | (if pred value value)
  | (call triv opand ...)
  | (begin effect ... value)
     
  effect ::= (mset! aloc opand value)
  | (let ([aloc value] ...) effect)
  | (begin effect ... effect)
     
  opand ::= int64
  | aloc
     
  triv ::= opand
  | label
     
  binop ::= *
  | +
  | -
  | bitwise-and
  | bitwise-ior
  | bitwise-xor
  | arithmetic-shift-right
     
  relop ::= <
  | <=
  | =
  | >=
  | >
  | !=
     
  int64 ::= int64?
     
  aloc ::= aloc?
     
  label ::= label?

procedure

(proc-imp-mf-lang-v8? a)  boolean?

  a : any/c
Decides whether a is a valid program in the proc-imp-mf-lang-v8 grammar. The first non-terminal in the grammar defines valid programs.

proc-imp-mf-lang-v8 : grammar?

  p ::= 
(module (define label (lambda (aloc ...) entry)) ...
  entry)
     
  entry ::= tail
     
  pred ::= (relop opand opand)
  | (true)
  | (false)
  | (not pred)
  | (begin effect ... pred)
  | (if pred pred pred)
     
  tail ::= value
  | (call triv opand ...)
  | (begin effect ... tail)
  | (if pred tail tail)
     
  value ::= triv
  | (binop opand opand)
  | (mref aloc opand)
  | (alloc opand)
  | (begin effect ... value)
  | (if pred value value)
  | (call triv opand ...)
     
  effect ::= (set! aloc value)
  | (mset! aloc opand value)
  | (begin effect ... effect)
  | (if pred effect effect)
     
  opand ::= int64
  | aloc
     
  triv ::= opand
  | label
     
  binop ::= *
  | +
  | -
  | bitwise-and
  | bitwise-ior
  | bitwise-xor
  | arithmetic-shift-right
     
  relop ::= <
  | <=
  | =
  | >=
  | >
  | !=
     
  int64 ::= int64?
     
  aloc ::= aloc?
     
  label ::= label?

procedure

(imp-mf-lang-v8? a)  boolean?

  a : any/c
Decides whether a is a valid program in the imp-mf-lang-v8 grammar. The first non-terminal in the grammar defines valid programs.

imp-mf-lang-v8 : grammar?

  p ::= (module info (define label info tail) ... tail)
     
  info ::= (#:from-contract (info/c (new-frames (frame ...))))
     
  frame ::= (aloc ...)
     
  pred ::= (relop opand opand)
  | (true)
  | (false)
  | (not pred)
  | (begin effect ... pred)
  | (if pred pred pred)
     
  tail ::= (jump trg loc ...)
  | (begin effect ... tail)
  | (if pred tail tail)
     
  value ::= triv
  | (binop opand opand)
  | (mref loc opand)
  | (alloc opand)
  | (begin effect ... value)
  | (if pred value value)
  | (return-point label tail)
     
  effect ::= (set! loc value)
  | (mset! loc opand value)
  | (begin effect ... effect)
  | (if pred effect effect)
     
  opand ::= int64
  | loc
     
  triv ::= opand
  | label
     
  loc ::= rloc
  | aloc
     
  trg ::= label
  | loc
     
  binop ::= *
  | +
  | -
  | bitwise-and
  | bitwise-ior
  | bitwise-xor
  | arithmetic-shift-right
     
  relop ::= <
  | <=
  | =
  | >=
  | >
  | !=
     
  int64 ::= int64?
     
  aloc ::= aloc?
     
  label ::= label?
     
  rloc ::= register?
  | fvar?

procedure

(imp-cmf-lang-v8? a)  boolean?

  a : any/c
Decides whether a is a valid program in the imp-cmf-lang-v8 grammar. The first non-terminal in the grammar defines valid programs.

imp-cmf-lang-v8 : grammar?

  p ::= (module info (define label info tail) ... tail)
     
  info ::= (#:from-contract (info/c (new-frames (frame ...))))
     
  frame ::= (aloc ...)
     
  pred ::= (relop opand opand)
  | (true)
  | (false)
  | (not pred)
  | (begin effect ... pred)
  | (if pred pred pred)
     
  tail ::= (jump trg loc ...)
  | (begin effect ... tail)
  | (if pred tail tail)
     
  value ::= triv
  | (binop opand opand)
  | (mref loc opand)
  | (alloc opand)
     
  effect ::= (set! loc value)
  | (mset! loc opand triv)
  | (begin effect ... effect)
  | (if pred effect effect)
  | (return-point label tail)
     
  opand ::= int64
  | loc
     
  triv ::= opand
  | label
     
  loc ::= rloc
  | aloc
     
  trg ::= label
  | loc
     
  binop ::= *
  | +
  | -
  | bitwise-and
  | bitwise-ior
  | bitwise-xor
  | arithmetic-shift-right
     
  relop ::= <
  | <=
  | =
  | >=
  | >
  | !=
     
  int64 ::= int64?
     
  aloc ::= aloc?
     
  label ::= label?
     
  rloc ::= register?
  | fvar?

procedure

(asm-alloc-lang-v8? a)  boolean?

  a : any/c
Decides whether a is a valid program in the asm-alloc-lang-v8 grammar. The first non-terminal in the grammar defines valid programs.

asm-alloc-lang-v8 : grammar?

  p ::= (module info (define label info tail) ... tail)
     
  info ::= (#:from-contract (info/c (new-frames (frame ...))))
     
  frame ::= (aloc ...)
     
  pred ::= (relop loc opand)
  | (true)
  | (false)
  | (not pred)
  | (begin effect ... pred)
  | (if pred pred pred)
     
  tail ::= (jump trg loc ...)
  | (begin effect ... tail)
  | (if pred tail tail)
     
  effect ::= (set! loc triv)
  | (set! loc_1 (binop loc_1 opand))
  | (set! loc_1 (mref loc_2 index))
  | (set! loc (alloc index))
  | (mset! loc index triv)
  | (begin effect ... effect)
  | (if pred effect effect)
  | (return-point label tail)
     
  opand ::= int64
  | loc
     
  triv ::= opand
  | label
     
  loc ::= rloc
  | aloc
     
  trg ::= label
  | loc
     
  index ::= int64
  | loc
     
  binop ::= *
  | +
  | -
  | bitwise-and
  | bitwise-ior
  | bitwise-xor
  | arithmetic-shift-right
     
  relop ::= <
  | <=
  | =
  | >=
  | >
  | !=
     
  int64 ::= int64?
     
  int32 ::= int32?
     
  aloc ::= aloc?
     
  label ::= label?
     
  rloc ::= register?
  | fvar?

procedure

(asm-pred-lang-v8? a)  boolean?

  a : any/c
Decides whether a is a valid program in the asm-pred-lang-v8 grammar. The first non-terminal in the grammar defines valid programs.

asm-pred-lang-v8 : grammar?

  p ::= (module info (define label info tail) ... tail)
     
  info ::= (#:from-contract (info/c (new-frames (frame ...))))
     
  frame ::= (aloc ...)
     
  pred ::= (relop loc opand)
  | (true)
  | (false)
  | (not pred)
  | (begin effect ... pred)
  | (if pred pred pred)
     
  tail ::= (jump trg loc ...)
  | (begin effect ... tail)
  | (if pred tail tail)
     
  effect ::= (set! loc triv)
  | (set! loc_1 (binop loc_1 opand))
  | (set! loc_1 (mref loc_2 index))
  | (mset! loc index triv)
  | (begin effect ... effect)
  | (if pred effect effect)
  | (return-point label tail)
     
  opand ::= int64
  | loc
     
  triv ::= opand
  | label
     
  loc ::= rloc
  | aloc
     
  trg ::= label
  | loc
     
  index ::= int64
  | loc
     
  binop ::= *
  | +
  | -
  | bitwise-and
  | bitwise-ior
  | bitwise-xor
  | arithmetic-shift-right
     
  relop ::= <
  | <=
  | =
  | >=
  | >
  | !=
     
  int64 ::= int64?
     
  int32 ::= int32?
     
  aloc ::= aloc?
     
  label ::= label?
     
  rloc ::= register?
  | fvar?

procedure

(asm-pred-lang-v8/locals? a)  boolean?

  a : any/c
Decides whether a is a valid program in the asm-pred-lang-v8/locals grammar. The first non-terminal in the grammar defines valid programs.
  p ::= (module info (define label info tail) ... tail)
     
  info ::= (#:from-contract (info/c (new-frames (frame ...)) (locals (aloc ...))))
     
  frame ::= (aloc ...)
     
  pred ::= (relop loc opand)
  | (true)
  | (false)
  | (not pred)
  | (begin effect ... pred)
  | (if pred pred pred)
     
  tail ::= (jump trg loc ...)
  | (begin effect ... tail)
  | (if pred tail tail)
     
  effect ::= (set! loc triv)
  | (set! loc_1 (binop loc_1 opand))
  | (set! loc_1 (mref loc_2 index))
  | (begin effect ... effect)
  | (mset! loc index triv)
  | (if pred effect effect)
  | (return-point label tail)
     
  opand ::= int64
  | loc
     
  triv ::= opand
  | label
     
  loc ::= rloc
  | aloc
     
  trg ::= label
  | loc
     
  index ::= int64
  | loc
     
  binop ::= *
  | +
  | -
  | bitwise-and
  | bitwise-ior
  | bitwise-xor
  | arithmetic-shift-right
     
  relop ::= <
  | <=
  | =
  | >=
  | >
  | !=
     
  int64 ::= int64?
     
  int32 ::= int32?
     
  aloc ::= aloc?
     
  label ::= label?
     
  rloc ::= register?
  | fvar?

procedure

(asm-pred-lang-v8/undead? a)  boolean?

  a : any/c
Decides whether a is a valid program in the asm-pred-lang-v8/undead grammar. The first non-terminal in the grammar defines valid programs.
  p ::= (module info (define label info tail) ... tail)
     
  info ::= (#:from-contract (info/c (new-frames (frame ...)) (locals (aloc ...)) (call-undead (loc ...)) (undead-out undead-set-tree/rloc?)))
     
  frame ::= (aloc ...)
     
  pred ::= (relop loc opand)
  | (true)
  | (false)
  | (not pred)
  | (begin effect ... pred)
  | (if pred pred pred)
     
  tail ::= (jump trg loc ...)
  | (begin effect ... tail)
  | (if pred tail tail)
     
  effect ::= (set! loc triv)
  | (set! loc_1 (binop loc_1 opand))
  | (set! loc_1 (mref loc_2 index))
  | (mset! loc index triv)
  | (begin effect ... effect)
  | (if pred effect effect)
  | (return-point label tail)
     
  opand ::= int64
  | loc
     
  triv ::= opand
  | label
     
  loc ::= rloc
  | aloc
     
  trg ::= label
  | loc
     
  index ::= int64
  | loc
     
  binop ::= *
  | +
  | -
  | bitwise-and
  | bitwise-ior
  | bitwise-xor
  | arithmetic-shift-right
     
  relop ::= <
  | <=
  | =
  | >=
  | >
  | !=
     
  int64 ::= int64?
     
  int32 ::= int32?
     
  aloc ::= aloc?
     
  label ::= label?
     
  rloc ::= register?
  | fvar?

procedure

(asm-pred-lang-v8/conflicts? a)  boolean?

  a : any/c
Decides whether a is a valid program in the asm-pred-lang-v8/conflicts grammar. The first non-terminal in the grammar defines valid programs.
  p ::= (module info (define label info tail) ... tail)
     
  info ::= (#:from-contract (info/c (new-frames (frame ...)) (locals (aloc ...)) (call-undead (loc ...)) (undead-out undead-set-tree/rloc?) (conflicts ((loc (loc ...)) ...))))
     
  frame ::= (aloc ...)
     
  pred ::= (relop loc opand)
  | (true)
  | (false)
  | (not pred)
  | (begin effect ... pred)
  | (if pred pred pred)
     
  tail ::= (jump trg loc ...)
  | (begin effect ... tail)
  | (if pred tail tail)
     
  effect ::= (set! loc triv)
  | (set! loc_1 (binop loc_1 opand))
  | (set! loc_1 (mref loc_2 index))
  | (mset! loc index triv)
  | (begin effect ... effect)
  | (if pred effect effect)
  | (return-point label tail)
     
  opand ::= int64
  | loc
     
  triv ::= opand
  | label
     
  loc ::= rloc
  | aloc
     
  trg ::= label
  | loc
     
  index ::= int64
  | loc
     
  binop ::= *
  | +
  | -
  | bitwise-and
  | bitwise-ior
  | bitwise-xor
  | arithmetic-shift-right
     
  relop ::= <
  | <=
  | =
  | >=
  | >
  | !=
     
  int64 ::= int64?
     
  int32 ::= int32?
     
  aloc ::= aloc?
     
  label ::= label?
     
  rloc ::= register?
  | fvar?

procedure

(asm-pred-lang-v8/pre-framed? a)  boolean?

  a : any/c
Decides whether a is a valid program in the asm-pred-lang-v8/pre-framed grammar. The first non-terminal in the grammar defines valid programs.
  p ::= (module info (define label info tail) ... tail)
     
  info ::= (#:from-contract (info/c (new-frames (frame ...)) (locals (aloc ...)) (call-undead (loc ...)) (undead-out undead-set-tree/rloc?) (conflicts ((loc (loc ...)) ...)) (assignment ((aloc loc) ...))))
     
  frame ::= (aloc ...)
     
  pred ::= (relop loc opand)
  | (true)
  | (false)
  | (not pred)
  | (begin effect ... pred)
  | (if pred pred pred)
     
  tail ::= (jump trg loc ...)
  | (begin effect ... tail)
  | (if pred tail tail)
     
  effect ::= (set! loc triv)
  | (set! loc_1 (binop loc_1 opand))
  | (set! loc_1 (mref loc_2 index))
  | (mset! loc index triv)
  | (begin effect ... effect)
  | (if pred effect effect)
  | (return-point label tail)
     
  opand ::= int64
  | loc
     
  triv ::= opand
  | label
     
  loc ::= rloc
  | aloc
     
  trg ::= label
  | loc
     
  index ::= int64
  | loc
     
  binop ::= *
  | +
  | -
  | bitwise-and
  | bitwise-ior
  | bitwise-xor
  | arithmetic-shift-right
     
  relop ::= <
  | <=
  | =
  | >=
  | >
  | !=
     
  int64 ::= int64?
     
  int32 ::= int32?
     
  aloc ::= aloc?
     
  label ::= label?
     
  rloc ::= register?
  | fvar?

procedure

(asm-pred-lang-v8/framed? a)  boolean?

  a : any/c
Decides whether a is a valid program in the asm-pred-lang-v8/framed grammar. The first non-terminal in the grammar defines valid programs.
  p ::= (module info (define label info tail) ... tail)
     
  info ::= (#:from-contract (info/c (locals (aloc ...)) (undead-out undead-set-tree/rloc?) (conflicts ((loc (loc ...)) ...)) (assignment ((aloc loc) ...))))
     
  pred ::= (relop loc opand)
  | (true)
  | (false)
  | (not pred)
  | (begin effect ... pred)
  | (if pred pred pred)
     
  tail ::= (jump trg loc ...)
  | (begin effect ... tail)
  | (if pred tail tail)
     
  effect ::= (set! loc triv)
  | (set! loc_1 (binop loc_1 opand))
  | (set! loc_1 (mref loc_2 index))
  | (mset! loc index triv)
  | (begin effect ... effect)
  | (if pred effect effect)
  | (return-point label tail)
     
  opand ::= int64
  | loc
     
  triv ::= opand
  | label
     
  loc ::= rloc
  | aloc
     
  trg ::= label
  | loc
     
  index ::= int64
  | loc
     
  binop ::= *
  | +
  | -
  | bitwise-and
  | bitwise-ior
  | bitwise-xor
  | arithmetic-shift-right
     
  relop ::= <
  | <=
  | =
  | >=
  | >
  | !=
     
  int64 ::= int64?
     
  int32 ::= int32?
     
  aloc ::= aloc?
     
  label ::= label?
     
  rloc ::= register?
  | fvar?

procedure

(asm-pred-lang-v8/spilled? a)  boolean?

  a : any/c
Decides whether a is a valid program in the asm-pred-lang-v8/spilled grammar. The first non-terminal in the grammar defines valid programs.
  p ::= (module info (define label info tail) ... tail)
     
  info ::= (#:from-contract (info/c (locals (aloc ...)) (undead-out undead-set-tree/rloc?) (conflicts ((loc (loc ...)) ...)) (assignment ((aloc loc) ...))))
     
  frame ::= (aloc ...)
     
  pred ::= (relop loc opand)
  | (true)
  | (false)
  | (not pred)
  | (begin effect ... pred)
  | (if pred pred pred)
     
  tail ::= (jump trg loc ...)
  | (begin effect ... tail)
  | (if pred tail tail)
     
  effect ::= (set! loc triv)
  | (set! loc_1 (binop loc_1 opand))
  | (set! loc_1 (mref loc_2 index))
  | (mset! loc index triv)
  | (begin effect ... effect)
  | (if pred effect effect)
  | (return-point label tail)
     
  opand ::= int64
  | loc
     
  triv ::= opand
  | label
     
  loc ::= rloc
  | aloc
     
  trg ::= label
  | loc
     
  index ::= int64
  | loc
     
  binop ::= *
  | +
  | -
  | bitwise-and
  | bitwise-ior
  | bitwise-xor
  | arithmetic-shift-right
     
  relop ::= <
  | <=
  | =
  | >=
  | >
  | !=
     
  int64 ::= int64?
     
  int32 ::= int32?
     
  aloc ::= aloc?
     
  label ::= label?
     
  rloc ::= register?
  | fvar?

procedure

(asm-pred-lang-v8/assignments? a)  boolean?

  a : any/c
Decides whether a is a valid program in the asm-pred-lang-v8/assignments grammar. The first non-terminal in the grammar defines valid programs.
  p ::= (module info (define label info tail) ... tail)
     
  info ::= (#:from-contract (info/c (assignment ((aloc loc) ...))))
     
  frame ::= (aloc ...)
     
  pred ::= (relop loc opand)
  | (true)
  | (false)
  | (not pred)
  | (begin effect ... pred)
  | (if pred pred pred)
     
  tail ::= (jump trg loc ...)
  | (begin effect ... tail)
  | (if pred tail tail)
     
  effect ::= (set! loc triv)
  | (set! loc_1 (binop loc_1 opand))
  | (set! loc_1 (mref loc_2 index))
  | (mset! loc index triv)
  | (begin effect ... effect)
  | (if pred effect effect)
  | (return-point label tail)
     
  opand ::= int64
  | loc
     
  triv ::= opand
  | label
     
  loc ::= rloc
  | aloc
     
  trg ::= label
  | loc
     
  index ::= int64
  | loc
     
  binop ::= *
  | +
  | -
  | bitwise-and
  | bitwise-ior
  | bitwise-xor
  | arithmetic-shift-right
     
  relop ::= <
  | <=
  | =
  | >=
  | >
  | !=
     
  int64 ::= int64?
     
  int32 ::= int32?
     
  aloc ::= aloc?
     
  label ::= label?
     
  rloc ::= register?
  | fvar?

procedure

(nested-asm-lang-fvars-v8? a)  boolean?

  a : any/c
Decides whether a is a valid program in the nested-asm-lang-fvars-v8 grammar. The first non-terminal in the grammar defines valid programs.
  p ::= (module (define label tail) ... tail)
     
  pred ::= (relop loc opand)
  | (true)
  | (false)
  | (not pred)
  | (begin effect ... pred)
  | (if pred pred pred)
     
  tail ::= (jump trg)
  | (begin effect ... tail)
  | (if pred tail tail)
     
  effect ::= (set! loc triv)
  | (set! loc_1 (binop loc_1 opand))
  | (set! loc_1 (mref loc_2 index))
  | (mset! loc index triv)
  | (begin effect ... effect)
  | (if pred effect effect)
  | (return-point label tail)
     
  triv ::= opand
  | label
     
  opand ::= int64
  | loc
     
  trg ::= label
  | loc
     
  loc ::= reg
  | fvar
     
  index ::= int64
  | loc
     
  reg ::= rsp
  | rbp
  | rax
  | rbx
  | rcx
  | rdx
  | rsi
  | rdi
  | r8
  | r9
  | r12
  | r13
  | r14
  | r15
     
  binop ::= *
  | +
  | -
  | bitwise-and
  | bitwise-ior
  | bitwise-xor
  | arithmetic-shift-right
     
  relop ::= <
  | <=
  | =
  | >=
  | >
  | !=
     
  int64 ::= int64?
     
  int32 ::= int32?
     
  aloc ::= aloc?
     
  fvar ::= fvar?
     
  label ::= label?

procedure

(nested-asm-lang-v8? a)  boolean?

  a : any/c
Decides whether a is a valid program in the nested-asm-lang-v8 grammar. The first non-terminal in the grammar defines valid programs.

nested-asm-lang-v8 : grammar?

  p ::= (module (define label tail) ... tail)
     
  pred ::= (relop loc opand)
  | (true)
  | (false)
  | (not pred)
  | (begin effect ... pred)
  | (if pred pred pred)
     
  tail ::= (jump trg)
  | (begin effect ... tail)
  | (if pred tail tail)
     
  effect ::= (set! loc triv)
  | (set! loc_1 (binop loc_1 opand))
  | (set! loc_1 (mref loc_2 index))
  | (mset! loc index triv)
  | (begin effect ... effect)
  | (if pred effect effect)
  | (return-point label tail)
     
  triv ::= opand
  | label
     
  opand ::= int64
  | loc
     
  trg ::= label
  | loc
     
  loc ::= reg
  | addr
     
  index ::= int64
  | loc
     
  reg ::= rsp
  | rbp
  | rax
  | rbx
  | rcx
  | rdx
  | rsi
  | rdi
  | r8
  | r9
  | r12
  | r13
  | r14
  | r15
     
  binop ::= *
  | +
  | -
  | bitwise-and
  | bitwise-ior
  | bitwise-xor
  | arithmetic-shift-right
     
  relop ::= <
  | <=
  | =
  | >=
  | >
  | !=
     
  int64 ::= int64?
     
  int32 ::= int32?
     
  addr ::= (fbp - dispoffset)
     
  fbp ::= frame-base-pointer-register?
     
  dispoffset ::= dispoffset?
     
  label ::= label?

procedure

(block-pred-lang-v8? a)  boolean?

  a : any/c
Decides whether a is a valid program in the block-pred-lang-v8 grammar. The first non-terminal in the grammar defines valid programs.

block-pred-lang-v8 : grammar?

  p ::= (module b ... b)
     
  b ::= (define label tail)
     
  pred ::= (relop loc opand)
  | (true)
  | (false)
  | (not pred)
     
  tail ::= (jump trg)
  | (begin s ... tail)
  | (if pred (jump trg) (jump trg))
     
  s ::= (set! loc triv)
  | (set! loc_1 (binop loc_1 opand))
  | (set! loc_1 (mref loc_2 index))
  | (mset! loc index triv)
     
  triv ::= opand
  | label
     
  opand ::= int64
  | loc
     
  trg ::= label
  | loc
     
  loc ::= reg
  | addr
     
  index ::= int64
  | loc
     
  reg ::= rsp
  | rbp
  | rax
  | rbx
  | rcx
  | rdx
  | rsi
  | rdi
  | r8
  | r9
  | r12
  | r13
  | r14
  | r15
     
  binop ::= *
  | +
  | -
  | bitwise-and
  | bitwise-ior
  | bitwise-xor
  | arithmetic-shift-right
     
  relop ::= <
  | <=
  | =
  | >=
  | >
  | !=
     
  int64 ::= int64?
     
  int32 ::= int32?
     
  addr ::= (fbp - dispoffset)
     
  fbp ::= frame-base-pointer-register?
     
  dispoffset ::= dispoffset?
     
  label ::= label?

procedure

(block-asm-lang-v8? a)  boolean?

  a : any/c
Decides whether a is a valid program in the block-asm-lang-v8 grammar. The first non-terminal in the grammar defines valid programs.

block-asm-lang-v8 : grammar?

  p ::= (module b ... b)
     
  b ::= (define label tail)
     
  tail ::= (jump trg)
  | (begin s ... tail)
  | (if (relop loc opand) (jump trg) (jump trg))
     
  s ::= (set! loc triv)
  | (set! loc_1 (binop loc_1 opand))
  | (set! loc_1 (mref loc_2 index))
  | (mset! loc index triv)
     
  triv ::= opand
  | label
     
  opand ::= int64
  | loc
     
  trg ::= label
  | loc
     
  loc ::= reg
  | addr
     
  index ::= int64
  | loc
     
  reg ::= rsp
  | rbp
  | rax
  | rbx
  | rcx
  | rdx
  | rsi
  | rdi
  | r8
  | r9
  | r12
  | r13
  | r14
  | r15
     
  binop ::= *
  | +
  | -
  | bitwise-and
  | bitwise-ior
  | bitwise-xor
  | arithmetic-shift-right
     
  relop ::= <
  | <=
  | =
  | >=
  | >
  | !=
     
  int64 ::= int64?
     
  int32 ::= int32?
     
  addr ::= (fbp - dispoffset)
     
  fbp ::= frame-base-pointer-register?
     
  dispoffset ::= dispoffset?
     
  label ::= label?

procedure

(para-asm-lang-v8? a)  boolean?

  a : any/c
Decides whether a is a valid program in the para-asm-lang-v8 grammar. The first non-terminal in the grammar defines valid programs.

para-asm-lang-v8 : grammar?

  p ::= (begin s ...)
     
  s ::= (set! loc triv)
  | (set! loc_1 (binop loc_1 opand))
  | (set! loc_1 (mref loc_2 index))
  | (mset! loc_1 index triv)
  | (with-label label s)
  | (jump trg)
  | (compare loc opand)
  | (jump-if relop trg)
     
  trg ::= label
  | loc
     
  triv ::= opand
  | label
     
  opand ::= int64
  | loc
     
  loc ::= reg
  | addr
     
  index ::= int64
  | loc
     
  reg ::= rsp
  | rbp
  | rax
  | rbx
  | rcx
  | rdx
  | rsi
  | rdi
  | r8
  | r9
  | r12
  | r13
  | r14
  | r15
     
  addr ::= (fbp - dispoffset)
     
  fbp ::= frame-base-pointer-register?
     
  binop ::= *
  | +
  | -
  | bitwise-and
  | bitwise-ior
  | bitwise-xor
  | arithmetic-shift-right
     
  relop ::= <
  | <=
  | =
  | >=
  | >
  | !=
     
  int64 ::= int64?
     
  int32 ::= int32?
     
  label ::= label?
     
  dispoffset ::= dispoffset?

procedure

(paren-x64-mops-v8? a)  boolean?

  a : any/c
Decides whether a is a valid program in the paren-x64-mops-v8 grammar. The first non-terminal in the grammar defines valid programs.

paren-x64-mops-v8 : grammar?

  p ::= (begin s ...)
     
  s ::= (set! addr int32)
  | (set! addr trg)
  | (set! reg loc)
  | (set! reg triv)
  | (set! reg_1 (binop reg_1 int32))
  | (set! reg_1 (binop reg_1 loc))
  | (set! reg_1 (mref reg_2 index))
  | (mset! reg_1 index triv)
  | (with-label label s)
  | (jump trg)
  | (compare reg opand)
  | (jump-if relop label)
     
  trg ::= reg
  | label
     
  triv ::= trg
  | int64
     
  opand ::= int64
  | reg
     
  loc ::= reg
  | addr
     
  index ::= int32
  | reg
     
  reg ::= rsp
  | rbp
  | rax
  | rbx
  | rcx
  | rdx
  | rsi
  | rdi
  | r8
  | r9
  | r10
  | r11
  | r12
  | r13
  | r14
  | r15
     
  addr ::= (fbp - dispoffset)
     
  fbp ::= frame-base-pointer-register?
     
  binop ::= *
  | +
  | -
  | bitwise-and
  | bitwise-ior
  | bitwise-xor
  | arithmetic-shift-right
     
  relop ::= <
  | <=
  | =
  | >=
  | >
  | !=
     
  int64 ::= int64?
     
  int32 ::= int32?
     
  label ::= label?
     
  dispoffset ::= dispoffset?

procedure

(paren-x64-v8? a)  boolean?

  a : any/c
Decides whether a is a valid program in the paren-x64-v8 grammar. The first non-terminal in the grammar defines valid programs.

paren-x64-v8 : grammar?

  p ::= (begin s ...)
     
  s ::= (set! addr int32)
  | (set! addr trg)
  | (set! reg loc)
  | (set! reg triv)
  | (set! reg_1 (binop reg_1 int32))
  | (set! reg_1 (binop reg_1 loc))
  | (with-label label? s)
  | (jump trg)
  | (compare reg opand)
  | (jump-if relop label)
     
  trg ::= reg
  | label
     
  triv ::= trg
  | int64
     
  opand ::= int64
  | reg
     
  loc ::= reg
  | addr
     
  reg ::= rsp
  | rbp
  | rax
  | rbx
  | rcx
  | rdx
  | rsi
  | rdi
  | r8
  | r9
  | r10
  | r11
  | r12
  | r13
  | r14
  | r15
     
  addr ::= (fbp - dispoffset)
  | (reg + int32)
  | (reg + reg)
     
  fbp ::= frame-base-pointer-register?
     
  binop ::= *
  | +
  | -
  | bitwise-and
  | bitwise-ior
  | bitwise-xor
  | arithmetic-shift-right
     
  relop ::= <
  | <=
  | =
  | >=
  | >
  | !=
     
  int32 ::= int32?
     
  int64 ::= int64?
     
  label ::= label?
     
  dispoffset ::= dispoffset?