Home My Page Projects Code Snippets Project Openings SML/NJ
 Summary Activity Forums Tracker Lists Tasks Docs Surveys News SCM Files

# SCM Repository

[smlnj] Diff of /sml/trunk/compiler/ElabData/prim/primop.sig
 [smlnj] / sml / trunk / compiler / ElabData / prim / primop.sig

# Diff of /sml/trunk/compiler/ElabData/prim/primop.sig

revision 4886, Wed Oct 10 16:54:46 2018 UTC revision 4986, Fri Apr 26 17:08:01 2019 UTC
# Line 4  Line 4
5   *)   *)
6
(*********************************************************************
Integer/Word Conversions Explained

All integer/word conversion operations are expressed using five
primitive conversion operators. Algebraic equations over these
operators are easy to define and can be used to simplify composition
of conversion operations.

The five basic conversion operators are (in all cases, we assume
that (n >= m):

TEST(n,m)     -- map an n-bit, 2's complement signed value to an
m-bit, 2's complement signed value;
raise Overflow if the value is too large.

TESTU(n,m)    -- map an unsigned n-bit value to an m-bit 2's
complement value; raise Overflow if the value
is too large.

EXTEND(m,n)   -- sign extend an m-bit value to a n-bit value

TRUNC(n,m)    -- truncate an n-bit value to an m-bit value.

COPY(m,n)     -- copy an m-bit value to an n-bit value.

TEST, TESTU, and TRUNC are used to go from large values to small
ones, and EXTEND and COPY are used to go from small values to
large. The operators EXTEND, TRUNC, and COPY are "pure," while TEST
and TESTU may raise Overflow.

Conversions where the sizes are the same can be simplified to copies:

TEST(n,n)     == COPY(n,n)
EXTEND(n,n)   == COPY(n,n)    Note: this does not apply to TESTU
TRUNC(n,n)    == COPY(n,n)

The translation of conversion operations in the Word32 and Word8
structures (for example) is given by:

Module        function     => Implemented by
----------------------------------------------------------
Word32        toLargeInt    => TESTU(32,32)
toLargeIntX   => EXTEND(32,32)          = COPY(32,32)
fromLargeInt  => COPY(32,32)
toInt         => TESTU(32,31)
toIntX        => TEST(32,31)
fromInt       => EXTEND(31,32)
toLargeWord   => COPY(32,32)
toLargeWordX  => EXTEND(32,32)          = COPY(32,32)
fromLargeWord => TRUNC(32,32)           = COPY(32,32)

Word8         toLargeInt    => COPY(8,32)
toLargeIntX   => EXTEND(8,32)
fromLargeInt  => TRUNC(32,8)
toInt         => COPY(8,31)
toIntX        => EXTEND(8,31)
fromInt       => TRUNC(31,8)
toLargeWord   => COPY(8,32)
toLargeWordX  => EXTEND(8,32)
fromLargeWord => TRUNC(32,8)

Each operator composed with itself is itself, but with different parameters:

TEST(n,m) o TEST(p,n)         == TEST(p,m)
TESTU(n,m) o TESTU(p,n)       == TESTU(p,m)
EXTEND(n,m) o EXTEND(p,n)     == EXTEND(p,m)
TRUNC(n,m) o TRUNC(p,n)       == TRUNC(p,m)
COPY(n,m) o COPY(p,n)         == COPY(p,m)

The composition of these operators can be described by a simple algebra.

EXTEND(n,m) o COPY(p,n)       == COPY(p,m)   if (n > p)
== EXTEND(p,m) if (n = p)
COPY(n,m) o EXTEND(p,n)       == EXTEND(p,m) if (n = m)

TRUNC(n,m) o COPY(p,n)        == COPY(p,m)   if (m >= p)
== TRUNC(p,m)  if (m < p)

COPY(n,m) o TRUNC(p,n)        == TRUNC(p,m)  if (n = m)

TEST(n,m) o COPY(p,n)         == COPY(p,m)   if (m >= p)
== TEST(p,m)   if (m < p)

TESTU(n,m) o COPY(p,n)        == COPY(p,m)   if (m >= p)
== TESTU(p,m)  if (m < p)

COPY(n,m) o TEST(p,n)         == TEST(p,m)   if (n = m)

COPY(n,m) o TESTU(p,n)        == TESTU(p,m)  if (n = m)

TRUNC(n,m) o EXTEND(p,n)      == EXTEND(p,m) if (m >= p)
== TRUNC(p,m)  if (m < p)

TEST(n,m) o EXTEND(p,n)       == EXTEND(p,m) if (m >= p)
== TEST(p,m)   if (m < p)

TESTU(n,m) o EXTEND(p,n)      == EXTEND(p,m) if (m >= p)
== TESTU(p,m)  if (m < p)

For example, consider:
Word.toInt o Word.fromLargeWord o Word8.toLargeWord

This translates to:
TESTU(31,31) o TRUNC(32,31) o COPY(8,32)

and simplifies to:
TESTU(31,31) o COPY(8,31)

This further simplifies to:
COPY(8, 31)

Since both 8-bit and 31-bit quantities are tagged the same way, this
gets translated to a MOVE. With a smart register allocator that MOVE
can be eliminated.
*********************************************************************)

7  signature PRIMOP =  signature PRIMOP =
8    sig    sig
9
# Line 133  Line 16
16
17      datatype arithop      datatype arithop
18        = ADD | SUB | MUL | NEG                   (* int or float *)        = ADD | SUB | MUL | NEG                   (* int or float *)
19        | FDIV | ABS | FSQRT | FSIN | FCOS | FTAN (* floating point only *)        | FDIV | FABS | FSQRT | FSIN | FCOS | FTAN (* floating point only *)
20        | LSHIFT | RSHIFT | RSHIFTL               (* int only *)        | LSHIFT | RSHIFT | RSHIFTL               (* int only *)
21        | ANDB | ORB | XORB | NOTB                (* int only *)        | ANDB | ORB | XORB | NOTB                (* int only *)
22        | DIV | MOD | QUOT | REM                  (* int only *)        | DIV | MOD | QUOT | REM                  (* int only *)
# Line 150  Line 33
33     * as are the "checked=true" versions of NUMSUBSCRIPT and NUMUPDATE (L?:).     * as are the "checked=true" versions of NUMSUBSCRIPT and NUMUPDATE (L?:).
34     * "Environmental" primops (occurring in the InLine structure) are indicated     * "Environmental" primops (occurring in the InLine structure) are indicated
35     * by "E:" in the comment.     * by "E:" in the comment.
36       *
37       * See dev-notes/conversions.md for an explanation of the conversion operators.
38     *)     *)
39      datatype primop      datatype primop
40        = ARITH of {                              (* E: arithmetic ops *)        = ARITH of {                              (* E: arithmetic ops *)
# Line 169  Line 54
54        | EXTEND_INF of int                       (* E: intinf extensions, e.g. extend_8_inf *)        | EXTEND_INF of int                       (* E: intinf extensions, e.g. extend_8_inf *)
55        | COPY_INF of int                         (* E: conversions to intinf, e.g. copy_8_inf *)        | COPY_INF of int                         (* E: conversions to intinf, e.g. copy_8_inf *)
56        | ROUND of {                              (* E: floor, round *)        | ROUND of {                              (* E: floor, round *)
57              floor: bool, fromkind: numkind, tokind: numkind              floor: bool, from: int, to: int
58            }            }
59        | REAL of {                               (* E: real, real32 *)        | REAL of {                               (* E: real, real32 *)
60              fromkind: numkind, tokind: numkind              from: int, to: int
61            }            }
62        | NUMSUBSCRIPT of {                       (* E: L?: ordof, etc. *)        | NUMSUBSCRIPT of {                       (* E: L?: ordof, etc. *)
63              kind: numkind, checked: bool, immutable: bool              kind: numkind, checked: bool, immutable: bool

Legend:
 Removed from v.4886 changed lines Added in v.4986