PreviousUpNext

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.


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext