   ### 15.3.208  src/lib/compiler/back/top/highcode/highcode-baseops.api

`## highcode-baseops.api `
`#`
`# The base-functions vocabulary used in lambdacode and anormcode.`
`#`
`# For general background see:`
`#`
`#     src/A.COMPILER-PASSES.OVERVIEW `

`# Compiled by:`
`#     `src/lib/compiler/core.sublib

`############################################################################`
`# `
`#                  Int/Unt Conversions Explained`
`# `
`# All Un/signed integer conversion operations are expressed using five`
`# base conversion operators. Algebraic equations over these`
`# operators are easy to define and can be used to simplify composition`
`# of conversion operations.`
`# `
`# There are five basic conversion operators.`
`# `
`#     SHRINK_INT, SHRINK_UNT, and CHOP are used to go from large values to small ones;`
`#     STRETCH and COPY are used to go from small values to large.`
`#`
`# The operators STRETCH, CHOP, and COPY are "pure, " while SHRINK_INT`
`# and SHRINK_UNT may raise OVERFLOW. `

`# In all cases, we assume that (n >= m):`
`# `
`#   SHRINK_INT (n, m)   -- map a   signed n-bit value to an m-bit 2's`
`#                  complement value; raise OVERFLOW if the value`
`#                  is too large.`
`# `
`#   SHRINK_UNT (n, m)   map an unsigned n-bit value to an m-bit 2's `
`#                  complement value; raise OVERFLOW if the value `
`#                  is too large.`
`# `
`#   STRETCH (m, n)      -- sign extend an m-bit value to a n-bit value`
`# `
`#   CHOP (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.`
`# `
`# `
`# Conversions where the sizes are the same can be simplified to copies:`
`# `
`#   SHRINK_INT (n, n)   == COPY (n, n)`
`#   STRETCH (n, n)      == COPY (n, n)  Note: this does not apply to SHRINK_UNT`
`#   CHOP (n, n) == COPY (n, n)`
`# `
`# The translation of conversion operations in the one_word_unt and one_byte_unt`
`# packages (for example) is given by:`
`# `
`#   Package      function       =>  Implemented by      `
`#   ----------   --------------     ---------------------`
`#   one_word_unt toLargeInt     =>  SHRINK_UNT (32, 32)         `
`#                toLargeIntX    =>  STRETCH    (32, 32)         = COPY (32, 32)`
`#                from_large_int =>  COPY       (32, 32)         `
`#                toInt          =>  SHRINK_UNT (32, 31)         `
`#                toIntX         =>  SHRINK_INT (32, 31)         `
`#                from_int       =>  STRETCH    (31, 32)         `
`#                toLargeUnt     =>  COPY       (32, 32)         `
`#                toLargeUntX    =>  STRETCH    (32, 32)         = COPY (32, 32)`
`#                fromLargeUnt   =>  CHOP       (32, 32)         = COPY (32, 32)`
`# `
`#   one_byte_unt toLargeInt     =>  COPY       ( 8, 32)`
`#                toLargeIntX    =>  STRETCH    ( 8, 32)`
`#                from_large_int =>  CHOP       (32,  8)`
`#                toInt          =>  COPY       ( 8, 31)`
`#                toIntX         =>  STRETCH    ( 8, 31)`
`#                from_int       =>  CHOP       (31,  8)`
`#                toLargeUnt     =>  COPY       ( 8, 32)`
`#                toLargeUntX    =>  STRETCH    ( 8, 32)`
`#                fromLargeUnt   =>  CHOP       (32,  8)`
`# `
`# `
`# Each operator composed with itself is itself, but with different parameters:`
`# `
`#     SHRINK_INT (n,m)   o   SHRINK_INT (p,n)   ==   SHRINK_INT (p,m)`
`#     SHRINK_UNT (n,m)   o   SHRINK_UNT (p,n)   ==   SHRINK_UNT (p,m)`
`#     STRETCH    (n,m)   o   STRETCH    (p,n)   ==   STRETCH    (p,m)`
`#     CHOP       (n,m)   o   CHOP       (p,n)   ==   CHOP       (p,m)`
`#     COPY       (n,m)   o   COPY       (p,n)   ==   COPY       (p,m)`
`# `
`# The composition of these operators can be described by a simple algebra:`
`# `
`#     STRETCH    (n,m)   o   COPY       (p,n)   ==   COPY       (p,m) if (n >  p),   STRETCH    (p,m) if (n == p)       `
`#     COPY       (n,m)   o   STRETCH    (p,n)   ==   STRETCH    (p,m) if (n == m)       `
`#     CHOP       (n,m)   o   COPY       (p,n)   ==   COPY       (p,m) if (m >= p)    CHOP       (p,m) if (m <  p)       `
`#     COPY       (n,m)   o   CHOP       (p,n)   ==   CHOP       (p,m) if (n == m)       `
`#     SHRINK_INT (n,m)   o   COPY       (p,n)   ==   COPY       (p,m) if (m >= p)    SHRINK_INT (p,m) if (m <  p)       `
`#     SHRINK_UNT (n,m)   o   COPY       (p,n)   ==   COPY       (p,m) if (m >= p)    SHRINK_UNT (p,m) if (m <  p)       `
`#     COPY       (n,m)   o   SHRINK_INT (p,n)   ==   SHRINK_INT (p,m) if (n == m)       `
`#     COPY       (n,m)   o   SHRINK_UNT (p,n)   ==   SHRINK_UNT (p,m) if (n == m)       `
`#     CHOP       (n,m)   o   STRETCH    (p,n)   ==   STRETCH    (p,m) if (m >= p)    CHOP       (p,m) if (m <  p)       `
`#     SHRINK_INT (n,m)   o   STRETCH    (p,n)   ==   STRETCH    (p,m) if (m >= p)    SHRINK_INT (p,m) if (m <  p)       `
`#     SHRINK_UNT (n,m)   o   STRETCH    (p,n)   ==   STRETCH    (p,m) if (m >= p)    SHRINK_UNT (p,m) if (m <  p)       `
`# `
`# For example, consider:`
`#       unt::toInt o unt::fromLargeUnt o one_byte_unt::toLargeUnt`
`# `
`# This translates to:`
`# `
`#       SHRINK_UNT(31,31)  o  CHOP(32,31)  o  COPY(8,32)`
`# `
`# and simplifies to:`
`# `
`#       SHRINK_UNT(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.`
`#`
`############################################################################`

`###               "Every minute dies a man, Every minute one is born;"`
`###`
`###            I need hardly point out to you that this calculation`
`###            would tend to keep the sum total of the world's population`
`###            in a state of perpetual equipoise, whereas it is a`
`###            well-known fact that the said sum total is constantly`
`###            on the increase.`
`###`
`###            I would therefore take the liberty of suggesting that`
`###            in the next edition of your excellent poem the erroneous`
`###            calculation to which I refer should be corrected as follows:`
`###`
`###               "Every moment dies a man, And one and a sixteenth is born."`
`###`
`###            I may add that the exact figures are 1.067, but something must,`
`###            of course, be conceded to the laws of metre.`
`###`
`###                        ~Charles Babbage,`
`###                         letter to Alfred, Lord Tennyson,`
`###                         about a couplet in his "The Vision of Sin"`

`stipulate`
`    package cty =  ctypes;                                                      # ctypes                is from   `src/lib/compiler/back/low/ccalls/ctypes.pkg
`herein`

`    # This api is implemented in:`
`    #`
`    #     `src/lib/compiler/back/top/highcode/highcode-baseops.pkg
`    #`
`    api Highcode_Baseops {`
`        #`

`        # Number_Kind_And_Size gives kind of number (int/unt/float)`
`        # plus size-in-bits:`
`        #`
`        Number_Kind_And_Size `
`          #`
`          = INT   Int           # Fixed-length   signed-integer type.`
`          ``| UNT   Int           ``# Fixed-length unsigned-integer type.`
`          ``| FLOAT Int           ``# Fixed-length floating-point   type.   `
`          ;`

`        Math_Op`
`          #`
`          = ADD ``| SUBTRACT | MULTIPLY | DIVIDE | NEGATE                 ``# Int or Float.  For int, this does Round-to-zero division -- this is the native instruction on Intel32.`
`          ``| ABS | FSQRT | FSIN | FCOS | FTAN                            ``# Float only.`
`          ``| LSHIFT | RSHIFT | RSHIFTL                                   ``# Int only.`
`          ``| BITWISE_AND | BITWISE_OR | BITWISE_XOR | BITWISE_NOT        ``# Int only.`
`          ``| REM                                                         ``# Int only.               This does round-to-zero remainder -- this is the native instruction on Intel32.`
`          ``| DIV                                                         ``# Int only.               This does round-to-negative-infinity division  -- this will be much slower on Intel32, has to be faked.`
`          ``| MOD                                                         ``# Int only.               This does round-to-negative-infinity remainder -- this will be much slower on Intel32, has to be faked.`
`          ;`

`        Comparison_Op = GT ``| GE | LT | LE | LEU | LTU | GEU | GTU | EQL | NEQ;`

`        # Various base ops.  Those that are designated _MACRO ("inline") are`
`        # expanded into lambda code in terms of other operators in`
`        #`
`        #     `src/lib/compiler/back/top/translate/translate-deep-syntax-to-lambdacode.pkg
`        #`
`        # as is the "checkbounds=>TRUE" version of GET_VECSLOT_NUMERIC_CONTENTS or SET_VECSLOT_TO_NUMERIC_VALUE.`
`        # GET_VECSLOT_NUMERIC_CONTENTS and SET_VECSLOT_TO_NUMERIC_VALUE are for vectors of floats or ints`
`        # stored WITHOUT boxing or tags.`
`        #`
`        Baseop`
`          = ARITH  {  op: Math_Op,  overflow: Bool,  kind_and_size: Number_Kind_And_Size }`
`          ``| LSHIFT_MACRO  Number_Kind_And_Size`
`          ``| RSHIFT_MACRO  Number_Kind_And_Size`
`          ``| RSHIFTL_MACRO  Number_Kind_And_Size                         ``# "RSHIFTL" is probably "right-shift logical", where "logical" means "without extending sign".`
`          ``| COMPARE  { op: Comparison_Op, kind_and_size: Number_Kind_And_Size }`

`          ``| SHRINK_UNT  (Int, Int)`
`          ``| SHRINK_INT  (Int, Int)`
`          ``| CHOP        (Int, Int)`
`          ``| STRETCH     (Int, Int)`
`          ``| COPY        (Int, Int)`

`          ``| SHRINK_INTEGER      Int             ``#  Integer -> Int `
`          ``| CHOP_INTEGER        Int             ``#  Integer -> Int`
`          ``| STRETCH_TO_INTEGER  Int             ``#  Int -> Integer `
`          ``| COPY_TO_INTEGER     Int             ``#  Int -> Integer `

`          ``| ROUND         { floor: Bool, from: Number_Kind_And_Size, to: Number_Kind_And_Size }`
`          ``| CONVERT_FLOAT {              from: Number_Kind_And_Size, to: Number_Kind_And_Size }`

`          ``| GET_VECSLOT_NUMERIC_CONTENTS  { kind_and_size: Number_Kind_And_Size, checkbounds: Bool, immutable: Bool }`
`          ``| SET_VECSLOT_TO_NUMERIC_VALUE  { kind_and_size: Number_Kind_And_Size, checkbounds: Bool }`

`          ``| MAKE_NONEMPTY_RW_VECTOR_MACRO               ``# Make       typeagnostic rw_vector.`
`          #`
`          ``| RW_VECTOR_GET                               ``# Fetch from typeagnostic rw_vector.`
`          ``| RO_VECTOR_GET                               ``# Fetch from typeagnostic    vector.`
`          ``| RW_VECTOR_SET                               ``#       rw_vector update (maybe boxed).         Updates the heap changelog.`
`          #`
`          ``| RW_VECTOR_GET_WITH_BOUNDSCHECK              ``# Fetch from typeagnostic rw_vector.            # Gets replaced by RW_VECTOR_GET after the bounds-check gets expanded in `src/lib/compiler/back/top/translate/translate-deep-syntax-to-lambdacode.pkg
`          ``| RO_VECTOR_GET_WITH_BOUNDSCHECK              ``# Fetch from typeagnostic    vector.            # Gets replaced by RW_VECTOR_GET after the bounds-check gets expanded in `src/lib/compiler/back/top/translate/translate-deep-syntax-to-lambdacode.pkg
`          ``| RW_VECTOR_SET_WITH_BOUNDSCHECK              ``#       rw_vector update (maybe boxed)                  Becomes RW_VECTOR_SET after bounds-check is expanded out in `src/lib/compiler/back/top/translate/translate-deep-syntax-to-lambdacode.pkg
`          #`
`          ``| RW_MATRIX_GET_MACRO                         ``# Fetch from typeagnostic rw_matrix.`
`          ``| RO_MATRIX_GET_MACRO                         ``# Fetch from typeagnostic    matrix.`
`          ``| RW_MATRIX_SET_MACRO                         ``#       rw_matrix update (maybe boxed).`
`          #`
`          ``| RW_MATRIX_GET_WITH_BOUNDSCHECK_MACRO        ``# Fetch from typeagnostic rw_matrix.`
`          ``| RO_MATRIX_GET_WITH_BOUNDSCHECK_MACRO        ``# Fetch from typeagnostic    matrix.`
`          ``| RW_MATRIX_SET_WITH_BOUNDSCHECK_MACRO        ``#       rw_matrix update (maybe boxed)`

`          ``| POINTER_EQL`
`          ``| POINTER_NEQ                                 ``# Pointer equality.`
`          #`
`          ``| POLY_EQL | POLY_NEQ                         ``# Typeagnostic equality.`
`          #`
`          ``| IS_BOXED                                    ``# This is just (x&1)==0  -- checks that we don't have a Tagged_Int value.`
`          ``| IS_UNBOXED                                  ``# This is just (x&1)!=0  -- checks that we DO    have a Tagged_Int value.`
`          #`
`          ``| VECTOR_LENGTH_IN_SLOTS                      ``# Length of vector, string, rw_vector, ...`
`          ``| HEAPCHUNK_LENGTH_IN_WORDS                   ``# Length of arbitrary heapchunk, excluding tagword itself.`
`          #`
`          ``| CAST                                        ``# If this is introduced at all, it must(?) be in   `src/lib/compiler/back/top/forms/drop-types-from-anormcode-junk.pkg
`          ``| WCAST                                       ``# This might have been weak sealing of packages at one point; I can find no evidence that it ever gets introduced by the current compiler.`
`          #`
`          ``| GET_RUNTIME_ASM_PACKAGE_RECORD              ``# (This may be dead code; I can't find any implementation. --2011-08-24 CrT)   Get runtime::asm vector -- see src/c/main/construct-runtime-package.c, `src/lib/core/init/runtime.pkg
`          #`
`          ``| MARK_EXCEPTION_WITH_STRING                  ``# Mark an exception value with a string `
`          #`
`          ``| GET_EXCEPTION_HANDLER_REGISTER              ``# Get exception handler pointer.`
`          ``| SET_EXCEPTION_HANDLER_REGISTER              ``# Set exception handler pointer.`
`          #`
`          ``| GET_CURRENT_MICROTHREAD_REGISTER            ``# Get "current thread" register contents.`
`          ``| SET_CURRENT_MICROTHREAD_REGISTER            ``# Set "current thread" register contents.`
`          #`
`          ``| PSEUDOREG_GET`
`          ``| PSEUDOREG_SET                               ``# Get/set pseudo registers.     This appears to be code that died a-borning.            `
`          #`
`          ``| SETMARK | DISPOSE                           ``# Capture/dispose frames.`
`          #`
`          ``| CALLCC                                      ``# Fate ("continuation") operations.`
`          ``| CALL_WITH_CURRENT_CONTROL_FATE`
`          ``| THROW`
`          ``| MAKE_ISOLATED_FATE                          ``# "Isolating a function." Something involving setting the exception handler -- see   `src/lib/compiler/back/top/nextcode/translate-anormcode-to-nextcode-g.pkg
`          #`
`          ``| MAKE_REFCELL                                ``# Allocate a REF cell.`
`          ``| GET_REFCELL_CONTENTS                        ``# Implements the *ref op.`
`          ``| SET_REFCELL_TO_TAGGED_INT_VALUE             ``# Implements the ':=' op on Ref(Tagged_Int) refcells.   Does NOT update the heap changelog.`
`          ``| SET_REFCELL                                 ``# Implements the ':=' op.                               Updates the heap changelog.`
`          ``| SET_VECSLOT_TO_BOXED_VALUE                  ``# Used to store String and Float64 into a vector.       Updates the heap changelog.`
`          ``| SET_VECSLOT_TO_TAGGED_INT_VALUE             ``# Update rw_vector of integers WITH tags                Does NOT update the heap changelog.`

`          ``| GET_BATAG_FROM_TAGWORD                      ``# Extract (b-tag << 2 ``| a-tag) from given tagword.`
`                                                        # Used in rep()         in   `src/lib/std/src/unsafe/unsafe-chunk.pkg
`                                                        # Used in poly_equal()  in   `src/lib/core/init/core.pkg

`          ``| MAKE_WEAK_POINTER_OR_SUSPENSION                             ``# `
`          ``| SET_STATE_OF_WEAK_POINTER_OR_SUSPENSION                     ``# `
`          ``| GET_STATE_OF_WEAK_POINTER_OR_SUSPENSION                     ``# `
`          ``| USELVAR | DEFLVAR`

`          ``| MIN_MACRO  Number_Kind_And_Size                             ``# inline min `
`          ``| MAX_MACRO  Number_Kind_And_Size                             ``# inline max `

`          ``| ABS_MACRO  Number_Kind_And_Size                             ``# inline abs `
`          ``| NOT_MACRO                                                   ``# inline Bool not operator `
`          ``| COMPOSE_MACRO                                               ``# inline compose ('o')  operator `

`          ``| THEN_MACRO                                                  ``# inline "then" operator`
`          ``| IGNORE_MACRO                                                ``# inline "ignore" function `

`          ``| ALLOCATE_RW_VECTOR_MACRO                                    ``# inline typeagnostic rw_vector allocation `
`          ``| ALLOCATE_RO_VECTOR_MACRO                                    ``# inline typeagnostic    vector allocation `

`          ``| ALLOCATE_NUMERIC_RW_VECTOR_MACRO  Number_Kind_And_Size      ``# inline typelocked   rw_vector allocation `
`          ``| ALLOCATE_NUMERIC_RO_VECTOR_MACRO  Number_Kind_And_Size      ``# inline typelocked      vector allocation `

`          ``| MAKE_EXCEPTION_TAG                                          ``# Make a new exception tag.`

`          ``| WRAP                                                        ``# Box a value by wrapping it.`
`          ``| UNWRAP                                                      ``# Unbox a value by unwrapping it.`

`          #  Primops to support new rw_vector representations `
`          #`
`          ``| MAKE_ZERO_LENGTH_VECTOR                                     ``# Allocate zero-length rw_vector.`
`          ``| GET_VECTOR_DATACHUNK                                        ``# Get data pointer from vector/rw_vector header `
`          ``| RECORD_GET                                                  ``# Fetch-from-record operation.`
`          ``| RAW64_GET                                                   ``# Fetch-from-raw64 operation.`

`          # Primops to support new experimental C FFI. `
`          #`
`          ``| GET_FROM_NONHEAP_RAM  Number_Kind_And_Size                  ``# Load from arbitrary memory location `
`          ``| SET_NONHEAP_RAM       Number_Kind_And_Size                  ``# Store to arbitrary memory location `

`          ``| RAW_CCALL   Null_Or { c_prototype:                   cty::Cfun_Type,`
`                                  ml_argument_representations:    List( Ccall_Type ),`
`                                  ml_result_representation:       Null_Or( Ccall_Type ),`
`                                  is_reentrant:                  Bool`
`                                }`
`              #`
`              # Make a call to a C-function.`
`              # The baseop carries C function prototype information and specifies`
`              # which of its (ML-) arguments are floating point. C prototype`
`              # information is for use by the backend, ML information is for`
`              # use by the FPS converter.`

`          ``| RAW_ALLOCATE_C_RECORD  { fblock: Bool }`
`              #`
`              # Allocate uninitialized storage on the heap.`
`              # The record is meant to hold short-lived C chunks, i.e.,`
`              # they are not Mythryl pointers.  The representation is `
`              # the same as RECORD with tag`
`              #     four_byte_aligned_nonpointer_data_btag (fblock = FALSE),            # 32-bit int   data.`
`              # or  tag_fblock                             (fblock = TRUE).             # 64-bit float data.`

`          ``| IDENTITY_MACRO                      ``#  typeagnostic identity `

`          ``| CVT64                               ``# convert between external and`
`                                                # internal representation of`
`                                                # simulated 64-bit scalars`

`        also`
`        Ccall_Type`
`          = CCI32                               # Passed as Int1.`
`          ``| CCI64                               ``# Passed as Int2 -- currently unused.`
`          ``| CCR64                               ``# Passed as Float64.`
`          ``| CCML                                ``# Passed as unsafe::unsafe_chunk::chunk.`
`          ;`

`        iadd:  Baseop;                          # Default integer addition.`
`        isub:  Baseop;                          # Default integer subtraction.`
`        imul:  Baseop;`
`        idiv:  Baseop;`
`        ineg:  Baseop;`

`        feqld: Baseop;`
`        ieql:  Baseop;`
`        ineq:  Baseop;`
`        igt:   Baseop;`
`        ilt:   Baseop;`
`        ile:   Baseop;`
`        ige:   Baseop;`

`        kind_and_size_to_string:        Number_Kind_And_Size -> String;`
`        baseop_to_string:               Baseop               -> String;`

`        might_raise_exception:          Baseop -> Bool;         # TRUE means "Might raise exception".                   # Currently nowhere used.`
`        might_have_side_effects:        Baseop -> Bool;         # TRUE means "May not be dead-code eliminated".`

`    };          # api Highcode_Baseops`
`end;`

`## Copyright 1996 by AT&T Bell Laboratories `
`## Subsequent changes by Jeff Prothero Copyright (c) 2010-2015,`
`## released per terms of SMLNJ-COPYRIGHT.`   