Preprocessor macros
*******************

Preprocessor macros provide a way of simplifying the writing of .cpu files.

Pmacros introduction
====================

The macro facility provided by CGEN is quite extensive. This is to give .cpu file writers the freedom to write the file in ways that work for the architecture in question. Not all architectures are best described in the same way.

The macros are called pmacros because the word macro has become overloaded.  For clarity, we give them a unique name: pmacros.

One important point to keep in mind regarding pmacros is that when loading .cpu files all pmacros are expanded and discarded, their only purpose is to simplify writing the dnis and other elements of the architecture description.

Therefore, do not try to write RTL as pmacros. You can of course use pmacros to assist in the writing of RTL, but remember that the resulting RTL cannot use pmacros. By the time the RTL is processed all pmacros have been expanded and discarded.

A simple picture may help. Here is a basic diagram of the steps in processing cpu descriptions.

              (1) .cpu file
                     |
           (2) pmacro expansion
                     |
     (3) define-{insn,operand,etc.} processing
                     |
        (4) instruction set analysis
                     |
      (5) application source file generation

Once CGEN gets to step (3) pmacros no longer exist.

Defining pmacros
================

There are two kinds of macros:

  * function macros

  * variable macros

Preprocessor function macros are defined with:

     (define-pmacro (name [parm1 parm2 ... parmN])
       ["optional comment"]
       expansion
     )

expansion must be exactly one expression.

Preprocessor variable macros are just global variables, nothing special. When invoked their value is used in place of their name.

Variable macros are defined with:

     (define-pmacro name
       ["optional comment"]
       expansion
     )

Using pmacros
=============

Functional macros are invoked in either of two ways: positional arguments or specifying arguments by name.

     (define-pmacro (foo arg1 arg2) (bar arg1 arg2))

     ;; Invoke by positional arguments.

     (foo abc def) ==> (bar abc def)

     ;; Invoke by naming arguments.

     (foo #:arg1 ghi #:arg2 jkl) ==> (bar ghi jkl)

Variable macros are invoked simply by specifying their name.

     (define-pmacro foo "abc")

     (.str foo "def") ==> "abcdef"

Pmacro expansion
================

Most (Syntactic form pmacros don't pre-evaluate their arguments. See Syntactic forms.) function pmacros are expanded by first processing any macros in the invocation, binding the resulting expressions to the pmacro's parameters, processing the pmacro according to its definition, and returning the result. Free variables are left unchanged. (A "free variable", as defined here, is one that is not already bound, be it to parameter, macro, or local variable within a macro. Note that to pmacros, cpu description file elements like reg, sequence, VOID, etc. are just symbols; they have no special meaning.)

Variable macros are expanded simply by replacing their name with their value.

After a pmacro has been expanded, if the result is a symbol that names another pmacro, it is in turn processed.  This happens just once, not repeatedly. (This behaviour will go away eventually, do not rely on it.)

Here is a simple example that uses pmacros to simplify the definition of several instructions.

     ;; OP1_*,OP2_* are previously defined enums
     (define-pmacro arithmetic-insns
       ((add OP2_0) (sub OP2_1) (mul OP2_2) (div OP2_3))
     )
     (define-pmacro (make-arith-reg/reg-format opcode)
       (+ OP1_0 opcode dr sr)
     )
     (define-pmacro (make-arith-reg/imm-format opcode)
       (+ OP1_1 opcode dr sr)
     )
     (define-pmacro (define-arith-insn ispec)
       (begin
         (dni (.ref ispec 0)
              (.str (.ref ispec 0) " reg/reg")
              ()
              (.str (.ref ispec 0) " $dr,$sr")
              (make-arith-reg/reg-format (.ref ispec 1))
              (set dr ((.ref ispec 0) dr sr))
              ()
              )
         (dni (.ref ispec 0)
              (.str (.ref ispec 0) " reg/imm")
              ()
              (.str (.ref ispec 0) " $dr,$imm")
              (make-arith-reg/imm-format (.ref ispec 1))
              (set dr ((.ref ispec 0) dr imm))
              ()
              )
       )
     )

     ;; Create dnis for each kind of instruction.
     ;; The result of this is:
     ;; (begin (begin (dni ...) ...) (begin (dni ...) ...) ...)
     (.splice begin (.unsplice (.map define-arith-insn arithmetic-insns)))

The .splice, .unsplice are necessary to pass properly formed expressions to the .cpu file reader. If we just used (.map define-arith-insn arithmetic-insns) the reader would see ((begin (dni ...) ...) (begin (dni ...) ...)). Note how the first begin is nested within a list, and does not appear in the ``top level'' list.

Another way to accomplish the same thing that doesn't require .splice, .unsplice is to use .for-each, .exec. .for-each is only used for its side-effects, it does not return a result.  Therefore, in order to actually cause the .cpu file reader to see any definitions we need to use .exec to pass the dnis to the reader.

     (define-pmacro (define-arith-insn ispec)
       (.exec (dni (.ref ispec 0)
                (.str (.ref ispec 0) " reg/reg")
                ()
                (.str (.ref ispec 0) " $dr,$sr")
                (make-arith-reg/reg-format (.ref ispec 1))
                (set dr ((.ref ispec 0) dr sr))
                ()
                ))
       (.exec (dni (.ref ispec 0)
                (.str (.ref ispec 0) " reg/imm")
                ()
                (.str (.ref ispec 0) " $dr,$imm")
                (make-arith-reg/imm-format (.ref ispec 1))
                (set dr ((.ref ispec 0) dr imm))
                ()
                ))
     )
     (.for-each define-arith-insn arithmetic-insns)

Syntactic forms
===============

Some function pmacros are called syntactic forms. These pmacros are processed differently in that parameters are not evaluated first.  Instead it is up to the pmacro to decide when, and if, the parameters are evaluated.

The syntactic forms are:

  * .pmacro. See Defining a pmacro inline.

  * .let, .let*. See Defining a block of locals.

  * .if. See Traditional if.

  * .case. See Traditional case.

  * .cond. See Extended if/elseif/else.

  * .begin. See A block of statements.

  * .andif. See .andif.

  * .orif. See .orif.

The docs for each syntactic pmacro describes when it evaluates its arguments.

All syntactic form pmacros are pre-defined. The user can not currently define his/her own.

Default argument values
=======================

Invoking pmacros by specifying argument names allows some, or all, arguments to be elided and thus allows for arguments to have default values.

Specify default values with the following syntax.

     (define-pmacro (macro-name (arg1 . default-value)
                                (arg2 . default value) ...)
       ...
     )

To invoke a pmacro with default values for some, or all, arguments, you must specify arguments by name.

Example:

     (define-pmacro (foo (arg1 . 1) (arg2 . 2))
       (bar arg1 arg2)
     )

     (foo #:arg1 4) ==> (bar 4 2)

     (foo 4) ==> ERROR, must invoke pmacro by specifying arguments by name

Multiple result statements
==========================

The result of a preprocessor macro is exactly one expression. It is often useful, however, to return multiple expressions, say for example when you want one macro to define several instructions.

The way to do this is to enclose all the expressions with begin. begin is only valid at the top [definition] level.

Note that this is not the .begin builtin pmacro. We want to pass a list of statements to the .cpu file reader, and pmacros have all been evaluated and discarded by this point.

Symbols and strings
===================

There are several builtin macros for symbol and string manipulation.

Symbol concatenation
--------------------

Symbol and string concatenation are supported. Symbol concatenation is done with:

(.sym arg1 arg2 ...)

Acceptable arguments are symbols, strings, and numbers. The result is a symbol with the arguments concatenated together. Numbers are converted to a string, base 10, and then to a symbol. The result must be a valid Scheme symbol with the additional restriction that the first character must be a letter.  The resulting symbol is recursively macro-expanded.

String concatenation
--------------------

String concatenation is done with

(.str arg1 arg2 ...)

Acceptable arguments are symbols, strings, and numbers.  The result is a string with the arguments concatenated together. Numbers are converted base 10.

Example:

     (define-pmacro (bin-op mnemonic op2-op sem-op)
       (dni mnemonic
            (.str mnemonic " reg/reg")
            ()
            (.str mnemonic " $dr,$sr")
            (+ OP1_0 op2-op dr sr)
            (set dr (sem-op dr sr))
            ())
     )
     (bin-op and OP2_12 and)
     (bin-op or OP2_14 or)
     (bin-op xor OP2_13 xor)

Convert a number to a hex
-------------------------

Convert a number to a lowercase hex string with .hex.  If width is present, the result is that many characters beginning with the least significant digit.  Zeros are prepended as necessary.

Syntax: (.hex number [width])

Examples:

     (.hex 42)   --> "2a"
     (.hex 42 1) --> "a"
     (.hex 42 4) --> "002a"

Convert a string to uppercase
-----------------------------

Convert a string to uppercase with .upcase.

Syntax: (.upcase string)

Example:

     (.upcase "foo!") --> "FOO!"

Convert a string to lowercase
-----------------------------

Convert a string to lowercase with .downcase.

Syntax: (.downcase string)

Example:

     (.downcase "BAR?") --> "bar?"

Getting part of a string
------------------------

Extract a part of a string with .substring.

Syntax: (.substring string start end)

where start is the starting character, and end is one past the ending character.  Character numbering begins at position 0. If start and end are the same, and both valid, the empty string is returned.

Example:

     (.substring "howzitgoineh?" 2 6) --> "wzit"

Symbol or string length
-----------------------

Compute the length, in characters, of a symbol or string.

Syntax: (.length symbol-or-string)

Examples:

     (.length abc) --> 3
     (.length "def") --> 3
     (.length "") --> 0

Number utilities
================

Builtin macros for manipulating numbers.

Number generation
-----------------

Machine descriptions often require a list of sequential numbers. Generate a list of numbers with the .iota builtin macro.

Syntax: (.iota count [start [incr]]).

Examples:

     (.iota 5)      --> 0 1 2 3 4
     (.iota 5 4)    --> 4 5 6 7 8
     (.iota 5 5 -1) --> 5 4 3 2 1

List utilities
==============

Builtin macros for maninpulating lists.

Creating lists
--------------

Lists can be created with the .list builtin.

Syntax: (.list elm1 elm2 ...)

It's somewhat redundant as lists can also be created simply writing (elm1 elm2 ...).

List splicing
-------------

Syntax: (.splice [expr1] [expr2] [(.unsplice list1)] [(.unsplice list2)] [expr3] ...)

It is often useful to splice a list into a "parent" list. This is best explained with an example.

     (define-pmacro (splice-test a b c)
                    (.splice a (.unsplice b) c))
     (pmacro-dump (splice-test 1 (2) 3))

     --> (1 2 3)

Note that a level of parentheses around 2 has been removed.

This is useful, for example, when one wants to pass a list of fields to a macro that defines an instruction.  For example:

     (define-pmacro (cond-move-1 name comment mnemonic cc-prefix cc-name cc-opcode
     			    src-name src-opcode cond test)
       (dni name
            (.str "move %" cc-name " " comment ", v9 page 191")
            ((MACH64))
            (.str mnemonic " " cc-prefix cc-name ",$" src-name ",$rd")
            (.splice + OP_2 rd OP3_MOVCC cond
     		(.unsplice cc-opcode) (.unsplice src-opcode))
            (if (test cc-name)
     	   (set rd src-name))
            ())
     )

This macro, taken from sparc64.cpu, defines a conditional move instruction. Arguments cc-opcode and src-opcode are lists of fields. The macro is invoked with (simplified from sparc64.cpu):

     (cond-move-1 mova-icc "blah ..." mova
                  "%" icc ((f-fmt4-cc2 1) (f-fmt4-cc1-0 0))
                  rs2 ((f-i 0) (f-fmt4-res10-6 0) rs2)
                  CC_A test-always)
     (cond-move-1 mova-imm-icc "blah ..." mova
                  "%" icc ((f-fmt4-cc2 1) (f-fmt4-cc1-0 0))
                  simm11 ((f-i 1) simm11)
                  CC_A test-always)

Macro cond-move-1 is being used here to define both the register and the immediate value case.  Each case has a slightly different list of opcode fields.  Without the use of .splice/.unsplice, the resulting formats would be:

     (+ OP_2 rd OP3_MOVCC CC_A ((f-fmt4-cc2-1) (f-fmt4-cc1-0 0))
        ((f-i 0) (f-fmt4-res10-6 0) rs2))

     and

     (+ OP_2 rd OP3_MOVCC CC_A ((f-fmt4-cc2-1) (f-fmt4-cc1-0 0))
        ((f-i 1) simm11))

respectively.  This is not what is wanted.  What is wanted is

     (+ OP_2 rd OP3_MOVCC CC_A (f-fmt4-cc2-1) (f-fmt4-cc1-0 0)
        (f-i 0) (f-fmt4-res10-6 0) rs2)

     and

     (+ OP_2 rd OP3_MOVCC CC_A (f-fmt4-cc2-1) (f-fmt4-cc1-0 0)
        (f-i 1) simm11)

respectively, which is what .splice achieves.

.unsplice is a special reserved symbol that is only recognized inside .splice.  There can be any number of .unsplice expressions in a .splice but they all must be at the ``top level''.

I.e. this is not supported: (.splice 1 (2 3 (.unsplice (4 5)))).

Note that .splice without any .unsplice expressions behaves identically to .list.

Referencing a list element
--------------------------

Reference elements of a list with .ref.

Syntax: (.ref list element-number)

Example:

     (.ref (1 2 3) 1) --> 2

List length
-----------

The length of a list is computed with .length.

Syntax: (.length list).

Example:

     (.length (1 2 3)) --> 3

Lists of repeated elements
--------------------------

Create a list of repeated elements with .replicate.

Syntax: (.replicate n expr)

Example:

     (.replicate 4 5) --> (5 5 5 5)

Finding a subset of a list
--------------------------

Compute a subset of a list matching a specified predicate with .find.

Syntax: (.find predicate list)

Example:

     (.find (.pmacro (n) (.lt n 2)) (.iota 4)) --> (0 1)

car/cdr
-------

CGEN provides a small set of pmacros for those familiar with Scheme/Lisp lists.

  * car

     Equivalent to (.ref list 0).

     Example:

          (.car (1 2 3)) --> 1

  * cdr

     Return all elements of the list after the first one.

     Example:

          (.cdr (1 2 3)) --> (2 3)

  * caar

     Return the first element of the first element of the list.

     I.e., the car of the car of the list.

     Example:

          (.caar ((1 2 3) (4 5 6))) --> 1

  * cadr

     Return the second element of the list.

     I.e., the car of the cdr of the list.

     Example:

          (.cadr (1 2 3)) --> 2

  * cdar

     Return all elements after the first element of the first element of the list. That's a bit of a mouthful, it's easier to understand by applying car and cdr in turn.

     I.e., the cdr of the car of the list.

     Example:

          (.cadr ((1 2 3) (4 5 6))) --> (2 3)

  * cddr

     I.e., the cdr of the cdr of the list.

     Return all elements of the list after the first two.

     Example:

          (.cddr (1 2 3)) --> (3)

Iteration utilities
===================

Macros for iterating over lists

Mapping a macro over a list
---------------------------

Apply a macro to each element of a list, or set of lists, with .map. The order in which each element of the list is processed is unspecified.

The syntax is (.map macro-name list1 [list2 ...]). macro must take as many arguments as there are lists.

The result is a list with macro applied to each element of listN.  This is often useful in constructing enum and register name lists.

Example:

     (define-pmacro (foo name number) ((.sym X name) number))
     (.map foo (A B C D E) (.iota 5))

     -->

     ((XA 0) (XB 1) (XC 2) (XD 3) (XE 4))

Iterating over a list
---------------------

Apply a macro to each element of a list, or set of lists, with .for-each. Each element of the list is guaranteed to be processed in order.

The syntax is (.for-each macro list1 [list2 ...]). macro must take as many arguments as there are lists.

There is no result, or rather the result is always the empty list (). Note that this macro is therefore useless for macro expansion. It's purpose is to process macro for its side-effects. The .exec builtin pmacro is useful here.

Conditional macros
==================

Macros for conditional execution.

Traditional if
--------------

Syntax: (.if condition then-expr [else-expr]).

The condition is evaluated, and if it is non-#f then then-expr is evaluated and returned. Otherwise, if else-expr is present it is evaluated and returned. Otherwise, the empty list () is returned.

Traditional case
----------------

Syntax: (.case expr ((case1-list) expr-list) [case-list] [(else expr-list)])

The expression expr is evaluated, and then each case list is examined in turn to look for a match. The first case list with an element that matches expr wins, its expr-list is evaluated and the result of the last expression in the expression list is returned.

If there is no successful match and no else part, then the empty list () is returned.

Extended if/elseif/else
-----------------------

Syntax: (.cond (expr1 expr-list) [cond-list] [(else expr-list)])

Each condition's expression is evaluated in turn. The first condition to evaluate to non-#f wins, its expr-list is evaluated and the result of the last expression in the expression list is returned.

If there is no successful condition and no else part, then the empty list () is returned.

Pmacro utilities
================

Pmacros for working with pmacros.

Re-evaluating an expression
---------------------------

Syntax: (.eval expr)

Sometimes one wishes to build up an expression in non-trivial ways and then have the expression evaluated. Use the .eval builtin pmacro for this purpose, it re-evaluates expr, invoking any pmacros contained therein.

A perhaps contrived example is when one wants to construct the pmacro's name from a set of parameters.

Example:

     (define-pmacro (do-foo a b) (foo a b))
     (define-pmacro (do-bar a b) (bar a b))
     (define-pmacro (doer what a b) (.eval (.list (.sym do- what) a b)))
     (doer foo 1 2) ;; --> (foo 1 2)
     (doer bar 3 4) ;; --> (bar 3 4)

Immediate execution of a command
--------------------------------

Syntax: (.exec expr)

Sometimes one wishes to pass an expression to the .cpu file reader immediately, rather than waiting for it to process the expression that is the result of a pmacro.  This typically happens with the .for-each builtin pmacro. Use the .exec builtin pmacro for this purpose. It immediately passes expr to the .cpu file reader for processing and returns () as a result.

Applying a pmacro to a list
---------------------------

Invoke a macro with each argument coming from an element of a list, with .apply.

The syntax is (.apply macro-name list).

The result is the result of invoking macro macro-name. macro-name should take as many arguments as there elements in list.  If macro-name takes a variable number of trailing arguments, there must be at least as many list elements as there are fixed arguments.

Example:

Example:

     (.apply .str (.iota 5)) --> "01234"

Note that (.str (.iota 5)) is an error.  Here the list (0 1 2 3 4) is passed as the first argument of .str, which is wrong.

Defining a pmacro inline
------------------------

Define a macro inline with .pmacro. This is only supported when passing macros as arguments to other macros, and as values for local variables in .let or .let*.

Example:

     (define-pmacro (load-op suffix op2-op mode ext-op)
       (begin
         (dni (.sym ld suffix) (.str "ld" suffix)
     	 ()
     	 (.str "ld" suffix " $dr,@$sr")
     	 (+ OP1_2 op2-op dr sr)
     	 (set dr (ext-op WI (mem mode sr)))
     	 ())
       )
     )

     (load-op "" OP2_12 WI (.pmacro (mode expr) expr))
     (load-op b OP2_8 QI (.pmacro (mode expr) (ext mode expr)))
     (load-op h OP2_10 HI (.pmacro (mode expr) (ext mode expr)))
     (load-op ub OP2_9 QI (.pmacro (mode expr) (zext mode expr)))
     (load-op uh OP2_11 HI (.pmacro (mode expr) (zext mode expr)))

.pmacro's bind the same way Scheme lambda expressions do. In the following example, arg2 in the second pmacro is bound to the arg2 argument of the outer pmacro.

     (define-pmacro (foo arg1 arg2) ((.pmacro (bar) (+ arg2 bar)) arg1))
     (foo 3 4) ==> (+ 4 3)

The contents of a .pmacro are not evaluated until the pmacro is invoked.

Passing pmacros as arguments
----------------------------

Macros may be passed to other macros.

Example:

     (define-pmacro (no-ext-expr mode expr) expr)
     (define-pmacro (ext-expr mode expr) (ext mode expr))
     (define-pmacro (zext-expr mode expr) (zext mode expr))

     (define-pmacro (load-op suffix op2-op mode ext-op)
       (begin
         (dni (.sym ld suffix) (.str "ld" suffix)
     	 ()
     	 (.str "ld" suffix " $dr,@$sr")
     	 (+ OP1_2 op2-op dr sr)
     	 (set dr (ext-op WI (mem mode sr)))
     	 ())
       )
     )

     (load-op "" OP2_12 WI no-ext-expr)
     (load-op b OP2_8 QI ext-expr)
     (load-op h OP2_10 HI ext-expr)
     (load-op ub OP2_9 QI zext-expr)
     (load-op uh OP2_11 HI zext-expr)

Defining a block of locals
--------------------------

It is often handy to assign expressions to local variables, if only to improve readability. This is accomplished with the .let and .let* builtin pmacros.

.let and .let* have the same syntax:

(.let local-list expr1 [expr2 ...])

(.let* local-list expr1 [expr2 ...])

where local-list is a list of local variable assignments, with the syntax (name expr).  All variable names must be distinct.

The difference is that in .let all expressions of all locals are evaluated first and then assigned to the locals, whereas in .let* each local is evaluated and assigned in turn. This means that expressions in .let cannot refer to other locals in the .let.  If they do, they will get the values the variables had before the .let.  Also remember that symbols in pmacros are ``self-quoting'', so if a symbol isn't bound to any value, its value is the symbol name.

Example:

     (define-pmacro (load-op suffix op2-op mode ext-op)
       (.let (
              (no-ext-expr (.pmacro (mode expr) expr))
              (ext-expr (.pmacro (mode expr) (ext mode expr)))
              (zext-expr (.pmacro (mode expr) (zext mode expr)))
             )
         (begin
           (dni (.sym ld suffix) (.str "ld" suffix)
     	   ()
                (.str "ld" suffix " $dr,@$sr")
                (+ OP1_2 op2-op dr sr)
                (set dr (ext-op WI (mem mode sr)))
                ())
         )
       )
     )

     (load-op "" OP2_12 WI no-ext-expr)
     (load-op b OP2_8 QI ext-expr)
     (load-op h OP2_10 HI ext-expr)
     (load-op ub OP2_9 QI zext-expr)
     (load-op uh OP2_11 HI zext-expr)

Note that one can also assign pmacros to local variables.

Note that .let* is equivalent to a set of nested .let expressions:

     (.let* ((x 1) (y x)) y)
     ;; is equivalent to
     (.let ((x 1)) (.let ((y x)) y))

A block of statements
---------------------

Sometimes one wishes to have a list of expressions (or statements) and the context only allows one expression. This can happen, for example, in the then and else clauses of the .if builtin pmacro. Use the .begin builtin pmacro for these situations.

Syntax: (.begin [expr1 [expr2 ...]])

Each expression is evaluated in turn and the result is the result of the last expression.

Testing if something is a pmacro
--------------------------------

Sometimes one wishes to know if an argument is a pmacro or not. This is useful when one is writing a pmacro that has a parameter that is either a pmacro or is not (e.g., it could be an rtl function instead).  When the parameter is a pmacro one might like to .apply it to another argument, and if not one might like to simply construct a list of it and the other argument.

Syntax: (.pmacro? arg)

Example:

     (define-pmacro (compare a b) (if (eq a b) 1 0))
     (define-pmacro (maybe-apply fun args)
       (.if (.pmacro? fun)
            (.apply fun args)
            (.splice fun (.unsplice args))))
     (define-pmacro (gen-semantics semfun args)
       (set dest (maybe-apply semfun args)))
     (gen-semantics add (op1 op2))) ;; ==> (set dest (add op1 op2))
     (gen-semantics compare (op1 op2))) ;; ==> (set dest (if (eq op1 op2) 1 0))

Debugging utilities
===================

.print
------

Syntax: (.print expr1 [...])

Evaluate and print the supplied expressions. This is useful for debugging and logging messages.

NOTE: Strings are printed without enclosing quotes. Use dump if you want to print strings with enclosing quotes.

The result is the empty list ().

.dump
-----

Syntax: (.dump expr1 [...])

Evaluate and print the supplied expressions. This is useful for debugging and logging messages.

NOTE: Strings are printed with enclosing quotes. Use print if you want to print strings without enclosing quotes.

The result is the empty list ().

.error
------

Syntax: (.error expr1 [...])

Evaluate the supplied expressions and signal an error. The expressions are typically error messages, often with the object that caused the error.

Comparisons
===========

Builtin macros for comparing objects.

In CGEN ``true'' is represented by #t and ``false'' is represented by #f.

.equals
-------

Syntax: (.equals x y)

Return #t if x is equal to y, otherwise #f.

A ``deep'' comparison is used. I.e., if x and y are lists, list elements are recursively compared

Examples:

     (.equals "abc" "abc") --> #t
     (.equals symbol1 symbol1) --> #t
     (.equals ((1 2 3) (4 5 6)) ((1 2 3) (4 5 6))) --> #t

.andif
------

Syntax: (.andif [expr1 [expr2 ...]])

Each expression is evaluated in turn. If an expression evaluates to false (#f) then evaluation stops and the result is #f. If all expressions evaluate to non-#f, then the value of the last expression is returned.

Note that this is a special form. Just like && in C, evaluation of subsequent expressions is not done once an expression is found that evaluates to ``false''.

Examples:

     (.andif 1 #f 2) --> #f
     (.andif 1 2 3) --> 3
     (.andif) --> #t

.orif
-----

Syntax: (.orif [expr1 [expr2 ...]])

Each expression is evaluated in turn. If an expression evaluates to non-false (#f) then evaluation stops and the result is the value of the first non-#f expression. If all expressions evaluate to #f, then the result is #f.

Note that this is a special form. Just like || in C, evaluation of subsequent expressions is not done once an expression is found that evaluates to non-``false''.

Examples:

     (.orif 1 2 3) --> 1
     (.orif #f #f #f) --> #f
     (.orif) --> #f

.not
----

Syntax: (.not expr)

If expr is #f return #t. If expr is non-#f return #f.

Note that (.not 0) is not 1, it is #f!.

.eq
---

Syntax: (.eq x y)

Return ``true'' if x equals y, otherwise ``false''.

Note that this does not do a deep comparison, and can only be used with symbols, strings, and numbers. Both x and y must be the same type.

Examples:

     (.eq 1 1) -> #t
     (.eq 0 1) -> #f
     (.eq 0 one) -> error
     (.eq one one) -> #t
     (.eq zero one) -> #f
     (.eq "abc" "abc") -> #t
     (.eq "abc" "def") -> #f

.ne
---

Syntax: (.ne x y)

Return ``true'' if x does not equal y, otherwise ``false''.

Note that this does not do a deep comparison, and can only be used with symbols, strings, and numbers. Both x and y must be the same type.

Examples:

     (.ne 1 1) -> #f
     (.ne 0 1) -> #t
     (.ne 0 one) -> error
     (.ne one one) -> #f
     (.ne zero one) -> #t
     (.ne "abc" "abc") -> #f
     (.ne "abc" "def") -> #t

.lt
---

Syntax: (.lt x y)

Return ``true'' if x is less than y, otherwise ``false''.

Both x and y must be numbers.

.gt
---

Syntax: (.gt x y)

Return ``true'' if x is greater than y, otherwise ``false''.

Both x and y must be numbers.

.le
---

Syntax: (.le x y)

Return ``true'' if x is less than or equal to y, otherwise ``false''.

Both x and y must be numbers.

.ge
---

Syntax: (.ge x y)

Return ``true'' if x is greater than or equal to y, otherwise ``false''.

Both x and y must be numbers.

Arithmetic functions
====================

.add
----

Syntax: (.add x y)

Return x + y.

.sub
----

Syntax: (.sub x y)

Return x - y.

.mul
----

Syntax: (.mul x y)

Return x * y.

.div
----

Syntax: (.div x y)

Return the quotient of x divided by y.

Only integer division is supported, both x and y must be integers.

.rem
----

Syntax: (.rem x y)

Return the remainder of x divided by y.

Only integer division is supported, both x and y must be integers.

Logical functions
=================

Builtin macros for shifts and bitwise functions.

.sll
----

Syntax: (.sll x n)

Shift x left by n bits. Zeroes are shifted into the low-order bits.

n must be a non-negative integer.

.srl
----

Syntax: (.srl x n)

Shift x right by n bits.

x must be a non-negative integer. Numbers at the pmacro level have ``infinite precision'', and shifting zeroes into the high-order bits of infinite-precision negative numbers is undefined.

n must be a non-negative integer.

.sra
----

Syntax: (.sra x n)

Shift x right arithmetically by n bits. The sign bit of x is shifted into the high-order bits.

n must be a non-negative integer.

.and
----

Syntax: (.and x y)

Return the bitwise and of x and y.

.or
---

Syntax: (.or x y)

Return the bitwise or of x and y.

.xor
----

Syntax: (.xor x y)

Return the bitwise exclusive-or of x and y.

.inv
----

Syntax: (.inv x)

Return the bitwise inversion of x.

Internal use pmacros
====================

This section documents pmacros that are for internal use only. Today there's only one, .internal-test, and it is used by the testsuite.

.internal-test
--------------

Syntax: (.internal-test expr)

Execute expr as a Scheme expression and return #f if the expression returns #f and return #t if the expression returns non-#f.

This is for use in the CGEN testsuite only. See the testsuite for usage examples.