Commit 6f4a7fbb authored by Kunshan Wang's avatar Kunshan Wang

Defined memory operations in one place. Added concrete description of

memory accesses via pointers.
parent 73baed17
......@@ -2029,7 +2029,7 @@ loc
excClause
*exception clause*: Used to handle NULL reference errors.
return value
Type is the strong variant of *T*: The value loaded from *loc*
Type is the strong variant of *T*: The result of the load operation.
+------+------+------+-----+------+-----------+
| opct | opct | opct | idt | idt | excClause |
......@@ -2037,11 +2037,10 @@ return value
| 0x1A | PTR | ord | T | loc | excClause |
+------+------+------+-----+------+-----------+
The ``LOAD`` instruction loads from the memory location/address *loc*.
The ``LOAD`` instruction performs a *load* operation with argument (*ord*, *T*,
*loc*) as defined in `Mu and the Memory <uvm-memory>`__.
*ord* is the memory order. In the text form, the *ord* can be omitted and
defaults to ``NOT_ATOMIC``. The instruction is atomic if *ord* is not
``NOT_ATOMIC``.
In the text form, *ord* can be omitted and defaults to ``NOT_ATOMIC``.
For LLVM users: This is the counterpart of the ``load`` instruction.
``volatile`` is absent in Mu because memory accesses are part of the
......@@ -2084,12 +2083,10 @@ newVal
| 0x1B | PTR | ord | T | loc | newVal | excClause |
+------+------+------+-----+------+--------+-----------+
The ``STORE`` instruction stores *newVal* into the memory location/address
*loc*.
The ``STORE`` instruction performs a *store* operation with argument (*ord*,
*T*, *loc*, *newVal*) as defined in `Mu and the Memory <uvm-memory>`__.
*ord* is the memory order. In the text form, the *ord* can be omitted and
defaults to ``NOT_ATOMIC``. The instruction is atomic if *ord* is not
``NOT_ATOMIC``.
In the text form, *ord* can be omitted and defaults to ``NOT_ATOMIC``.
For LLVM users: This is the counterpart of the ``store`` instruction.
``volatile`` is absent.
......@@ -2109,14 +2106,14 @@ defaults to ``NOT_ATOMIC``. The instruction is atomic if *ord* is not
``CMPXCHG`` Instruction
~~~~~~~~~~~~~~~~~~~~~~~
``CMPXCHG`` ``PTR`` :sub:`opt` ``WEAK`` :sub:`opt` *succOrd* *failOrd* ``<`` *T*
``CMPXCHG`` ``PTR`` :sub:`opt` ``WEAK`` :sub:`opt` *ordSucc* *ordFail* ``<`` *T*
``>`` *loc* *expected* *desired* *excClause*
``PTR`` :sub:`opt`
If present, *loc* is a pointer. Otherwise it is an internal reference.
``WEAK`` :sub:`opt`
If present, the ``CMPXCHG`` operation is weak.
succOrd, failOrd
ordSucc, ordFail
*memory order*: The memory order for success and failure, respectively.
T
*type*, must be EQ-comparable: The referent type of *loc*.
......@@ -2133,35 +2130,22 @@ excClause
*exception clause*: Used to handle NULL reference errors.
return value:
Type is ``struct<U int<1>>`` where *U* is the strong variant of *T*:
A pair of the original value in the memory and whether this operation is
successful.
The result of the compare exchange operation.
+------+------+------+---------+---------+-----+------+----------+---------+-----------+
| opct | opct | opct | opct | opct | idt | idt | idt | idt | excClause |
+======+======+======+=========+=========+=====+======+==========+=========+===========+
| 0x1C | PTR | WEAK | succOrd | failOrd | T | loc | expected | desired | excClause |
| 0x1C | PTR | WEAK | ordSucc | ordFail | T | loc | expected | desired | excClause |
+------+------+------+---------+---------+-----+------+----------+---------+-----------+
``CMPXCHG`` loads the value from memory location/address *loc* and compare it
with the *expected* value. If the comparison succeeds, then store the *desired*
value to *loc*. If fails, no store operation will happen. The whole process
happens atomically.
The ``CMPXCHG`` instruction performs a *compare exchange* operation with
argument (*isWeak*, *ordSucc*, *ordFail*, *T*, *loc*, *expected*, *desired*),
where *isWeak* is true if ``WEAK`` is present, otherwise false. The operation
is defined in `Mu and the Memory <uvm-memory>`__.
A ``CMPXCHG`` instruction can be **strong** or **weak**. In the text form, it is
weak if the flag ``WEAK`` is present, otherwise it is strong. In the binary
form, it is weak if the field *weak* is 1 and it is strong if *weak* is 0.
If the instruction is strong, The comparison succeeds **if and only if** the
loaded value equals the *expected* value. If it is weak, the comparison succeeds
**only if** the loaded value equals the *expected* value and it may spuriously
fail, that is, it may fail even if the loaded value equals the *expected* value.
The return value of this instruction is a struct of two fields: The first field
is the value loaded from the memory. The second field is 1 if the comparison is
successful, or 0 otherwise.
The memory order of this instruction is *succOrd* if the comparison succeeds, or
*failOrd* otherwise.
The result is a struct. The two fields represents the *v* and *s* value as
defined in `Mu and the Memory <uvm-memory>`__. The second field is 1 for true
and 0 for false.
For LLVM users: This is the counterpart of the ``cmpxchg`` instruction.
......@@ -2224,7 +2208,8 @@ opnd
excClause
*exception clause*: Used to handle NULL reference errors.
return value
Type is the strong variant of *T*: The original value in the memory.
Type is the strong variant of *T*: The result of the atomic-x operation
where x is *op*.
+------+------+------+------+-----+------+------+-----------+
| opct | opct | opct | opct | idt | idt | idt | excClause |
......@@ -2250,45 +2235,9 @@ UMAX 0x09 int unsigned max
UMIN 0x0A int unsigned min
=========== ====== === =============
The ``ATOMICRMW`` loads the value from memory location/address *loc*, perform an
operation *op* with the loaded value as the left-hand-side operand and *opnd* as
the right-hand-side operand and store the result back to the memory
location/address *loc*. The whole process happen atomically.
All operators other than ``XCHG`` are only applicable for integer types.
``XCHG`` is allowed for any type. However, a Mu implementation may only
implement some combinations of operators and operand types according to the
requirements specified in `<portability>`__
The results of the operations are: (NOTE: the result of the operation is not the
return value of this instruction)
XCHG
The value of *opnd*.
ADD
The sum of the two operands.
SUB
The difference of the two operands.
AND
The bitwise AND of the two operands.
NAND
The bitwise NOT of the bitwise AND of the two operands.
OR
The bitwise inclusive OR of the two operands.
XOR
The bitwise exclusive OR of the two operands.
MAX
The maximum value of the two operands, considering both operand as signed.
MIN
The minimum value of the two operands, considering both operand as signed.
UMAX
The maximum value of the two operands, considering both operand as unsigned.
UMIN
The minimum value of the two operands, considering both operand as unsigned.
..
NOTE: In the C syntax, the semantic of NAND is ``~(op1 & op2)``.
The ``ATOMICRMW`` instruction performs an *atomic-x* operation with argument
(*ord*, *T*, *loc*, *opnd*), where the *x* in *atomic-x* is *op*. The operation
is defined in `Mu and the Memory <uvm-memory>`__.
..
......@@ -2317,11 +2266,9 @@ ord
| 0x1E | ord |
+------+------+
The ``FENCE`` is used to introduce happen-before edges between operations. Its
The ``FENCE`` is a fence of memory order *ord*. Its
semantic is specified in `<memory-model>`__.
*ord* is the memory order of the fence.
For LLVM users: This is the counterpart of the ``fence`` instruction.
..
......
......@@ -115,8 +115,9 @@ store
A memory store. May be atomic or not.
atomic read-modify-write
A load and (maybe conditionally) a store as one atomic action. It has both a
load and a store operation, but may have special atomic properties.
A load and (maybe conditionally) a store as one atomic action. It may
contain both a load and a store operation, but may have special atomic
properties.
fence
A fence introduces memory orders.
......
......@@ -122,48 +122,18 @@ Only a subset of types can be used as the type parameter of the ``ptr`` and the
native-safe if all of their type arguments *T1*, *T2*, ..., *T*, *F*, *V* are
native-safe.
* ``ptr<T>`` is native-safe. It requires T to be native-safe.
* ``ptr<T>`` is always native-safe. It requires T to be native-safe.
* ``funcptr<sig>`` is native-safe. It requires the return type and all parameter
types of *sig* to be native-safe.
* ``funcptr<sig>`` is always native-safe. It requires the return type and all
parameter types of *sig* to be native-safe.
* All other types are not native-safe. Specifically, they are ``ref``, ``iref``,
``weakref``, ``func``, ``thread``, ``stack``.
``weakref``, ``func``, ``thread``, ``stack`` as well as ``struct``, ``array``
or ``hybrid`` that contains them.
Exposing Mu Memory to the Native World
======================================
Memory Layout
-------------
The bytes in the address space can be interpreted as Mu values in an
implementation-dependent way. The bytes that represents a Mu value is the
**bytes representation** of that Mu value.
A memory location (in the Mu memory) can be **pinned**. In this state, it is
mapped to a contiguous region of bytes in the address space which contains the
bytes representation of the value the memory location holds. The beginning of
the memory location is mapped to the lowest address of the region. Different
components of a memory location which do not contain each other do not map to
overlapping regions in the address space.
For C programmers:
* Mu assumes 8-bit bytes.
* Mu does not have the bit-field type, but a client can implement bit-fields
using integer types and bit operations.
* Mu does not have union types. However, like C, directly casting an address
to a pointer has implementation-defined behaviours. If a Mu program
interfaces with native programs, it has to also depend on the platform.
* Unlike C, Mu operations work on SSA variables rather than memory locations
(the counterpart of objects in C).
* Mu forces the 2's complement representation, though the byte order and
alignment requirement are implementation-defined.
Pinning
-------
......@@ -190,22 +160,6 @@ his multi-set. A memory location is pinned as long as there is at least one
implemented as a thread-local buffer. In this case, if GC never happens, no
expensive atomic memory access or inter-thread synchronisation is performed.
Memory Access and Memory Model
------------------------------
TODO:
* How does the atomic/non-atomic load/store/atomicrmw operations to the
bytes in the address space relate to the atomic/non-atomic
load/store/atomicrmw operations described in the Mu memory model? How does
the modification of bytes affect the values?
* How to model the modification of bytes that spans over more than one
memory location (in the Mu memory's sense)?
* And the attempt to look into the bytes representation of references must
be forbidden.
Calling between Mu and Native Functions
=======================================
......
......@@ -852,9 +852,8 @@ The ``load`` message
- return value: A handle of the loaded value.
The ``load`` message loads from the memory location/address of ``loc``.
This operation has the memory order ``ord``.
The ``load`` message performs a load operation with arguments (*ord*, *T*,
*loc*) where *T* is the referent type of *loc*.
For JNI users: This is similar to the ``Get<type>Field`` routine.
......@@ -879,9 +878,8 @@ The ``store`` message
``newval`` must have the unmarked type of the referent type of ``loc``.
The ``store`` message stores ``newval`` into the memory location/address of ``loc``.
This operation has the memory order ``ord``.
The ``store`` message performs a *store* operation with argument (*ord*,
*T*, *loc*, *newval*) where *T* is the referent type of *loc*.
For JNI users: This is similar to the ``Set<type>Field`` routine.
......@@ -914,17 +912,11 @@ The ``cmpxchg`` message
``expected`` and ``desired`` must have the unmarked type of the referent type of
``loc``.
The ``cmpxchg`` message loads form ``loc`` and compare with ``expected``. If
successful, then store ``desired`` to ``loc``, otherwise do nothing. In both
cases, the old value ``oldval`` at memory location/address ``loc`` is returned. This
whole process happen atomically.
The ``cmpxchg`` message performs a *compare exchange* operation with
argument (*weak*, *ord_sicc*, *ord_fail*, *T*, *loc*, *expected*, *desired*),
where *T* is the referent type of *loc*.
If this operation is strong, The comparison is successful if and only if the
loaded value equals ``expected``. If weak, it may spuriously fail even if they
are equal.
This operation has the memory order ``ord_succ`` when successful and
``ord_fail`` when failed.
..
Example in Java::
......@@ -958,14 +950,9 @@ The ``atomicrmw`` message
``opnd`` must have the unmarked type of the referent type of ``loc``.
The ``atomicrmw`` message performs a binary operation ``op`` on the current
value in ``loc`` as the left-hand-side and ``opnd`` as the right-hand-side and
stores the result to ``loc``. The whole process happen atomically.
``op`` is one operation defined in the ``ATOMICRMW`` instruction. (See
`<instruction-set>`__)
This operation has the memory order ``ord``.
The ``atomicrmw`` message performs an *atomic-x* operation with argument (*ord*,
*T*, *loc*, *opnd*), where *T* is the referent type of *loc*, and the *x* in
*atomic-x* is *op*.
Example Java signature: ``Handle ClientAgent.atomicrmw(MemoryOrder ord, AtomicRMWOp op, Handle loc, Handle opnd)``
......@@ -982,9 +969,7 @@ The ``fence`` message
- return value: None
The ``fence`` is a memory fence.
This operation has the memory order ``ord``.
The ``fence`` is a memory fence of memory order ``ord``.
Example Java signature: ``void ClientAgent.fence(MemoryOrder ord)``
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment