Subversion Repositories tendra.SVN

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

<!-- Crown Copyright (c) 1998 -->
<HTML>
<HEAD>
<TITLE>Operations</TITLE>
</HEAD>
<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#0000FF" VLINK="#400080" ALINK="#FF0000">
<A NAME=S66>
<H1>TDF Guide, Issue 4.0 </H1>
<H3>January 1998</H3>
<A HREF="guide11.html"><IMG SRC="../images/next.gif" ALT="next section"></A>
<A HREF="guide9.html"><IMG SRC="../images/prev.gif" ALT="previous section"></A>
<A HREF="guide1.html"><IMG SRC="../images/top.gif" ALT="current document"></A>
<A HREF="../index.html"><IMG SRC="../images/home.gif" ALT="TenDRA home page">
</A>
<IMG SRC="../images/no_index.gif" ALT="document index"><P>
<HR>
<DL>
<DT><A HREF="#S67"><B>8.1 </B> - VARIETY and overflow</A><DD>
<DT><A HREF="#S68"><B>8.1.1 </B> - ERROR_TREATMENT</A><DD>
<DT><A HREF="#S69"><B>8.2 </B> - Division and remainder</A>
<DD>
<DT><A HREF="#S70"><B>8.3 </B> - change_variety</A><DD>
<DT><A HREF="#S71"><B>8.4 </B> - and, or, not, xor</A><DD>
<DT><A HREF="#S72"><B>8.5 </B> - Floating-point operations, ROUNDING_MODE</A>
<DD>
<DT><A HREF="#S73"><B>8.6 </B> - change_bitfield_to_int, change_int_to_bitfield
</A><DD>
<DT><A HREF="#S74"><B>8.7 </B> - make_compound, make_nof, n_copies</A><DD>
</DL>
<HR>
<H1>8  Operations</H1>
Most of the arithmetic operations of TDF have familiar analogues in
standard languages and processors. They differ principally in how
error conditions (e.g. numeric overflow) are handled. There is a wide
diversity in error handling in both languages and processors, so TDF
tries to reduce it to the simplest primitive level compatible with
their desired operation in languages and their implementation on processors.
Before delving into the details of error handling, it is worthwhile
revisiting the SHAPEs and ranges in arithmetic VARIETYs.<P>
<A NAME=S67>
<HR><H2>8.1. VARIETY and overflow</H2>
An INTEGER VARIETY, for example, is defined by some range of signed
natural numbers. A translator will fit this range into some possibly
larger range which is convenient for the processor in question. For
example, the integers with variety(1,10) would probably be represented
as unsigned characters with range (0..255), a convenient representation
for both storage and arithmetic. <P>
The question then arises of what is meant by overflow in an operation
which is meant to deliver an integer of this VARIETY - is it when
the integer result is outside the range (1..10) or outside the range
(0..255)? For purely pragmatic reasons, TDF chooses the latter - the
result is overflowed when it is outside its representational range
(0..255). If the program insists that it must be within (1..10), then
it can always test for it. If the program uses the error handling
mechanism and the result is outside (1..10) but still within the representational
limits, then, in order for the program to be portable, then the error
handling actions must in some sense be &quot;continuous&quot; with
the normal action. This would not be the case if, for example, the
value was used to index an array with bounds (1..10), but will usually
be the case where the value is used in further arithmetic operations
which have similar error handling. The arithmetic will continue to
give the mathematically correct result provided the representational
bounds are not exceeded.<P>
The limits in a VARIETY are there to provide a guide to its representation,
and not to give hard limits to its possible values. This choice is
consistent with the general TDF philosophy of how exceptions are to
be treated. If, for example, one wishes to do array-bound checking,
then it must be done by explicit tests on the indices and jumping
to some exception action if they fail. Similarly, explicit tests can
be made on an integer value, provided its representational limits
are not exceeded. It is unlikely that a translator could produce any
more efficient code, in general, if the tests were implicit. The representational
limits can be exceeded in arithmetic operations, so facilities are
provided to either to ignore it , to allow one to jump to a label
, or to obey a TDF exception handler if it happens.<P>
<A NAME=S68>
<H3>8.1.1. <A NAME=6>ERROR_TREATMENT</H3>
Taking integer addition as an example, plus has signature:<P>
<PRE>
<I>     ov_err</I>:     ERROR_TREATMENT
<I>     arg1</I>:       EXP INTEGER(<I>v</I>)
<I>     arg2</I>:       EXP INTEGER(<I>v</I>)
                   -&gt;        EXP INTEGER(<I>v</I>)
</PRE>
The result of the addition has the same integer VARIETY as its parameters.
If the representational bounds of <I>v</I> are exceeded, then the
action taken depends on the ERROR_TREATMENT <I>ov_err</I>. <P>
The ERROR_TREATMENT , impossible, is an assertion by the producer
that overflow will not occur; on its head be it if it does.<P>
The ERROR_TREATMENTS continue and wrap give &quot;fixup&quot; values
for the result. For continue the fixup value is undefined. For wrap,
the the answer will be modulo 2 to the power of the number of bits
in the representational variety.Thus, integer arithmetic with byte
representational variety is done modulo 256. This just corresponds
to what happens in most processors and, incidentally, the definition
of C. <P>
The ERROR_TREATMENT that one would use if one wished to jump to a
label is error_jump:<P>
<PRE>
<I>     lab</I>:        LABEL
                   -&gt;        ERROR_TREATMENT
</PRE>
A branch to <I>lab</I> will occur if the result overflows. <P>
The ERROR_TREATMENT, trap(overflow) will raise a TDF exception(see
<A HREF="guide8.html#31">section 6.3 on page 35</A>)with ERROR_CODE
overflow if overflow occurs.<P>
<P>
<A NAME=S69>
<HR><H2>8.2. Division and remainder</H2>
The various constructors in involving integer division (e.g. div1,
rem1) have two ERROR_TREATMENT parameters, one for overflow and one
for divide-by-zero e.g. div1 is:<P>
<PRE>
        <I>div_by_zero_error</I>:       ERROR_TREATMENT
        <I>ov_err</I>:  ERROR_TREATMENT
        <I>arg1</I>:    EXP INTEGER(<I>v</I>)
        <I>arg2</I>:    EXP INTEGER(<I>v</I>)
                   -&gt; EXP INTEGER(<I>v</I>)
</PRE>
. There are two different kinds of division operators (with corresponding
remainder operators) defined. The operators div2 and rem2 are those
generally implemented directly by processor instructions giving the
sign of the remainder the same as the sign of the quotient. The other
pair, div1 and rem1, is less commonly implemented in hardware, but
have rather more consistent mathematical properties; here the sign
of remainder is the same as the sign of divisor. Thus, div1(x, 2)
is the same as shift_right(x, 1) which is only true for div2 if x
is positive. The two pairs of operations give the same results if
both operands have the same sign. The constructors div0 and rem0 allow
the translator to choose whichever of the two forms of division is
convenient - the producer is saying that he does not care which is
used, as long as they are pairwise consistent. The precise definition
of the divide operations is given in (S7.4)</A>.<P>
<A NAME=S70>
<HR><H2>8.3. change_variety</H2>
Conversions between the various INTEGER varieties are provided for
by change_variety:<P>
<PRE>
        <I>ov_err</I>:  ERROR_TREATMENT
<I>     r</I>:  VARIETY
<I>     arg1</I>:       EXP INTEGER(<I>v</I>)
                   -&gt;        EXP INTEGER(<I>r</I>)
</PRE>
If the value <I>arg1</I> is outside the limits of the representational
variety of <I>r</I>, then the ERROR_TREATMENT <I>ov_err</I> will be
invoked.<P>
<A NAME=S71>
<HR><H2>8.4. and, or, not, xor</H2>
The standard logical operations, and, not, or and xor are provided
for all integer varieties. Since integer varieties are defined to
be represented in twos-complement the result of these operations are
well defined.<P>
<A NAME=S72>
<HR><H2>8.5. Floating-point operations, ROUNDING_MODE</H2>
All of the floating-point (including complex) operations include ERROR-TREATMENTs.
If the result of a floating-point operation cannot be represented
in the desired FLOATING_VARIETY, the error treatment is invoked. If
the ERROR_TREATMENT is wrap or impossible, the result is undefined;
otherwise the jump operates in the same way as for integer operations.
Both floating_plus and floating_mult are defined as n-ary operations.
In general, floating addition and multiplication are not associative,
but a producer may not care about the order in which they are to be
performed. Making them appear as though they were associative allows
the translator to choose an order which is convenient to the hardware.<P>
Conversions from integer to floating are done by float_int and from
floating to integers by round_with_mode . This latter constructor
has a parameter of SORT ROUNDING_MODE which effectively gives the
IEEE rounding mode to be applied to the float to produce its integer
result.<P>
One can extract the real and imaginary parts of a complex FLOATING
using real_part and imaginary_part. A complex FLOATING can be constructed
using make_complex. Normal complex arithmetic applies to all the other
FLOATING constructors except for those explicitly excluded (eg floating_abs,
floating_max etc.)<P>
<A NAME=S73>
<HR><H2>8.6. change_bitfield_to_int, change_int_to_bitfield</H2>
There are two bit-field operation, change_bitfield_to_int and change_int_to_bitfield
to transform between bit-fields and integers. If the varieties do
not fit the result is undefined; the producer can always get it right.<P>
<A NAME=S74>
<HR><H2>8.7. <A NAME=36>make_compound, make_nof, n_copies</H2>
There is one operation to make values of COMPOUND SHAPE, make_compound:
<P>
<PRE>
<I>     arg1</I>:       EXP OFFSET(<I>base, y</I>)
<I>     arg2</I>:       LIST(EXP)
                   -&gt; EXP COMPOUND(<I>sz</I>)
</PRE>
The OFFSET <I>arg1</I> is evaluated as a translate-time constant to
give <I>sz</I>, the size of the compound object. The EXPs of arg2
are alternately OFFSETs (also translate-time constants) and values
which will be placed at those offsets. This constructor is used to
construct values given by structure displays; in C, these only occur
with constant <I>val[i]</I> in global definitions. It is also used
to provide union injectors; here <I>sz</I> would be the size of the
union and the list would probably two elements with the first being
an offset_zero.<P>
Constant sized array values may be constructed using make_nof, make_nof_int
(see <A HREF="#36">section 8.7 on page 42</A>), and n_copies. Again,
they only occur in C as constants in global definitions.<P>
<HR>
<P><I>Part of the <A HREF="../index.html">TenDRA Web</A>.<BR>Crown
Copyright &copy; 1998.</I></P>
</BODY>
</HTML>