Go to the previous section.
Instructions are the primary data structure in Simple-SUIF. Each procedure is represented by a doubly-linked list of instructions. These instructions contain references to the various types, symbols, and registers. Simple-SUIF instructions resemble assembly language instructions. Each one performs a relatively simple operation specified by its opcode. Most instructions have several operands in registers.
Instructions are stored in simple_instr
structures. All
instructions share several fields: the opcode, the result type, and
pointers to the next and previous instructions. Since different
instructions require different kinds of operands, the rest of the fields
in the simple_instr
structure are specific to the instruction
format. The simple_op_format
function may be used to
identify the format used for a particular opcode. The possible format
values are:
BASE_FORM
nop
(no operation) instructions use none of
the registers, and cpy
(copy) instruction only use the
destination and one of the source registers.
BJ_FORM
LDC_FORM
ldc
) instructions use this format. It includes a
destination register and a simple_immed
structure to hold the
immediate value. See section Immediate Values.
CALL_FORM
call
instructions. There
are at least two register operands: the destination and the address of
the procedure to be called. The format also includes a field to record
the number of arguments and an array of the argument registers.
MBR_FORM
mbr
) instructions use this format. The fields
include a source register, an integer offset, a default target label,
and an array of other target labels.
LABEL_FORM
lab
) instructions identify the position of a label in the
instruction list. They use this format which only contains a reference
to the label symbol.
The result type of an instruction identifies the type of the value
produced for the destination register. If the instruction format does
not contain a destination register or if the particular opcode does not
use the destination, the result type should always be a
VOID_TYPE
. Otherwise, the result type must always be
supplied and should generally be the same as the type of the variable in
the destination register. In rare cases, the destination register field
may be set to NO_REGISTER
even though the instruction
produces a result. When this happens, the result type should indicate
the type of the value that is actually produced even though that value
is unused.
Unlike the other Simple-SUIF data structures, instructions can be freely
modified and rearranged. The library includes functions to help create
new instructions and deallocate them when they are no longer needed.
The new_instr
function creates a new simple_instr
object given the opcode and result type. The other fields must be
filled in separately. Note that this function is merely a convenience;
nothing special is required when creating new instructions, and users
are free to create them by calling malloc
and setting the
opcode and result type manually. The free_instr
function
deallocates the storage used by an instruction. Again, this function
does nothing magic and is only provided for convenience.
The following table lists all of the Simple-SUIF opcodes. Each opcode
has an internal representation that is a member of the
simple_op
enumeration. The simple_op_name
function may be used to produce a textual representation for an opcode.
The table lists both forms. Unless indicated otherwise, the opcodes use
the BASE_FORM
format.
nop NOP_OP
NO_REGISTER
, and the result type should be a
VOID_TYPE
.
load LOAD_OP
src1
register and
put it in the dst
register. The result type may be any type and
indicates the type of the value being loaded. The type of the variable
in src1
must be a pointer to the result type. The src2
register is not used.
str STR_OP
src2
register at the address contained in
the src1
register. Both registers must be specified. The
src2
register may have any type. The src1
register should
contain a variable that is a pointer to the type of the variable being
stored. The dst
register is not used.
mcpy MCPY_OP
src2
register and store it at the address in the src1
register. Objects of any type may be copied. Both of the source
registers must be pointers to the type of the object that is being
copied. The dst
register is not used.
cpy CPY_OP
src1
register to the dst
register. The
src2
register is not used. The result type must be compatible
with the type of the source register but need not necessarily be
equivalent. Only scalar types are allowed here.
cvt CVT_OP
src1
register to the result type and put it in the
dst
register. The src2
register is not used. Conversions
should be performed in steps, changing only one attribute at a time.
For example, when converting from an unsigned 8-bit type to a signed
32-bit type, use one cvt
instruction to change the size and
another to make it signed. Conversions between integer and
floating-point types should always be made using types that are as close
as possible in size. Nothing can be converted to or from a
VOID_TYPE
type or a RECORD_TYPE
.
ADDRESS_TYPE
types can only be converted to and from integer
types.
ldc LDC_OP
LDC_FORM
format. The value
operand is an immediate constant stored in a
simple_immed
structure (see section Immediate Values). If the
immediate value is an integer, the result type must be a
SIGNED_TYPE
, UNSIGNED_TYPE
or
ADDRESS_TYPE
type. The result type should be a
FLOAT_TYPE
type if the immediate is a floating-point value.
And finally, if the immediate value is a symbolic address, the result
type should always be an ADDRESS_TYPE
type.
neg NEG_OP
src1
register and
put the result in the dst
register. The src2
register is
unused. The result type and the type of the registers must be
compatible integer or floating-point types.
add ADD_OP
src1
and src2
registers and put the
result in the dst
register. Except for pointer additions, the
result type and the types of the registers must be compatible integer or
floating-point types. Pointer addition is a special case. One of the
source registers may have an ADDRESS_TYPE
type, as long as
the other source register contains a variable with an integer type of
the same size as the pointer; the result type must also be an
ADDRESS_TYPE
type.
sub SUB_OP
src2
register from the value in the
src1
register and put the result in the dst
register.
Except for pointer subtractions, the result type and the types of the
registers must be compatible integer or floating-point types. There are
two special cases for pointer subtractions. In either case, the
src1
register must have an ADDRESS_TYPE
type. First,
the src2
register may have an integer type of the same size as
the pointer to produce an ADDRESS_TYPE
value in the
dst
register. Second, the src2
register may be another
ADDRESS_TYPE
value to produce a value in the dst
register with an integer type that is the same size as the pointers.
mul MUL_OP
div DIV_OP
src1
register by the value in
the src2
register and put the result in the dst
register.
The result type and the types of the registers must be compatible
integer or floating-point types. Integer multiplication and division
are defined according to the rules for ANSI C.
rem REM_OP
mod MOD_OP
src1
register by the value in the
src2
register to find the remainder or modulus. The rem
instruction is identical to the modulus operator in ANSI C, and the
mod
instruction is the same except that its result is always
guaranteed to be positive. The result type and the types of the
destination and source registers must be compatible integer types.
not NOT_OP
src1
register and put the result in the dst
register. The src2
register is not used. The result type and
the types of the registers must be compatible UNSIGNED_TYPE
types.
and AND_OP
ior IOR_OP
xor XOR_OP
src1
and src2
registers and put the result in the
dst
register. The result type and the types of the registers
must be compatible UNSIGNED_TYPE
types.
asr ASR_OP
lsr LSR_OP
lsl LSL_OP
src1
register right or left by the amount
specified in the src2
register. The variable in the src2
register must always have an UNSIGNED_TYPE
type. The
asr
instruction performs sign extension and requires that the
result type and the types of the dst
and src1
registers be
compatible SIGNED_TYPE
types. The lsr
instructions
does not perform sign extension and requires that the result type and
types of the dst
and src1
register be compatible
UNSIGNED_TYPE
types. Sign extension is not an issue for left
shifts, so the lsl
instruction only requires that the result type
and the types of the dst
and src1
register be compatible
integer types.
rot ROT_OP
src1
register left or right by the amount
specified in the src2
register. The variable in the src2
register must always have an SIGNED_TYPE
type. If the shift
amount is positive, the value is rotated to the left; if it is negative,
the value is rotated to the right. The result type and the types of the
dst
and src1
registers must be compatible integer types.
seq SEQ_OP
sne SNE_OP
sl SL_OP
sle SLE_OP
src1
register is equal, not
equal, less than, or less than or equal, respectively, to the
src2
register, assign the integer value one to the dst
register. Otherwise, set the dst
register to zero. The result
type must always be a SIGNED_TYPE
type. The source registers
must have compatible scalar types.
jmp JMP_OP
BJ_FORM
format, but the src
register is unused. The flow of control is
unconditionally transferred to the code at target label.
btru BTRUE_OP
bfls BFALSE_OP
BJ_FORM
format. If the src
register, which must have an integer type,
contains a true (non-zero) or false (zero) value, respectively, the flow
of control is transferred to the code at the target label. Otherwise,
it continues with the next instruction in sequential order.
mbr MBR_OP
MBR_FORM
format,
which includes an array of target labels. The number of labels in the
array is identified by the value of the ntargets
field. Control
is transferred to one of these labels depending on the value in the
src
register. The variable in the src
register must have
a SIGNED_TYPE
or UNSIGNED_TYPE
type. The integer
value in the offset
field is subtracted from the value in the
src
register and the result is used to index into the array of
target labels. If the index is within the range of the array, the
instruction branches to the label at that position in the array;
otherwise, it branches to the default label in the deflab
field.
lab LABEL_OP
LABEL_FORM
format. No operation is performed by a label
instruction. Its only purpose is to mark the location of a label symbol
in the instruction list. The lab
field must be a pointer to the
simple_sym
for the label.
call CALL_OP
CALL_FORM
format. The proc
register must hold a pointer to the procedure
to be called. The type of the variable in that register must be a
pointer to the type of the procedure. Note: Simple SUIF currently
cannot represent procedure types, so you must use the pointer types that
are used in the input list when referring to procedure addresses. The
result type of the call
instruction must match the return type of
the procedure. If the result type is not a VOID_TYPE
type,
the dst
register will be assigned the value returned by the
procedure. The nargs
field in the call
instruction
indicates how many arguments are in the args
array. Each entry
in the args
array is a register holding the value of an argument
to the procedure.
ret RET_OP
src1
register is used and it
is optional. If specified, it is the return value and may contain a
variable of any type.
Go to the previous section.