[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4. Preprocessor macros

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


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.1 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.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.2 Defining pmacros

There are two kinds of 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
)

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.3 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"

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.4 Pmacro expansion

Most(24) 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.(25)

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.(26)

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)

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.5 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:

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.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.6 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

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.7 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.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.8 Symbols and strings

There are several builtin macros for symbol and string manipulation.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.8.1 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.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.8.2 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)

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.8.3 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"

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.8.4 Convert a string to uppercase

Convert a string to uppercase with .upcase.

Syntax: (.upcase string)

Example:

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

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.8.5 Convert a string to lowercase

Convert a string to lowercase with .downcase.

Syntax: (.downcase string)

Example:

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

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.8.6 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"

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.8.7 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

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.9 Number utilities

Builtin macros for manipulating numbers.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.9.1 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

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.10 List utilities

Builtin macros for maninpulating lists.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.10.1 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 ...)’.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.10.2 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.

Also note that the arguments to .splice and .unsplice are evaluted first. Any macro invocations are first expanded, and then .unsplice is processed.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.10.3 Referencing a list element

Reference elements of a list with .ref.

Syntax: ‘(.ref list element-number)

Example:

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

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.10.4 List length

The length of a list is computed with .length.

Syntax: ‘(.length list)’.

Example:

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

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.10.5 Lists of repeated elements

Create a list of repeated elements with .replicate.

Syntax: ‘(.replicate n expr)

Example:

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

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.10.6 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)

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.10.7 car/cdr

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


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.11 Iteration utilities

Macros for iterating over lists


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.11.1 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))

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.11.2 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.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.12 Conditional macros

Macros for conditional execution.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.12.1 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.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.12.2 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.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.12.3 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.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.13 Pmacro utilities

Pmacros for working with pmacros.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.13.1 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)

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.13.2 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.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.13.3 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.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.13.4 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.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.13.5 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)

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.13.6 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))

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.13.7 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.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.13.8 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))

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.14 Debugging utilities


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.14.1 .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 ().


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.14.2 .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 ().


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.14.3 .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.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.15 Comparisons

Builtin macros for comparing objects.

In CGEN “true” is represented by #t and “false” is represented by #f.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.15.1 .equal?

Syntax: ‘(.equal? 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:

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

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.15.2 .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

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.15.3 .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

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.15.4 .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!.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.15.5 .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

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.15.6 .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

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.15.7 .lt

Syntax: ‘(.lt x y)

Return “true” if x is less than y, otherwise “false”.

Both x and y must be numbers.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.15.8 .gt

Syntax: ‘(.gt x y)

Return “true” if x is greater than y, otherwise “false”.

Both x and y must be numbers.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.15.9 .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.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.15.10 .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.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.16 Arithmetic functions


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.16.1 .add

Syntax: ‘(.add x y)

Return x + y.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.16.2 .sub

Syntax: ‘(.sub x y)

Return x - y.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.16.3 .mul

Syntax: ‘(.mul x y)

Return x * y.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.16.4 .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.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.16.5 .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.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.17 Logical functions

Builtin macros for shifts and bitwise functions.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.17.1 .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.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.17.2 .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.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.17.3 .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.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.17.4 .and

Syntax: ‘(.and x y)

Return the bitwise and of x and y.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.17.5 .or

Syntax: ‘(.or x y)

Return the bitwise or of x and y.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.17.6 .xor

Syntax: ‘(.xor x y)

Return the bitwise exclusive-or of x and y.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.17.7 .inv

Syntax: ‘(.inv x)

Return the bitwise inversion of x.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.18 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.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.18.1 .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.


[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

This document was generated by Doug Evans on January, 28 2010 using texi2html 1.78.