[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Preprocessor macros provide a way of simplifying the writing of ‘.cpu’ files.
4.1 Pmacros introduction | Introduction to pmacros | |
4.2 Defining pmacros | define-pmacro
| |
4.3 Using pmacros | Using preprocessor macros | |
4.4 Pmacro expansion | How pmacros are expanded | |
4.5 Syntactic forms | Pmacros that defer argument expansion | |
4.6 Default argument values | Specifying default values of arguments | |
4.7 Multiple result statements | Using begin
| |
4.8 Symbols and strings | ||
4.9 Number utilities | Manipulating numbers | |
4.10 List utilities | Manipulating lists | |
4.11 Iteration utilities | Iterating over lists | |
4.12 Conditional macros | Conditional execution | |
4.13 Pmacro utilities | Utilities for using macros | |
4.14 Debugging utilities | Pmacros to assist debugging | |
4.15 Comparisons | Comparing things | |
4.16 Arithmetic functions | Math | |
4.17 Logical functions | Shifts, bitwise logical functions | |
4.18 Internal use pmacros | For internal use only |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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 dni
s 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] | [ ? ] |
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] | [ ? ] |
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] | [ ? ] |
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] | [ ? ] |
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 section Defining a pmacro inline.
.let
, .let*
.
See section Defining a block of locals.
.if
.
See section Traditional if
.
.case
.
See section Traditional case
.
.cond
.
See section Extended if/elseif/else.
.begin
.
See section A block of statements.
.andif
.
See section .andif.
.orif
.
See section .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.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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] | [ ? ] |
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] | [ ? ] |
There are several builtin macros for symbol and string manipulation.
4.8.1 Symbol concatenation | The .sym builtin
| |
4.8.2 String concatenation | The .str builtin
| |
4.8.3 Convert a number to a hex | The .hex builtin
| |
4.8.4 Convert a string to uppercase | The .upcase builtin
| |
4.8.5 Convert a string to lowercase | The .downcase builtin
| |
4.8.6 Getting part of a string | The .substring builtin
| |
4.8.7 Symbol or string length | The .length builtin
|
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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] | [ ? ] |
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] | [ ? ] |
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] | [ ? ] |
Convert a string to uppercase with .upcase
.
Syntax: (.upcase string)
Example:
(.upcase "foo!") --> "FOO!" |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Convert a string to lowercase with .downcase
.
Syntax: (.downcase string)
Example:
(.downcase "BAR?") --> "bar?" |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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] | [ ? ] |
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] | [ ? ] |
Builtin macros for manipulating numbers.
4.9.1 Number generation | The .iota builtin
|
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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] | [ ? ] |
Builtin macros for maninpulating lists.
4.10.1 Creating lists | The .list builtin
| |
4.10.2 List splicing | The .splice builtin
| |
4.10.3 Referencing a list element | The .ref builtin
| |
4.10.4 List length | The .length builtin
| |
4.10.5 Lists of repeated elements | The .replicate builtin
| |
4.10.6 Finding a subset of a list | The .find builtin
| |
4.10.7 car/cdr | car, cdr, etc. from Scheme/Lisp |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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] | [ ? ] |
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] | [ ? ] |
Reference elements of a list with .ref
.
Syntax: ‘(.ref list element-number)’
Example:
(.ref (1 2 3) 1) --> 2 |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The length of a list is computed with .length
.
Syntax: ‘(.length list)’.
Example:
(.length (1 2 3)) --> 3 |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Create a list of repeated elements with .replicate
.
Syntax: ‘(.replicate n expr)’
Example:
(.replicate 4 5) --> (5 5 5 5) |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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] | [ ? ] |
CGEN provides a small set of pmacros for those familiar with Scheme/Lisp lists.
Equivalent to ‘(.ref list 0)’.
Example:
(.car (1 2 3)) --> 1 |
Return all elements of the list after the first one.
Example:
(.cdr (1 2 3)) --> (2 3) |
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 |
Return the second element of the list.
I.e., the car
of the cdr
of the list.
Example:
(.cadr (1 2 3)) --> 2 |
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) |
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) |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Macros for iterating over lists
4.11.1 Mapping a macro over a list | The .map builtin
| |
4.11.2 Iterating over a list | The .for-each builtin
|
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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] | [ ? ] |
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] | [ ? ] |
Macros for conditional execution.
4.12.1 Traditional if | The .if builtin
| |
4.12.2 Traditional case | The .case builtin
| |
4.12.3 Extended if/elseif/else | The .cond builtin
|
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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] | [ ? ] |
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] | [ ? ] |
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] | [ ? ] |
Pmacros for working with pmacros.
4.13.1 Re-evaluating an expression | The .eval builtin
| |
4.13.2 Immediate execution of a command | The .exec builtin
| |
4.13.3 Applying a pmacro to a list | The .apply builtin
| |
4.13.4 Defining a pmacro inline | The .pmacro builtin
| |
4.13.5 Passing pmacros as arguments | Passing a pmacro to another pmacro | |
4.13.6 Defining a block of locals | The .let , .let* builtins
| |
4.13.7 A block of statements | The .begin builtin
| |
4.13.8 Testing if something is a pmacro | The .pmacro? builtin
|
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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] | [ ? ] |
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] | [ ? ] |
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] | [ ? ] |
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] | [ ? ] |
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] | [ ? ] |
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] | [ ? ] |
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] | [ ? ] |
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.1 .print | Printing a diagnostic message | |
4.14.2 .dump | Printing arbitrarily complex objects | |
4.14.3 .error | Signalling an error has occurred |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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] | [ ? ] |
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] | [ ? ] |
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] | [ ? ] |
Builtin macros for comparing objects.
In CGEN “true” is represented by #t
and “false” is represented by #f
.
4.15.1 .equal? | Deep comparison | |
4.15.2 .andif | && in C | |
4.15.3 .orif | || in C | |
4.15.4 .not | ! in C | |
4.15.5 .eq | Shallow comparison | |
4.15.6 .ne | Shallow comparison | |
4.15.7 .lt | Less than | |
4.15.8 .gt | Greater than | |
4.15.9 .le | Less than or equal to | |
4.15.10 .ge | Greater than or equal to |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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] | [ ? ] |
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] | [ ? ] |
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] | [ ? ] |
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] | [ ? ] |
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] | [ ? ] |
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] | [ ? ] |
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] | [ ? ] |
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] | [ ? ] |
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] | [ ? ] |
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.1 .add | Addition | |
4.16.2 .sub | Subtraction | |
4.16.3 .mul | Multiplication | |
4.16.4 .div | Integer division | |
4.16.5 .rem | Integer remainder |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Syntax: ‘(.add x y)’
Return x
+ y
.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Syntax: ‘(.sub x y)’
Return x
- y
.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Syntax: ‘(.mul x y)’
Return x
* y
.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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] | [ ? ] |
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] | [ ? ] |
Builtin macros for shifts and bitwise functions.
4.17.1 .sll | Shift left logical | |
4.17.2 .srl | Shift right logical | |
4.17.3 .sra | Shift right arithmetic | |
4.17.4 .and | Bitwise and | |
4.17.5 .or | Bitwise or | |
4.17.6 .xor | Bitwise exclusive-or | |
4.17.7 .inv | Bitwise inversion |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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] | [ ? ] |
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] | [ ? ] |
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] | [ ? ] |
Syntax: ‘(.and x y)’
Return the bitwise and
of x
and y
.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Syntax: ‘(.or x y)’
Return the bitwise or
of x
and y
.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Syntax: ‘(.xor x y)’
Return the bitwise exclusive-or
of x
and y
.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Syntax: ‘(.inv x)’
Return the bitwise inversion
of x
.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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] | [ ? ] |
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.