(→Segment selection) |
|||
(58 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
{{TOCright}} | {{TOCright}} | ||
− | < | + | <runphp> |
− | echo "<style >"; | + | echo "<style>"; |
− | echo ".pfrow { width: 100px; background: # | + | echo ".pfrow { width: 100px; background: #f5f5f5; padding-left: 5px; padding-right: 5px; text-align: left; font-weight: normal; vertical-align: top; border-style: solid; border-width: 1px; border-color: #b5b4b3; }"; |
− | echo ".pfdesc { width: | + | echo ".pfdesc { width: 500px; background: #f5f5f5; padding-left: 5px; padding-right: 5px; text-align: left; font-weight: normal; vertical-align: top; border-style: solid; border-width: 1px; border-color: #b5b4b3; }"; |
echo "</style>"; | echo "</style>"; | ||
− | </ | + | </runphp> |
The Postfix reference guide contains information about the structure and operations of the stack machine. | The Postfix reference guide contains information about the structure and operations of the stack machine. | ||
Line 12: | Line 12: | ||
The current postfix code generator class maintains the stack machine abstraction, but does not rely on macros. Instead, it defines an interface to be used by semantic analysers, as defined by a strategy pattern (Gamma et al., 1995). Specific implementations provide the realization of the postfix commands for a particular target machine. Since it is written in C++, it's very easy to extend to new needs and implementations (new target machines). | The current postfix code generator class maintains the stack machine abstraction, but does not rely on macros. Instead, it defines an interface to be used by semantic analysers, as defined by a strategy pattern (Gamma et al., 1995). Specific implementations provide the realization of the postfix commands for a particular target machine. Since it is written in C++, it's very easy to extend to new needs and implementations (new target machines). | ||
− | Like the original postfix code generator, the current abstraction uses an architecture based on a stack machine, hence the name | + | Like the original postfix code generator, the current abstraction uses an architecture based on a stack machine, hence the name "postfix", and three registers. |
# IP -- the instruction pointer -- indicates the position of the next instruction to be executed; | # IP -- the instruction pointer -- indicates the position of the next instruction to be executed; | ||
# SP -- the stack pointer -- indicates the position of the element currently at the stack top; | # SP -- the stack pointer -- indicates the position of the element currently at the stack top; | ||
# FP -- the frame pointer -- indicates the position of the activation register of the function currently being executed. | # FP -- the frame pointer -- indicates the position of the activation register of the function currently being executed. | ||
− | In | + | In the following tables, the "stack" columns present the results of the actions on the values at the top of the stack. Note that only elements relevant in a given context, i.e., that of the postfix instruction being executed, are shown. The notation '''#length''' represents a set of ''length'' consecutive bytes in the stack, i.e., a vector. |
− | + | {| | |
+ | ! class="pfrow" | OPERATION | ||
+ | ! class="pfrow" | stack before | ||
+ | ! class="pfrow" | stack after | ||
+ | ! class="pfdesc" | Description of actions | ||
+ | |} | ||
− | + | Consider the following fictitious example: | |
− | + | {| | |
+ | ! class="pfrow" | FAKE | ||
+ | ! class="pfrow" | $ a #8 b | ||
+ | ! class="pfrow" | $ a b | ||
+ | ! class="pfdesc" | This is a fake operation | ||
+ | |} | ||
+ | |||
+ | In this example, before the FAKE operation, the stack had at its top '''b''', followed by eight bytes, followed by '''a'''. After executing the FAKE operation (which used those elements in some way), the stack has at its top '''b''', followed by '''a'''. The symbol '''$''' is used to denote the point in the stack not affected by the current operation (this could be the top if the stack were empty). | ||
The following groups of operations are available in the Postfix interface: | The following groups of operations are available in the Postfix interface: | ||
Line 29: | Line 41: | ||
== Segments, Values, and Labels == | == Segments, Values, and Labels == | ||
− | === Segment | + | === Segment selection === |
− | These operations | + | These operations select various segments. They do not affect the stack. |
{| | {| | ||
! class="pfrow" | BSS | ! class="pfrow" | BSS | ||
− | | | + | ! class="pfrow" | |
− | | | + | ! class="pfrow" | |
− | | Specifies/selects the data segment for uninitialized values | + | ! class="pfdesc" | Specifies/selects the data segment for uninitialized values |
|- | |- | ||
! class="pfrow" | DATA | ! class="pfrow" | DATA | ||
− | | | + | ! class="pfrow" | |
− | | | + | ! class="pfrow" | |
− | | Specifies/selects the data segment for initialized values | + | ! class="pfdesc" | Specifies/selects the data segment for initialized values |
|- | |- | ||
! class="pfrow" | RODATA | ! class="pfrow" | RODATA | ||
− | | | + | ! class="pfrow" | |
− | | | + | ! class="pfrow" | |
− | | Specifies/selects the data segment for initialized constant values | + | ! class="pfdesc" | Specifies/selects the data segment for initialized constant values |
|- | |- | ||
! class="pfrow" | TEXT | ! class="pfrow" | TEXT | ||
− | | | + | ! class="pfrow" | |
− | | | + | ! class="pfrow" | |
− | | Specifies/selects the text (code) segment | + | ! class="pfdesc" | Specifies/selects the text (code) segment (default) |
+ | |- | ||
+ | ! class="pfrow" | TEXT name | ||
+ | ! class="pfrow" | | ||
+ | ! class="pfrow" | | ||
+ | ! class="pfdesc" | Specifies/selects the text (code) segment with name ''name'' | ||
+ | |- | ||
+ | ! class="pfrow" | TEXT number | ||
+ | ! class="pfrow" | | ||
+ | ! class="pfrow" | | ||
+ | ! class="pfdesc" | Specifies/selects the text (code) segment with name ''number'' | ||
|} | |} | ||
Line 60: | Line 82: | ||
{| | {| | ||
− | ! class="pfrow" | | + | ! class="pfrow" | SALLOC size |
− | | | + | ! class="pfrow" | |
− | | | + | ! class="pfrow" | |
− | | Declares an uninitialized vector with length '''size''' (in bytes) | + | ! class="pfdesc" | Declares an uninitialized vector with length '''size''' (in bytes) |
|- | |- | ||
− | ! class="pfrow" | | + | ! class="pfrow" | SSHORT value |
− | | | + | ! class="pfrow" | |
− | | | + | ! class="pfrow" | |
− | | Declares a static 16-bit integer '''value''' | + | ! class="pfdesc" | Declares a static 16-bit integer '''value''' |
|- | |- | ||
− | ! class="pfrow" | | + | ! class="pfrow" | SBYTE value |
− | | | + | ! class="pfrow" | |
− | | | + | ! class="pfrow" | |
− | | Declares a static 8-bit character '''value''' | + | ! class="pfdesc" | Declares a static 8-bit character '''value''' |
|- | |- | ||
− | ! class="pfrow" | | + | ! class="pfrow" | SINT value |
− | | | + | ! class="pfrow" | |
− | | | + | ! class="pfrow" | |
− | | Declares a static 32-bit integer '''value''' | + | ! class="pfdesc" | Declares a static 32-bit integer '''value''' |
|- | |- | ||
− | ! class="pfrow" | | + | ! class="pfrow" | SDOUBLE value |
− | | | + | ! class="pfrow" | |
− | | | + | ! class="pfrow" | |
− | | Declares a static double precision (64-bit) floating point '''value''' | + | ! class="pfdesc" | Declares a static double precision (64-bit) floating point '''value''' |
|- | |- | ||
− | ! class="pfrow" | | + | ! class="pfrow" | SFLOAT value |
− | | | + | ! class="pfrow" | |
− | | | + | ! class="pfrow" | |
− | | Declares a static simple precision (32-bit) floating point '''value''' | + | ! class="pfdesc" | Declares a static simple precision (32-bit) floating point '''value''' |
|- | |- | ||
− | ! class="pfrow" | | + | ! class="pfrow" | SADDR name |
− | | | + | ! class="pfrow" | |
− | | | + | ! class="pfrow" | |
− | | Declares a name for an address (i.e., declares the address associated with '''name''') | + | ! class="pfdesc" | Declares a name for an address (i.e., declares the address associated with '''name''') |
|- | |- | ||
− | ! class="pfrow" | | + | ! class="pfrow" | SSTRING string |
− | | | + | ! class="pfrow" | |
− | | | + | ! class="pfrow" | |
− | | Declares a static NULL-terminated character '''string''' (C-like) (may contain special characters) | + | ! class="pfdesc" | Declares a static NULL-terminated character '''string''' (C-like) (may contain special characters) |
|} | |} | ||
Line 107: | Line 129: | ||
{| | {| | ||
! class="pfrow" | ALIGN | ! class="pfrow" | ALIGN | ||
− | | | + | ! class="pfrow" | |
− | | | + | ! class="pfrow" | |
− | | Forces the alignment of code or data | + | ! class="pfdesc" | Forces the alignment of code or data |
|- | |- | ||
! class="pfrow" | LABEL name | ! class="pfrow" | LABEL name | ||
− | | | + | ! class="pfrow" | |
− | | | + | ! class="pfrow" | |
− | | Generates a new label '''name''' | + | ! class="pfdesc" | Generates a new label '''name''' |
|- | |- | ||
! class="pfrow" | EXTERN name | ! class="pfrow" | EXTERN name | ||
− | | | + | ! class="pfrow" | |
− | | | + | ! class="pfrow" | |
− | | Declares '''name''' as a symbol externally defined, i.e., defined in another compilation module | + | ! class="pfdesc" | Declares '''name''' as a symbol externally defined, i.e., defined in another compilation module |
|- | |- | ||
! class="pfrow" | GLOBAL name, type | ! class="pfrow" | GLOBAL name, type | ||
− | | | + | ! class="pfrow" | |
− | | | + | ! class="pfrow" | |
− | | Declares a '''name''' with a given '''type''' (see below) -- the declaration of a name must preceed its definition | + | ! class="pfdesc" | Declares a '''name''' with a given '''type''' (see below) -- the declaration of a name must preceed its definition |
|} | |} | ||
<!-- COMMON value || || || Declares that the name is common to other modules--> | <!-- COMMON value || || || Declares that the name is common to other modules--> | ||
Line 131: | Line 153: | ||
Global names may be of different types. These labels are to be used to generate the types needed for the second argument of '''GLOBAL'''. | Global names may be of different types. These labels are to be used to generate the types needed for the second argument of '''GLOBAL'''. | ||
− | + | * NONE - Unknown type | |
− | + | * FUNC - Name/label corresponds to a function | |
− | + | * OBJ - Name/label corresponds to an object (data) | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
== Addressing, Loading and Storing == | == Addressing, Loading and Storing == | ||
Line 159: | Line 167: | ||
! class="pfrow" | $ | ! class="pfrow" | $ | ||
! class="pfrow" | $ name | ! class="pfrow" | $ name | ||
− | | Absolute addressing: load address of '''name''' | + | ! class="pfdesc" | Absolute addressing: load address of '''name''' |
|- | |- | ||
! class="pfrow" | ADDRA name | ! class="pfrow" | ADDRA name | ||
! class="pfrow" | $ value | ! class="pfrow" | $ value | ||
! class="pfrow" | $ | ! class="pfrow" | $ | ||
− | | Absolute addressing: store '''value''' to '''name''' | + | ! class="pfdesc" | Absolute addressing: store '''value''' to '''name''' |
|- | |- | ||
! class="pfrow" | ADDRV name | ! class="pfrow" | ADDRV name | ||
! class="pfrow" | $ | ! class="pfrow" | $ | ||
! class="pfrow" | $ [name] | ! class="pfrow" | $ [name] | ||
− | | Absolute addressing: load value at '''name''' | + | ! class="pfdesc" | Absolute addressing: load value at '''name''' |
|- | |- | ||
! class="pfrow" | LOCAL offset | ! class="pfrow" | LOCAL offset | ||
! class="pfrow" | $ | ! class="pfrow" | $ | ||
! class="pfrow" | $ fp+offset | ! class="pfrow" | $ fp+offset | ||
− | | Local addressing: load address of '''offset''' | + | ! class="pfdesc" | Local addressing: load address of '''offset''' |
|- | |- | ||
! class="pfrow" | LOCA offset | ! class="pfrow" | LOCA offset | ||
! class="pfrow" | $ a | ! class="pfrow" | $ a | ||
! class="pfrow" | $ | ! class="pfrow" | $ | ||
− | | Local addressing: writes '''a''' to '''offset''' | + | ! class="pfdesc" | Local addressing: writes '''a''' to '''offset''' |
|- | |- | ||
! class="pfrow" | LOCV offset | ! class="pfrow" | LOCV offset | ||
! class="pfrow" | $ | ! class="pfrow" | $ | ||
! class="pfrow" | $ [fp+offset] | ! class="pfrow" | $ [fp+offset] | ||
− | | Local addressing: load value at '''offset''' | + | ! class="pfdesc" | Local addressing: load value at '''offset''' |
|} | |} | ||
− | ADDRA, ADDRV, LOCA, LOCV are functionally equivalent to ADDR+ | + | ADDRA, ADDRV, LOCA, LOCV are functionally equivalent to ADDR+STINT, ADDR+LDINT, LOCAL+STINT, LOCAL+LDINT, but the generated code is more efficient. They are compound operations (i.e., they contain not only the addressing part, but also the load/store part as well). Note that the postfix_writer visitor is, in general, incapable of generating these instructions. |
=== Load operations === | === Load operations === | ||
Line 194: | Line 202: | ||
{| | {| | ||
− | ! class="pfrow" | | + | ! class="pfrow" | LDINT |
! class="pfrow" | $ addr | ! class="pfrow" | $ addr | ||
! class="pfrow" | $ [addr] | ! class="pfrow" | $ [addr] | ||
− | | Loads | + | ! class="pfdesc" | Loads 4 bytes (int) |
|- | |- | ||
− | ! class="pfrow" | | + | ! class="pfrow" | LDFLOAT |
! class="pfrow" | $ addr | ! class="pfrow" | $ addr | ||
! class="pfrow" | $ [addr] | ! class="pfrow" | $ [addr] | ||
− | | Loads | + | ! class="pfdesc" | Loads 4 bytes (float) |
|- | |- | ||
− | ! class="pfrow" | | + | ! class="pfrow" | LDDOUBLE |
! class="pfrow" | $ addr | ! class="pfrow" | $ addr | ||
! class="pfrow" | $ [addr] | ! class="pfrow" | $ [addr] | ||
− | | Loads | + | ! class="pfdesc" | Loads 8 bytes (double) |
|- | |- | ||
− | ! class="pfrow" | | + | ! class="pfrow" | LDBYTE |
! class="pfrow" | $ addr | ! class="pfrow" | $ addr | ||
! class="pfrow" | $ [addr] | ! class="pfrow" | $ [addr] | ||
− | | Loads 1 byte ( | + | ! class="pfdesc" | Loads 1 byte (char) |
|- | |- | ||
− | ! class="pfrow" | | + | ! class="pfrow" | LDSHORT |
! class="pfrow" | $ addr | ! class="pfrow" | $ addr | ||
! class="pfrow" | $ [addr] | ! class="pfrow" | $ [addr] | ||
− | + | ! class="pfdesc" | Loads 2 bytes (short) | |
− | |||
− | |||
− | |||
− | ! class=" | ||
− | | Loads 2 bytes ( | ||
|} | |} | ||
Line 230: | Line 233: | ||
{| | {| | ||
− | ! class="pfrow" | | + | ! class="pfrow" | STINT |
+ | ! class="pfrow" | $ val addr | ||
+ | ! class="pfrow" | $ | ||
+ | ! class="pfdesc" | Stores 4 bytes (int) | ||
+ | |- | ||
+ | ! class="pfrow" | STFLOAT | ||
! class="pfrow" | $ val addr | ! class="pfrow" | $ val addr | ||
! class="pfrow" | $ | ! class="pfrow" | $ | ||
− | | Stores 4 bytes ( | + | ! class="pfdesc" | Stores 4 bytes (float) |
|- | |- | ||
− | ! class="pfrow" | | + | ! class="pfrow" | STDOUBLE |
! class="pfrow" | $ val addr | ! class="pfrow" | $ val addr | ||
! class="pfrow" | $ | ! class="pfrow" | $ | ||
− | | Stores 8 bytes (double) | + | ! class="pfdesc" | Stores 8 bytes (double) |
|- | |- | ||
− | ! class="pfrow" | | + | ! class="pfrow" | STBYTE |
! class="pfrow" | $ val addr | ! class="pfrow" | $ val addr | ||
! class="pfrow" | $ | ! class="pfrow" | $ | ||
− | | Stores 1 byte (char) | + | ! class="pfdesc" | Stores 1 byte (char) |
|- | |- | ||
− | ! class="pfrow" | | + | ! class="pfrow" | STSHORT |
! class="pfrow" | $ val addr | ! class="pfrow" | $ val addr | ||
! class="pfrow" | $ | ! class="pfrow" | $ | ||
− | | Stores 2 bytes (short) | + | ! class="pfdesc" | Stores 2 bytes (short) |
|} | |} | ||
Line 254: | Line 262: | ||
{| | {| | ||
− | ! class="pfrow" | | + | ! class="pfrow" | DUP32 |
! class="pfrow" | $ a | ! class="pfrow" | $ a | ||
! class="pfrow" | $ a a | ! class="pfrow" | $ a a | ||
− | | Duplicates the 32-bit value at the top of the stack | + | ! class="pfdesc" | Duplicates the 32-bit value at the top of the stack |
|- | |- | ||
− | ! class="pfrow" | | + | ! class="pfrow" | DUP64 |
! class="pfrow" | $ a | ! class="pfrow" | $ a | ||
! class="pfrow" | $ a a | ! class="pfrow" | $ a a | ||
− | | Duplicates the 64-bit value at the top of the stack | + | ! class="pfdesc" | Duplicates the 64-bit value at the top of the stack |
|- | |- | ||
! class="pfrow" | INT value | ! class="pfrow" | INT value | ||
! class="pfrow" | $ | ! class="pfrow" | $ | ||
! class="pfrow" | $ value | ! class="pfrow" | $ value | ||
− | | Pushes an integer '''value''' | + | ! class="pfdesc" | Pushes an integer '''value''' |
+ | |- | ||
+ | ! class="pfrow" | FLOAT value | ||
+ | ! class="pfrow" | $ | ||
+ | ! class="pfrow" | $ value | ||
+ | ! class="pfdesc" | Pushes a 4-byte float '''value''' (single precision) | ||
+ | |- | ||
+ | ! class="pfrow" | DOUBLE value | ||
+ | ! class="pfrow" | $ | ||
+ | ! class="pfrow" | $ value | ||
+ | ! class="pfdesc" | Pushes an 8-byte float '''value''' (double precision) | ||
|- | |- | ||
! class="pfrow" | SP | ! class="pfrow" | SP | ||
! class="pfrow" | $ | ! class="pfrow" | $ | ||
− | ! class="pfrow" | sp | + | ! class="pfrow" | $ sp |
− | | Pushes the value of the stack pointer | + | ! class="pfdesc" | Pushes the value of the stack pointer |
+ | |- | ||
+ | ! class="pfrow" | SWAP32 | ||
+ | ! class="pfrow" | $ a b | ||
+ | ! class="pfrow" | $ b a | ||
+ | ! class="pfdesc" | Swaps the two 32-bit values at the top of the stack | ||
|- | |- | ||
− | ! class="pfrow" | | + | ! class="pfrow" | SWAP64 |
! class="pfrow" | $ a b | ! class="pfrow" | $ a b | ||
! class="pfrow" | $ b a | ! class="pfrow" | $ b a | ||
− | | Swaps the two | + | ! class="pfdesc" | Swaps the two 64-bit values at the top of the stack |
|- | |- | ||
! class="pfrow" | ALLOC | ! class="pfrow" | ALLOC | ||
! class="pfrow" | $ bytes | ! class="pfrow" | $ bytes | ||
! class="pfrow" | $ #bytes | ! class="pfrow" | $ #bytes | ||
− | | Allocates in the stack an array with size '''bytes'''. Since this operation alters the meaning of offsets in the stack, care should be taken when local variables exist. | + | ! class="pfdesc" | Allocates in the stack an array with size '''bytes'''. Since this operation alters the meaning of offsets in the stack, care should be taken when local variables exist. |
|} | |} | ||
Line 295: | Line 318: | ||
! class="pfrow" | $ a | ! class="pfrow" | $ a | ||
! class="pfrow" | $ -a | ! class="pfrow" | $ -a | ||
− | | Negation (symmetric) of integer value | + | ! class="pfdesc" | Negation (symmetric) of integer value |
|- | |- | ||
! class="pfrow" | ADD | ! class="pfrow" | ADD | ||
! class="pfrow" | $ a b | ! class="pfrow" | $ a b | ||
! class="pfrow" | $ a+b | ! class="pfrow" | $ a+b | ||
− | | Integer sum of two integer values | + | ! class="pfdesc" | Integer sum of two integer values |
|- | |- | ||
! class="pfrow" | SUB | ! class="pfrow" | SUB | ||
! class="pfrow" | $ a b | ! class="pfrow" | $ a b | ||
! class="pfrow" | $ a-b | ! class="pfrow" | $ a-b | ||
− | | Integer subtraction of two integer values | + | ! class="pfdesc" | Integer subtraction of two integer values |
|- | |- | ||
! class="pfrow" | MUL | ! class="pfrow" | MUL | ||
! class="pfrow" | $ a b | ! class="pfrow" | $ a b | ||
! class="pfrow" | $ a*b | ! class="pfrow" | $ a*b | ||
− | | Integer multiplication of two integer values | + | ! class="pfdesc" | Integer multiplication of two integer values |
|- | |- | ||
! class="pfrow" | DIV | ! class="pfrow" | DIV | ||
! class="pfrow" | $ a b | ! class="pfrow" | $ a b | ||
! class="pfrow" | $ a/b | ! class="pfrow" | $ a/b | ||
− | | Integer division of two integer values | + | ! class="pfdesc" | Integer division of two integer values |
|- | |- | ||
! class="pfrow" | MOD | ! class="pfrow" | MOD | ||
! class="pfrow" | $ a b | ! class="pfrow" | $ a b | ||
! class="pfrow" | $ a%b | ! class="pfrow" | $ a%b | ||
− | | Remainder of the integer division of two integer values | + | ! class="pfdesc" | Remainder of the integer division of two integer values |
|- | |- | ||
! class="pfrow" | UDIV | ! class="pfrow" | UDIV | ||
! class="pfrow" | $ a b | ! class="pfrow" | $ a b | ||
! class="pfrow" | $ a/b | ! class="pfrow" | $ a/b | ||
− | | Integer division of two natural (unsigned) integer values | + | ! class="pfdesc" | Integer division of two natural (unsigned) integer values |
|- | |- | ||
! class="pfrow" | UMOD | ! class="pfrow" | UMOD | ||
! class="pfrow" | $ a b | ! class="pfrow" | $ a b | ||
! class="pfrow" | $ a%b | ! class="pfrow" | $ a%b | ||
− | | Remainder of the integer division of two natural (unsigned) integer values. | + | ! class="pfdesc" | Remainder of the integer division of two natural (unsigned) integer values. |
|} | |} | ||
=== Floating point operations === | === Floating point operations === | ||
− | These operations take double precision floating | + | These operations take double precision floating point operands. |
{| | {| | ||
Line 341: | Line 364: | ||
! class="pfrow" | $ a | ! class="pfrow" | $ a | ||
! class="pfrow" | $ -a | ! class="pfrow" | $ -a | ||
− | | Negation (symmetric) | + | ! class="pfdesc" | Negation (symmetric) |
|- | |- | ||
! class="pfrow" | DADD | ! class="pfrow" | DADD | ||
! class="pfrow" | $ a b | ! class="pfrow" | $ a b | ||
! class="pfrow" | $ a+b | ! class="pfrow" | $ a+b | ||
− | | Sum | + | ! class="pfdesc" | Sum |
|- | |- | ||
! class="pfrow" | DSUB | ! class="pfrow" | DSUB | ||
! class="pfrow" | $ a b | ! class="pfrow" | $ a b | ||
! class="pfrow" | $ a-b | ! class="pfrow" | $ a-b | ||
− | | Subtraction | + | ! class="pfdesc" | Subtraction |
|- | |- | ||
! class="pfrow" | DMUL | ! class="pfrow" | DMUL | ||
! class="pfrow" | $ a b | ! class="pfrow" | $ a b | ||
! class="pfrow" | $ a*b | ! class="pfrow" | $ a*b | ||
− | | Multiplication | + | ! class="pfdesc" | Multiplication |
|- | |- | ||
! class="pfrow" | DDIV | ! class="pfrow" | DDIV | ||
! class="pfrow" | $ a b | ! class="pfrow" | $ a b | ||
! class="pfrow" | $ a/b | ! class="pfrow" | $ a/b | ||
− | | Division | + | ! class="pfdesc" | Division |
|} | |} | ||
Line 370: | Line 393: | ||
! class="pfrow" | $ address | ! class="pfrow" | $ address | ||
! class="pfrow" | $ address | ! class="pfrow" | $ address | ||
− | | Adds '''delta''' to the value at the '''address''' at the top of the stack, i.e. ''[address]'' becomes ''[address]+delta'' | + | ! class="pfdesc" | Adds '''delta''' to the value at the '''address''' at the top of the stack, i.e. ''[address]'' becomes ''[address]+delta'' |
|- | |- | ||
! class="pfrow" | DECR delta | ! class="pfrow" | DECR delta | ||
! class="pfrow" | $ address | ! class="pfrow" | $ address | ||
! class="pfrow" | $ address | ! class="pfrow" | $ address | ||
− | | Subtracts '''delta''' to the value at the '''address''' at the top of the stack, i.e. ''[address]'' becomes ''[address]-delta'' | + | ! class="pfdesc" | Subtracts '''delta''' to the value at the '''address''' at the top of the stack, i.e. ''[address]'' becomes ''[address]-delta'' |
|} | |} | ||
Line 386: | Line 409: | ||
! class="pfrow" | $ d | ! class="pfrow" | $ d | ||
! class="pfrow" | $ f | ! class="pfrow" | $ f | ||
− | | Converts from double precision (64-bit) to single precision (32-bit) floating point | + | ! class="pfdesc" | Converts from double precision (64-bit) to single precision (32-bit) floating point |
|- | |- | ||
! class="pfrow" | D2I | ! class="pfrow" | D2I | ||
! class="pfrow" | $ d | ! class="pfrow" | $ d | ||
! class="pfrow" | $ i | ! class="pfrow" | $ i | ||
− | | Converts from double precision (64-bit) floating point to integer (32-bit) | + | ! class="pfdesc" | Converts from double precision (64-bit) floating point to integer (32-bit) |
|- | |- | ||
! class="pfrow" | F2D | ! class="pfrow" | F2D | ||
! class="pfrow" | $ f | ! class="pfrow" | $ f | ||
! class="pfrow" | $ d | ! class="pfrow" | $ d | ||
− | | Converts from simple precision (32-bit) to double precision (64-bit) floating point | + | ! class="pfdesc" | Converts from simple precision (32-bit) to double precision (64-bit) floating point |
|- | |- | ||
! class="pfrow" | I2D | ! class="pfrow" | I2D | ||
! class="pfrow" | $ i | ! class="pfrow" | $ i | ||
! class="pfrow" | $ d | ! class="pfrow" | $ d | ||
− | | Converts from integer (32-bit) to double precision (64-bit) floating point | + | ! class="pfdesc" | Converts from integer (32-bit) to double precision (64-bit) floating point |
|} | |} | ||
Line 408: | Line 431: | ||
=== Integer comparison instructions === | === Integer comparison instructions === | ||
− | The comparison instructions are binary operations that leave at the top of the stack 0 (zero) or 1 (one), depending on the | + | The comparison instructions are binary operations that leave at the top of the stack 0 (zero) or 1 (one), depending on the result of the comparison: respectively, '''false''' or '''true'''. The value may be directly used to perform conditional jumps (e.g., JZ, JNZ), that use the value of the top of the stack instead of relying on special processor registers ("flags"). |
{| | {| | ||
Line 414: | Line 437: | ||
! class="pfrow" | $ a b | ! class="pfrow" | $ a b | ||
! class="pfrow" | $ a≡b | ! class="pfrow" | $ a≡b | ||
− | | ''equal to'' | + | ! class="pfdesc" | ''equal to'' |
|- | |- | ||
! class="pfrow" | NE | ! class="pfrow" | NE | ||
! class="pfrow" | $ a b | ! class="pfrow" | $ a b | ||
! class="pfrow" | $ a≠b | ! class="pfrow" | $ a≠b | ||
− | | ''not equal to'' | + | ! class="pfdesc" | ''not equal to'' |
|} | |} | ||
Line 426: | Line 449: | ||
! class="pfrow" | $ a b | ! class="pfrow" | $ a b | ||
! class="pfrow" | $ a>b | ! class="pfrow" | $ a>b | ||
− | | ''greater than'' | + | ! class="pfdesc" | ''greater than'' |
|- | |- | ||
! class="pfrow" | GE | ! class="pfrow" | GE | ||
! class="pfrow" | $ a b | ! class="pfrow" | $ a b | ||
! class="pfrow" | $ a≥b | ! class="pfrow" | $ a≥b | ||
− | | ''greater than or equal to'' | + | ! class="pfdesc" | ''greater than or equal to'' |
|- | |- | ||
! class="pfrow" | LE | ! class="pfrow" | LE | ||
! class="pfrow" | $ a b | ! class="pfrow" | $ a b | ||
! class="pfrow" | $ a≤b | ! class="pfrow" | $ a≤b | ||
− | | ''less than or equal to'' | + | ! class="pfdesc" | ''less than or equal to'' |
|- | |- | ||
! class="pfrow" | LT | ! class="pfrow" | LT | ||
! class="pfrow" | $ a b | ! class="pfrow" | $ a b | ||
! class="pfrow" | $ a<b | ! class="pfrow" | $ a<b | ||
− | | ''less than'' | + | ! class="pfdesc" | ''less than'' |
|} | |} | ||
Line 450: | Line 473: | ||
! class="pfrow" | $ a b | ! class="pfrow" | $ a b | ||
! class="pfrow" | $ a>b | ! class="pfrow" | $ a>b | ||
− | | ''greater than'' for unsigned integers | + | ! class="pfdesc" | ''greater than'' for unsigned integers |
|- | |- | ||
! class="pfrow" | UGE | ! class="pfrow" | UGE | ||
! class="pfrow" | $ a b | ! class="pfrow" | $ a b | ||
! class="pfrow" | $ a≥b | ! class="pfrow" | $ a≥b | ||
− | | ''greater than or equal to'' for unsigned integers | + | ! class="pfdesc" | ''greater than or equal to'' for unsigned integers |
|- | |- | ||
! class="pfrow" | ULE | ! class="pfrow" | ULE | ||
! class="pfrow" | $ a b | ! class="pfrow" | $ a b | ||
! class="pfrow" | $ a≤b | ! class="pfrow" | $ a≤b | ||
− | | ''less than or equal to'' for unsigned integers | + | ! class="pfdesc" | ''less than or equal to'' for unsigned integers |
|- | |- | ||
! class="pfrow" | ULT | ! class="pfrow" | ULT | ||
! class="pfrow" | $ a b | ! class="pfrow" | $ a b | ||
! class="pfrow" | $ a<b | ! class="pfrow" | $ a<b | ||
− | | ''less than'' for unsigned integers | + | ! class="pfdesc" | ''less than'' for unsigned integers |
|} | |} | ||
Line 475: | Line 498: | ||
! class="pfrow" | DCMP | ! class="pfrow" | DCMP | ||
! class="pfrow" | $ a b | ! class="pfrow" | $ a b | ||
− | ! class="pfrow" | i | + | ! class="pfrow" | $ i |
− | | "compare" -- i<0, a<b; i≡0, a≡b; i>0, a>b | + | ! class="pfdesc" | "compare" -- i<0, a<b; i≡0, a≡b; i>0, a>b |
|} | |} | ||
− | == | + | == Bitwise Operations == |
{| | {| | ||
Line 485: | Line 508: | ||
! class="pfrow" | $ a | ! class="pfrow" | $ a | ||
! class="pfrow" | $ ~a | ! class="pfrow" | $ ~a | ||
− | | | + | ! class="pfdesc" | Bitwise negation, i.e., one's complement |
|- | |- | ||
! class="pfrow" | AND | ! class="pfrow" | AND | ||
! class="pfrow" | $ a b | ! class="pfrow" | $ a b | ||
! class="pfrow" | $ a∧b | ! class="pfrow" | $ a∧b | ||
− | | | + | ! class="pfdesc" | Bitwise AND operation |
|- | |- | ||
! class="pfrow" | OR | ! class="pfrow" | OR | ||
! class="pfrow" | $ a b | ! class="pfrow" | $ a b | ||
! class="pfrow" | $ a∨b | ! class="pfrow" | $ a∨b | ||
− | | | + | ! class="pfdesc" | Bitwise OR operation |
|- | |- | ||
! class="pfrow" | XOR | ! class="pfrow" | XOR | ||
! class="pfrow" | $ a b | ! class="pfrow" | $ a b | ||
! class="pfrow" | $ a⊕b | ! class="pfrow" | $ a⊕b | ||
− | | | + | ! class="pfdesc" | Bitwise XOR (exclusive OR) operation |
|} | |} | ||
Line 511: | Line 534: | ||
! class="pfrow" | $ value nbits | ! class="pfrow" | $ value nbits | ||
! class="pfrow" | $ value<rl>bits | ! class="pfrow" | $ value<rl>bits | ||
− | | Rotate '''value''' '''nbits''' to the left | + | ! class="pfdesc" | Rotate '''value''' '''nbits''' to the left |
|- | |- | ||
! class="pfrow" | ROTR | ! class="pfrow" | ROTR | ||
! class="pfrow" | $ value nbits | ! class="pfrow" | $ value nbits | ||
! class="pfrow" | $ value<rr>bits | ! class="pfrow" | $ value<rr>bits | ||
− | | Rotate '''value''' '''nbits''' to the right | + | ! class="pfdesc" | Rotate '''value''' '''nbits''' to the right |
|- | |- | ||
! class="pfrow" | SHTL | ! class="pfrow" | SHTL | ||
! class="pfrow" | $ value nbits | ! class="pfrow" | $ value nbits | ||
! class="pfrow" | $ value<<bits | ! class="pfrow" | $ value<<bits | ||
− | | Shift '''value''' '''nbits''' to the left | + | ! class="pfdesc" | Shift '''value''' '''nbits''' to the left |
|- | |- | ||
! class="pfrow" | SHTRU | ! class="pfrow" | SHTRU | ||
! class="pfrow" | $ value nbits | ! class="pfrow" | $ value nbits | ||
! class="pfrow" | $ value>>bits | ! class="pfrow" | $ value>>bits | ||
− | | Shift '''value''' '''nbits''' to the right (unsigned) | + | ! class="pfdesc" | Shift '''value''' '''nbits''' to the right (unsigned) |
|- | |- | ||
! class="pfrow" | SHTRS | ! class="pfrow" | SHTRS | ||
! class="pfrow" | $ value nbits | ! class="pfrow" | $ value nbits | ||
! class="pfrow" | $ value>>>bits | ! class="pfrow" | $ value>>>bits | ||
− | | Shift '''value''' '''nbits''' to the right (signed) | + | ! class="pfdesc" | Shift '''value''' '''nbits''' to the right (signed) |
|} | |} | ||
Line 546: | Line 569: | ||
! class="pfrow" | $ | ! class="pfrow" | $ | ||
! class="pfrow" | $ fp #bytes | ! class="pfrow" | $ fp #bytes | ||
− | | Starts a function: | + | ! class="pfdesc" | Starts a function: pushes the frame pointer (activation register) to the stack and allocates space for local variables ('''bytes''') |
|- | |- | ||
! class="pfrow" | START | ! class="pfrow" | START | ||
! class="pfrow" | $ | ! class="pfrow" | $ | ||
! class="pfrow" | $ fp | ! class="pfrow" | $ fp | ||
− | | Equivalent to "ENTER 0" | + | ! class="pfdesc" | Equivalent to "ENTER 0" |
|} | |} | ||
=== Leaving a function === | === Leaving a function === | ||
− | + | STFVAL32 or STFVAL64 may be called to specify return values in accordance with C conventions. Only return values that fit in these registers need these operations. Other return values are passed by pointer. | |
− | Note that these operations make use of specific hardware registers ( | + | Note that these operations make use of specific hardware registers (STFVAL32->eax, STFVAL64->st0). |
{| | {| | ||
− | ! class="pfrow" | | + | ! class="pfrow" | STFVAL32 |
! class="pfrow" | $ a | ! class="pfrow" | $ a | ||
! class="pfrow" | $ | ! class="pfrow" | $ | ||
− | | Removes a 32-bit integer value from the stack (to eax) | + | ! class="pfdesc" | Removes a 32-bit integer value from the stack (to eax) |
|- | |- | ||
− | ! class="pfrow" | | + | ! class="pfrow" | STFVAL64 |
! class="pfrow" | $ d | ! class="pfrow" | $ d | ||
! class="pfrow" | $ | ! class="pfrow" | $ | ||
− | | Removes a double precision (64-bit) floating point value from the stack (to st0) | + | ! class="pfdesc" | Removes a double precision (64-bit) floating point value from the stack (to st0) |
|} | |} | ||
Line 578: | Line 601: | ||
! class="pfrow" | $ fp ... | ! class="pfrow" | $ fp ... | ||
! class="pfrow" | $ | ! class="pfrow" | $ | ||
− | | Ends a function: restores the frame pointer (activation register) and destroys the function-local stack data | + | ! class="pfdesc" | Ends a function: restores the frame pointer (activation register) and destroys the function-local stack data |
|} | |} | ||
Line 587: | Line 610: | ||
! class="pfrow" | $ addr | ! class="pfrow" | $ addr | ||
! class="pfrow" | $ | ! class="pfrow" | $ | ||
− | | Returns from a function (the stack must contain the return address) | + | ! class="pfdesc" | Returns from a function (the stack must contain the return address) |
|- | |- | ||
! class="pfrow" | RETN bytes | ! class="pfrow" | RETN bytes | ||
! class="pfrow" | $ #bytes addr | ! class="pfrow" | $ #bytes addr | ||
! class="pfrow" | $ | ! class="pfrow" | $ | ||
− | | Returns from a function and removes '''bytes''' from the caller's stack after removing the return address. This is more or less the same as "RET+TRASH bytes". '''Note that this is not compatible with the Cdecl calling conventions.''' | + | ! class="pfdesc" | Returns from a function and removes '''bytes''' from the caller's stack after removing the return address. This is more or less the same as "RET+TRASH bytes". '''Note that this is not compatible with the Cdecl calling conventions.''' |
|} | |} | ||
Line 602: | Line 625: | ||
! class="pfrow" | CALL name | ! class="pfrow" | CALL name | ||
! class="pfrow" | $ | ! class="pfrow" | $ | ||
− | ! class="pfrow" | $ address | + | ! class="pfrow" | $ return-address |
− | ! class="pfdesc" | Calls the '''name'''d function. | + | ! class="pfdesc" | Calls the '''name'''d function. The '''return-address''' is pushed to the stack. |
+ | |- | ||
+ | ! class="pfrow" | BRANCH | ||
+ | ! class="pfrow" | $ address | ||
+ | ! class="pfrow" | $ return-address | ||
+ | ! class="pfdesc" | Invokes a function at the '''address''' indicated at the top of the stack. The '''return-address''' is pushed to the stack. | ||
|} | |} | ||
Line 610: | Line 638: | ||
{| | {| | ||
! class="pfrow" | TRASH bytes | ! class="pfrow" | TRASH bytes | ||
− | ! class="pfrow" | #bytes | + | ! class="pfrow" | $ #bytes |
! class="pfrow" | $ | ! class="pfrow" | $ | ||
− | | Removes '''bytes''' from the stack | + | ! class="pfdesc" | Removes '''bytes''' from the stack |
|} | |} | ||
− | To recover the returned value by the callee, the caller must call | + | To recover the returned value by the callee, the caller must call LDFVAL32, to put the value in eax in the stack. An analogous procedure is valid for LDFVAL64 (for double precision floating point return values -- value comes from st0). |
{| | {| | ||
− | ! class="pfrow" | | + | ! class="pfrow" | LDFVAL32 |
! class="pfrow" | $ | ! class="pfrow" | $ | ||
! class="pfrow" | $ value | ! class="pfrow" | $ value | ||
− | | Pushes the return '''value''' in the eax register to the stack | + | ! class="pfdesc" | Pushes the return '''value''' in the eax register to the stack |
|- | |- | ||
− | ! class="pfrow" | | + | ! class="pfrow" | LDFVAL64 |
! class="pfrow" | $ | ! class="pfrow" | $ | ||
! class="pfrow" | $ value | ! class="pfrow" | $ value | ||
− | | Pushes the return '''value''' in the st0 register to the stack | + | ! class="pfdesc" | Pushes the return '''value''' in the st0 register to the stack |
|} | |} | ||
Line 632: | Line 660: | ||
{| | {| | ||
− | |JMP label | + | ! class="pfrow" | JMP label |
+ | ! class="pfrow" | $ | ||
+ | ! class="pfrow" | $ | ||
+ | ! class="pfdesc" | Unconditional jump to '''label''' (does not affect or use the stack) | ||
|- | |- | ||
− | |LEAP | + | ! class="pfrow" | LEAP |
− | + | ! class="pfrow" | $ address | |
− | + | ! class="pfrow" | $ | |
+ | ! class="pfdesc" | Unconditional jump to the '''address''' at the top of the stack | ||
|} | |} | ||
Line 642: | Line 674: | ||
{| | {| | ||
− | |JZ label | + | ! class="pfrow" | JZ label |
+ | ! class="pfrow" | $ value | ||
+ | ! class="pfrow" | $ | ||
+ | ! class="pfdesc" | Jump to '''label''' if the '''value''' at the top of the stack is 0 (zero) | ||
|- | |- | ||
− | |JNZ label | + | ! class="pfrow" | JNZ label |
+ | ! class="pfrow" | $ value | ||
+ | ! class="pfrow" | $ | ||
+ | ! class="pfdesc" | Jump to '''label''' if the '''value''' at the top of the stack is non-zero | ||
|} | |} | ||
Line 650: | Line 688: | ||
{| | {| | ||
− | |JEQ label | + | ! class="pfrow" | JEQ label |
+ | ! class="pfrow" | $ a b | ||
+ | ! class="pfrow" | $ | ||
+ | ! class="pfdesc" | Jump to '''label''' if a≡b | ||
|- | |- | ||
− | |JNE label | + | ! class="pfrow" | JNE label |
+ | ! class="pfrow" | $ a b | ||
+ | ! class="pfrow" | $ | ||
+ | ! class="pfdesc" | Jump to '''label''' if a≠b | ||
|} | |} | ||
{| | {| | ||
− | |JGT label | + | ! class="pfrow" | JGT label |
+ | ! class="pfrow" | $ a b | ||
+ | ! class="pfrow" | $ | ||
+ | ! class="pfdesc" | Jump to '''label''' if a>b | ||
|- | |- | ||
− | |JGE label | + | ! class="pfrow" | JGE label |
+ | ! class="pfrow" | $ a b | ||
+ | ! class="pfrow" | $ | ||
+ | ! class="pfdesc" | Jump to '''label''' if a≥b | ||
|- | |- | ||
− | |JLE label | + | ! class="pfrow" | JLE label |
+ | ! class="pfrow" | $ a b | ||
+ | ! class="pfrow" | $ | ||
+ | ! class="pfdesc" | Jump to '''label''' if a≤b | ||
|- | |- | ||
− | |JLT label | + | ! class="pfrow" | JLT label |
+ | ! class="pfrow" | $ a b | ||
+ | ! class="pfrow" | $ | ||
+ | ! class="pfdesc" | Jump to '''label''' if a<b | ||
|} | |} | ||
Line 668: | Line 724: | ||
{| | {| | ||
− | |JUGT label | + | ! class="pfrow" | JUGT label |
+ | ! class="pfrow" | $ a b | ||
+ | ! class="pfrow" | $ | ||
+ | ! class="pfdesc" | Jump to '''label''' if a>b (unsigned) | ||
|- | |- | ||
− | |JUGE label | + | ! class="pfrow" | JUGE label |
+ | ! class="pfrow" | $ a b | ||
+ | ! class="pfrow" | $ | ||
+ | ! class="pfdesc" | Jump to '''label''' if a≥b (unsigned) | ||
|- | |- | ||
− | |JULE label | + | ! class="pfrow" | JULE label |
+ | ! class="pfrow" | $ a b | ||
+ | ! class="pfrow" | $ | ||
+ | ! class="pfdesc" | Jump to '''label''' if a≤b (unsigned) | ||
|- | |- | ||
− | |JULT label | + | ! class="pfrow" | JULT label |
+ | ! class="pfrow" | $ a b | ||
+ | ! class="pfrow" | $ | ||
+ | ! class="pfdesc" | Jump to '''label''' if a<b (unsigned) | ||
|} | |} | ||
Line 680: | Line 748: | ||
{| | {| | ||
− | |NIL || | + | ! class="pfrow" | NIL |
+ | ! class="pfrow" | | ||
+ | ! class="pfrow" | | ||
+ | ! class="pfdesc" | No action is performed | ||
|- | |- | ||
− | |NOP || | + | ! class="pfrow" | NOP |
+ | ! class="pfrow" | | ||
+ | ! class="pfrow" | | ||
+ | ! class="pfdesc" | Generates a null operation (consumes time; does not change the processor's state) | ||
|} | |} | ||
− | [[category: | + | [[category:Compiladores]] |
− | [[category: | + | [[category:Ensino]] |
The Postfix reference guide contains information about the structure and operations of the stack machine.
The original stack machine was created by Santos (2004). Is was composed by a set of macros to be used with printf functions. Each macro would “take” as arguments, either a number or a string. This was a simple and effective approach but was limited in its expressiveness.
The current postfix code generator class maintains the stack machine abstraction, but does not rely on macros. Instead, it defines an interface to be used by semantic analysers, as defined by a strategy pattern (Gamma et al., 1995). Specific implementations provide the realization of the postfix commands for a particular target machine. Since it is written in C++, it's very easy to extend to new needs and implementations (new target machines).
Like the original postfix code generator, the current abstraction uses an architecture based on a stack machine, hence the name "postfix", and three registers.
In the following tables, the "stack" columns present the results of the actions on the values at the top of the stack. Note that only elements relevant in a given context, i.e., that of the postfix instruction being executed, are shown. The notation #length represents a set of length consecutive bytes in the stack, i.e., a vector.
OPERATION | stack before | stack after | Description of actions |
---|
Consider the following fictitious example:
FAKE | $ a #8 b | $ a b | This is a fake operation |
---|
In this example, before the FAKE operation, the stack had at its top b, followed by eight bytes, followed by a. After executing the FAKE operation (which used those elements in some way), the stack has at its top b, followed by a. The symbol $ is used to denote the point in the stack not affected by the current operation (this could be the top if the stack were empty).
The following groups of operations are available in the Postfix interface:
These operations select various segments. They do not affect the stack.
BSS | Specifies/selects the data segment for uninitialized values | ||
---|---|---|---|
DATA | Specifies/selects the data segment for initialized values | ||
RODATA | Specifies/selects the data segment for initialized constant values | ||
TEXT | Specifies/selects the text (code) segment (default) | ||
TEXT name | Specifies/selects the text (code) segment with name name | ||
TEXT number | Specifies/selects the text (code) segment with name number |
These operations declare values directly in various segments. They do not affect the stack.
SALLOC size | Declares an uninitialized vector with length size (in bytes) | ||
---|---|---|---|
SSHORT value | Declares a static 16-bit integer value | ||
SBYTE value | Declares a static 8-bit character value | ||
SINT value | Declares a static 32-bit integer value | ||
SDOUBLE value | Declares a static double precision (64-bit) floating point value | ||
SFLOAT value | Declares a static simple precision (32-bit) floating point value | ||
SADDR name | Declares a name for an address (i.e., declares the address associated with name) | ||
SSTRING string | Declares a static NULL-terminated character string (C-like) (may contain special characters) |
These operations handle symbols and their definitions within some segment. They do not affect the stack.
ALIGN | Forces the alignment of code or data | ||
---|---|---|---|
LABEL name | Generates a new label name | ||
EXTERN name | Declares name as a symbol externally defined, i.e., defined in another compilation module | ||
GLOBAL name, type | Declares a name with a given type (see below) -- the declaration of a name must preceed its definition |
In a declaration common to several modules, any number of modules may contain common or external declarations, but only one of them may contain an initialized declaration. A declaration does not need to be specified in a specific segment.
Global names may be of different types. These labels are to be used to generate the types needed for the second argument of GLOBAL.
Absolute addressing uses addresses based on named labels. Local addressing is used in function frames and uses offsets relative to the frame pointer to load data: negative addresses correspond to local variables, offset zero contains the previous (saved) value of the frame pointer, offset 4 (32 bits) contains the previous (saved) value of the instruction pointer, and, after offset 8, reside the function arguments.
ADDR name | $ | $ name | Absolute addressing: load address of name |
---|---|---|---|
ADDRA name | $ value | $ | Absolute addressing: store value to name |
ADDRV name | $ | $ [name] | Absolute addressing: load value at name |
LOCAL offset | $ | $ fp+offset | Local addressing: load address of offset |
LOCA offset | $ a | $ | Local addressing: writes a to offset |
LOCV offset | $ | $ [fp+offset] | Local addressing: load value at offset |
ADDRA, ADDRV, LOCA, LOCV are functionally equivalent to ADDR+STINT, ADDR+LDINT, LOCAL+STINT, LOCAL+LDINT, but the generated code is more efficient. They are compound operations (i.e., they contain not only the addressing part, but also the load/store part as well). Note that the postfix_writer visitor is, in general, incapable of generating these instructions.
The load instructions assume that the top of the stack contains an address pointing to the data to be read. Each load instruction will replace the address at the top of the stack with the contents of the position it points to. Load operations differ only in what they load.
LDINT | $ addr | $ [addr] | Loads 4 bytes (int) |
---|---|---|---|
LDFLOAT | $ addr | $ [addr] | Loads 4 bytes (float) |
LDDOUBLE | $ addr | $ [addr] | Loads 8 bytes (double) |
LDBYTE | $ addr | $ [addr] | Loads 1 byte (char) |
LDSHORT | $ addr | $ [addr] | Loads 2 bytes (short) |
Store instructions assume the stack contains at the top the address where data is to be stored. That data is in the stack, immediately after the address. Store instructions differ only in what they store.
STINT | $ val addr | $ | Stores 4 bytes (int) |
---|---|---|---|
STFLOAT | $ val addr | $ | Stores 4 bytes (float) |
STDOUBLE | $ val addr | $ | Stores 8 bytes (double) |
STBYTE | $ val addr | $ | Stores 1 byte (char) |
STSHORT | $ val addr | $ | Stores 2 bytes (short) |
DUP32 | $ a | $ a a | Duplicates the 32-bit value at the top of the stack |
---|---|---|---|
DUP64 | $ a | $ a a | Duplicates the 64-bit value at the top of the stack |
INT value | $ | $ value | Pushes an integer value |
FLOAT value | $ | $ value | Pushes a 4-byte float value (single precision) |
DOUBLE value | $ | $ value | Pushes an 8-byte float value (double precision) |
SP | $ | $ sp | Pushes the value of the stack pointer |
SWAP32 | $ a b | $ b a | Swaps the two 32-bit values at the top of the stack |
SWAP64 | $ a b | $ b a | Swaps the two 64-bit values at the top of the stack |
ALLOC | $ bytes | $ #bytes | Allocates in the stack an array with size bytes. Since this operation alters the meaning of offsets in the stack, care should be taken when local variables exist. |
The arithmetic operations considered here apply to both signed and unsigned integer arguments, and to double precision floating point arguments.
NEG | $ a | $ -a | Negation (symmetric) of integer value |
---|---|---|---|
ADD | $ a b | $ a+b | Integer sum of two integer values |
SUB | $ a b | $ a-b | Integer subtraction of two integer values |
MUL | $ a b | $ a*b | Integer multiplication of two integer values |
DIV | $ a b | $ a/b | Integer division of two integer values |
MOD | $ a b | $ a%b | Remainder of the integer division of two integer values |
UDIV | $ a b | $ a/b | Integer division of two natural (unsigned) integer values |
UMOD | $ a b | $ a%b | Remainder of the integer division of two natural (unsigned) integer values. |
These operations take double precision floating point operands.
DNEG | $ a | $ -a | Negation (symmetric) |
---|---|---|---|
DADD | $ a b | $ a+b | Sum |
DSUB | $ a b | $ a-b | Subtraction |
DMUL | $ a b | $ a*b | Multiplication |
DDIV | $ a b | $ a/b | Division |
INCR delta | $ address | $ address | Adds delta to the value at the address at the top of the stack, i.e. [address] becomes [address]+delta |
---|---|---|---|
DECR delta | $ address | $ address | Subtracts delta to the value at the address at the top of the stack, i.e. [address] becomes [address]-delta |
The following instructions perform type conversions. The conversions are from and to integers and simple and double precision floating point values.
D2F | $ d | $ f | Converts from double precision (64-bit) to single precision (32-bit) floating point |
---|---|---|---|
D2I | $ d | $ i | Converts from double precision (64-bit) floating point to integer (32-bit) |
F2D | $ f | $ d | Converts from simple precision (32-bit) to double precision (64-bit) floating point |
I2D | $ i | $ d | Converts from integer (32-bit) to double precision (64-bit) floating point |
The comparison instructions are binary operations that leave at the top of the stack 0 (zero) or 1 (one), depending on the result of the comparison: respectively, false or true. The value may be directly used to perform conditional jumps (e.g., JZ, JNZ), that use the value of the top of the stack instead of relying on special processor registers ("flags").
EQ | $ a b | $ a≡b | equal to |
---|---|---|---|
NE | $ a b | $ a≠b | not equal to |
GT | $ a b | $ a>b | greater than |
---|---|---|---|
GE | $ a b | $ a≥b | greater than or equal to |
LE | $ a b | $ a≤b | less than or equal to |
LT | $ a b | $ a<b | less than |
The following consider unsigned operands:
UGT | $ a b | $ a>b | greater than for unsigned integers |
---|---|---|---|
UGE | $ a b | $ a≥b | greater than or equal to for unsigned integers |
ULE | $ a b | $ a≤b | less than or equal to for unsigned integers |
ULT | $ a b | $ a<b | less than for unsigned integers |
This operator compares two double precision floating point numbers. The result is an integer value: less than 0, if the first operand is less than the second; 0, if they are equal; greater than 0, otherwise.
DCMP | $ a b | $ i | "compare" -- i<0, a<b; i≡0, a≡b; i>0, a>b |
---|
NOT | $ a | $ ~a | Bitwise negation, i.e., one's complement |
---|---|---|---|
AND | $ a b | $ a∧b | Bitwise AND operation |
OR | $ a b | $ a∨b | Bitwise OR operation |
XOR | $ a b | $ a⊕b | Bitwise XOR (exclusive OR) operation |
Shift and rotation operations have as maximum value the number of bits of the underlying processor register (32 bits in a ix86-family processor). Safe operation for values above that limit is not guaranteed.
ROTL | $ value nbits | $ value<rl>bits | Rotate value nbits to the left |
---|---|---|---|
ROTR | $ value nbits | $ value<rr>bits | Rotate value nbits to the right |
SHTL | $ value nbits | $ value<<bits | Shift value nbits to the left |
SHTRU | $ value nbits | $ value>>bits | Shift value nbits to the right (unsigned) |
SHTRS | $ value nbits | $ value>>>bits | Shift value nbits to the right (signed) |
The following sections cover defining and calling functions.
Each function must allocate space for its local variables. This is done immediately after being called and before any other processing. The relevant operations are ENTER (to specify a given memory amount) and START (no space is reserved for local variables. Note that these operations do more than manipulate the stack: they also create an activation register for the function, i.e., they update the frame pointer and define a new stack frame.
ENTER bytes | $ | $ fp #bytes | Starts a function: pushes the frame pointer (activation register) to the stack and allocates space for local variables (bytes) |
---|---|---|---|
START | $ | $ fp | Equivalent to "ENTER 0" |
STFVAL32 or STFVAL64 may be called to specify return values in accordance with C conventions. Only return values that fit in these registers need these operations. Other return values are passed by pointer.
Note that these operations make use of specific hardware registers (STFVAL32->eax, STFVAL64->st0).
STFVAL32 | $ a | $ | Removes a 32-bit integer value from the stack (to eax) |
---|---|---|---|
STFVAL64 | $ d | $ | Removes a double precision (64-bit) floating point value from the stack (to st0) |
The stack frame is destroyed by the LEAVE operation. This action must be performed immediately before returning control to the caller (with RET).
LEAVE | $ fp ... | $ | Ends a function: restores the frame pointer (activation register) and destroys the function-local stack data |
---|
After the function's stack frame is destroyed and the activation register is restored to the caller, control must also be returned to the caller (i.e., IP must be updated).
RET | $ addr | $ | Returns from a function (the stack must contain the return address) |
---|---|---|---|
RETN bytes | $ #bytes addr | $ | Returns from a function and removes bytes from the caller's stack after removing the return address. This is more or less the same as "RET+TRASH bytes". Note that this is not compatible with the Cdecl calling conventions. |
In a stack machine the arguments for a function call are already in the stack. Thus, it is not necessary to put them there (it is enough not to remove them).
CALL name | $ | $ return-address | Calls the named function. The return-address is pushed to the stack. |
---|---|---|---|
BRANCH | $ address | $ return-address | Invokes a function at the address indicated at the top of the stack. The return-address is pushed to the stack. |
When building functions that conform to the C calling convention, the arguments are destroyed by the caller, after the return of the callee, using TRASH and stating the total size (i.e., for all arguments).
TRASH bytes | $ #bytes | $ | Removes bytes from the stack |
---|
To recover the returned value by the callee, the caller must call LDFVAL32, to put the value in eax in the stack. An analogous procedure is valid for LDFVAL64 (for double precision floating point return values -- value comes from st0).
LDFVAL32 | $ | $ value | Pushes the return value in the eax register to the stack |
---|---|---|---|
LDFVAL64 | $ | $ value | Pushes the return value in the st0 register to the stack |
JMP label | $ | $ | Unconditional jump to label (does not affect or use the stack) |
---|---|---|---|
LEAP | $ address | $ | Unconditional jump to the address at the top of the stack |
JZ label | $ value | $ | Jump to label if the value at the top of the stack is 0 (zero) |
---|---|---|---|
JNZ label | $ value | $ | Jump to label if the value at the top of the stack is non-zero |
The following operations combine comparisons and jumps.
JEQ label | $ a b | $ | Jump to label if a≡b |
---|---|---|---|
JNE label | $ a b | $ | Jump to label if a≠b |
JGT label | $ a b | $ | Jump to label if a>b |
---|---|---|---|
JGE label | $ a b | $ | Jump to label if a≥b |
JLE label | $ a b | $ | Jump to label if a≤b |
JLT label | $ a b | $ | Jump to label if a<b |
The following are for the unsigned versions of the comparisons.
JUGT label | $ a b | $ | Jump to label if a>b (unsigned) |
---|---|---|---|
JUGE label | $ a b | $ | Jump to label if a≥b (unsigned) |
JULE label | $ a b | $ | Jump to label if a≤b (unsigned) |
JULT label | $ a b | $ | Jump to label if a<b (unsigned) |
NIL | No action is performed | ||
---|---|---|---|
NOP | Generates a null operation (consumes time; does not change the processor's state) |